Merge "Revert "Shortcut integration with AppSearch (Part 5)"" into sc-dev
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index d5ed95f..90dca25 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -159,7 +159,15 @@
             PARALLEL_MAX_THREADS, "package-parsing-test",
             Process.THREAD_PRIORITY_FOREGROUND)
 
-        fun submit(file: File) = service.submit { queue.put(parse(file)) }
+        fun submit(file: File) {
+                service.submit {
+                    try {
+                        queue.put(parse(file))
+                    } catch (e: Exception) {
+                        queue.put(e)
+                    }
+                }
+        }
 
         fun take() = queue.poll(QUEUE_POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS)
 
diff --git a/boot/Android.bp b/boot/Android.bp
index 4f7c44e..71edea2 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -23,7 +23,24 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-boot_image {
-    name: "framework-boot-image",
-    image_name: "boot",
+// This module provides access to information Soong has related to the
+// whole platform bootclasspath. Currently, that information is provided solely
+// through configuration but additional information will be added here.
+//
+// This will provide support for the following:
+// * Hidden API processing for those parts of the bootclasspath that are not
+//   part of an APEX.
+// * Compatibility checking to ensure that the hidden API bits encoded into the
+//   dex files by the modularized hidden API processing is compatible with the
+//   runtimes of earlier releases which expect the bits to have been computed
+//   over the entirety of the bootclasspath in one go not separately.
+// * Dexpreopting apps and other libraries not on the platform bootclasspath.
+// * Generating and installing the appropriate files to the device which will
+//   allow it to generate the bootclasspath related environment variables
+//   dynamically.
+//
+// This module needs to be present in the build for the above processing to be
+// done correctly.
+platform_bootclasspath {
+    name: "platform-bootclasspath",
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 89cf257..39d0b8c 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -303,7 +303,7 @@
     field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
-    field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
+    field public static final int allowClickWhenDisabled;
     field public static final int allowEmbedded = 16843765; // 0x10103f5
     field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
@@ -334,7 +334,7 @@
     field public static final int apiKey = 16843281; // 0x1010211
     field public static final int appCategory = 16844101; // 0x1010545
     field public static final int appComponentFactory = 16844154; // 0x101057a
-    field public static final int attributionTags = 16844354; // 0x1010642
+    field public static final int attributionTags;
     field public static final int author = 16843444; // 0x10102b4
     field public static final int authorities = 16842776; // 0x1010018
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -400,7 +400,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844039; // 0x1010507
-    field public static final int canPauseRecording = 16844314; // 0x101061a
+    field public static final int canPauseRecording;
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
     field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
@@ -442,7 +442,7 @@
     field public static final int clickable = 16842981; // 0x10100e5
     field public static final int clipChildren = 16842986; // 0x10100ea
     field public static final int clipOrientation = 16843274; // 0x101020a
-    field public static final int clipToOutline = 16844328; // 0x1010628
+    field public static final int clipToOutline;
     field public static final int clipToPadding = 16842987; // 0x10100eb
     field public static final int closeIcon = 16843905; // 0x1010481
     field @Deprecated public static final int codes = 16843330; // 0x1010242
@@ -512,7 +512,7 @@
     field public static final int dashGap = 16843175; // 0x10101a7
     field public static final int dashWidth = 16843174; // 0x10101a6
     field public static final int data = 16842798; // 0x101002e
-    field public static final int dataExtractionRules = 16844350; // 0x101063e
+    field public static final int dataExtractionRules;
     field public static final int datePickerDialogTheme = 16843948; // 0x10104ac
     field public static final int datePickerMode = 16843955; // 0x10104b3
     field public static final int datePickerStyle = 16843612; // 0x101035c
@@ -534,8 +534,8 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
-    field public static final int dialTint = 16844342; // 0x1010636
-    field public static final int dialTintMode = 16844343; // 0x1010637
+    field public static final int dialTint;
+    field public static final int dialTintMode;
     field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
@@ -583,7 +583,7 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
-    field public static final int edgeEffectType = 16844329; // 0x1010629
+    field public static final int edgeEffectType;
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
@@ -669,7 +669,7 @@
     field @Deprecated public static final int fontProviderCerts = 16844125; // 0x101055d
     field @Deprecated public static final int fontProviderPackage = 16844119; // 0x1010557
     field @Deprecated public static final int fontProviderQuery = 16844113; // 0x1010551
-    field public static final int fontProviderSystemFontFamily = 16844322; // 0x1010622
+    field public static final int fontProviderSystemFontFamily;
     field public static final int fontStyle = 16844095; // 0x101053f
     field public static final int fontVariationSettings = 16844144; // 0x1010570
     field public static final int fontWeight = 16844083; // 0x1010533
@@ -733,14 +733,14 @@
     field public static final int groupIndicator = 16843019; // 0x101010b
     field public static final int gwpAsanMode = 16844310; // 0x1010616
     field public static final int hand_hour = 16843011; // 0x1010103
-    field public static final int hand_hourTint = 16844344; // 0x1010638
-    field public static final int hand_hourTintMode = 16844345; // 0x1010639
+    field public static final int hand_hourTint;
+    field public static final int hand_hourTintMode;
     field public static final int hand_minute = 16843012; // 0x1010104
-    field public static final int hand_minuteTint = 16844346; // 0x101063a
-    field public static final int hand_minuteTintMode = 16844347; // 0x101063b
-    field public static final int hand_second = 16844323; // 0x1010623
-    field public static final int hand_secondTint = 16844348; // 0x101063c
-    field public static final int hand_secondTintMode = 16844349; // 0x101063d
+    field public static final int hand_minuteTint;
+    field public static final int hand_minuteTintMode;
+    field public static final int hand_second;
+    field public static final int hand_secondTint;
+    field public static final int hand_secondTintMode;
     field public static final int handle = 16843354; // 0x101025a
     field public static final int handleProfiling = 16842786; // 0x1010022
     field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
@@ -824,7 +824,7 @@
     field public static final int installLocation = 16843447; // 0x10102b7
     field public static final int interactiveUiTimeout = 16844181; // 0x1010595
     field public static final int interpolator = 16843073; // 0x1010141
-    field public static final int isAccessibilityTool = 16844353; // 0x1010641
+    field public static final int isAccessibilityTool;
     field public static final int isAlwaysSyncable = 16843571; // 0x1010333
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
@@ -866,8 +866,8 @@
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
-    field public static final int knownCerts = 16844330; // 0x101062a
-    field public static final int lStar = 16844359; // 0x1010647
+    field public static final int knownCerts;
+    field public static final int lStar;
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
     field @Deprecated public static final int labelTextSize = 16843317; // 0x1010235
@@ -977,8 +977,8 @@
     field public static final int maxLines = 16843091; // 0x1010153
     field public static final int maxLongVersionCode = 16844163; // 0x1010583
     field public static final int maxRecents = 16843846; // 0x1010446
-    field public static final int maxResizeHeight = 16844339; // 0x1010633
-    field public static final int maxResizeWidth = 16844338; // 0x1010632
+    field public static final int maxResizeHeight;
+    field public static final int maxResizeWidth;
     field public static final int maxRows = 16843059; // 0x1010133
     field public static final int maxSdkVersion = 16843377; // 0x1010271
     field public static final int maxWidth = 16843039; // 0x101011f
@@ -987,7 +987,7 @@
     field public static final int measureWithLargestChild = 16843476; // 0x10102d4
     field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
-    field public static final int memtagMode = 16844324; // 0x1010624
+    field public static final int memtagMode;
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeGroup = 16844309; // 0x1010615
     field public static final int mimeType = 16842790; // 0x1010026
@@ -1011,7 +1011,7 @@
     field public static final int multiArch = 16843918; // 0x101048e
     field public static final int multiprocess = 16842771; // 0x1010013
     field public static final int name = 16842755; // 0x1010003
-    field public static final int nativeHeapZeroInitialized = 16844325; // 0x1010625
+    field public static final int nativeHeapZeroInitialized;
     field public static final int navigationBarColor = 16843858; // 0x1010452
     field public static final int navigationBarDividerColor = 16844141; // 0x101056d
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
@@ -1081,13 +1081,13 @@
     field public static final int panelTextAppearance = 16842850; // 0x1010062
     field public static final int parentActivityName = 16843687; // 0x10103a7
     field @Deprecated public static final int password = 16843100; // 0x101015c
-    field public static final int passwordsActivity = 16844351; // 0x101063f
+    field public static final int passwordsActivity;
     field public static final int path = 16842794; // 0x101002a
-    field public static final int pathAdvancedPattern = 16844320; // 0x1010620
+    field public static final int pathAdvancedPattern;
     field public static final int pathData = 16843781; // 0x1010405
     field public static final int pathPattern = 16842796; // 0x101002c
     field public static final int pathPrefix = 16842795; // 0x101002b
-    field public static final int pathSuffix = 16844318; // 0x101061e
+    field public static final int pathSuffix;
     field public static final int patternPathData = 16843978; // 0x10104ca
     field public static final int permission = 16842758; // 0x1010006
     field public static final int permissionFlags = 16843719; // 0x10103c7
@@ -1124,7 +1124,7 @@
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int preserveLegacyExternalStorage = 16844308; // 0x1010614
     field public static final int previewImage = 16843482; // 0x10102da
-    field public static final int previewLayout = 16844327; // 0x1010627
+    field public static final int previewLayout;
     field public static final int primaryContentAlpha = 16844114; // 0x1010552
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
@@ -1181,8 +1181,8 @@
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
-    field public static final int requestOptimizedExternalStorageAccess = 16844357; // 0x1010645
-    field public static final int requireDeviceScreenOn = 16844317; // 0x101061d
+    field public static final int requestOptimizedExternalStorageAccess;
+    field public static final int requireDeviceScreenOn;
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
@@ -1207,7 +1207,7 @@
     field public static final int right = 16843183; // 0x10101af
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
-    field public static final int rollbackDataPolicy = 16844311; // 0x1010617
+    field public static final int rollbackDataPolicy;
     field public static final int rotation = 16843558; // 0x1010326
     field public static final int rotationAnimation = 16844090; // 0x101053a
     field public static final int rotationX = 16843559; // 0x1010327
@@ -1268,7 +1268,7 @@
     field public static final int segmentedButtonStyle = 16843568; // 0x1010330
     field public static final int selectAllOnFocus = 16843102; // 0x101015e
     field public static final int selectable = 16843238; // 0x10101e6
-    field public static final int selectableAsDefault = 16844352; // 0x1010640
+    field public static final int selectableAsDefault;
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
     field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347
@@ -1296,7 +1296,7 @@
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
-    field public static final int showInInputMethodPicker = 16844361; // 0x1010649
+    field public static final int showInInputMethodPicker;
     field public static final int showMetadataInPreview = 16844079; // 0x101052f
     field @Deprecated public static final int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
@@ -1319,17 +1319,17 @@
     field public static final int spinnerMode = 16843505; // 0x10102f1
     field public static final int spinnerStyle = 16842881; // 0x1010081
     field public static final int spinnersShown = 16843595; // 0x101034b
-    field public static final int splashScreenTheme = 16844337; // 0x1010631
+    field public static final int splashScreenTheme;
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
     field public static final int splitName = 16844105; // 0x1010549
     field public static final int splitTrack = 16843852; // 0x101044c
     field public static final int spotShadowAlpha = 16843967; // 0x10104bf
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
-    field public static final int sspAdvancedPattern = 16844321; // 0x1010621
+    field public static final int sspAdvancedPattern;
     field public static final int sspPattern = 16843749; // 0x10103e5
     field public static final int sspPrefix = 16843748; // 0x10103e4
-    field public static final int sspSuffix = 16844319; // 0x101061f
+    field public static final int sspSuffix;
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
@@ -1402,7 +1402,7 @@
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
-    field public static final int suppressesSpellChecker = 16844355; // 0x1010643
+    field public static final int suppressesSpellChecker;
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
     field public static final int switchPreferenceStyle = 16843629; // 0x101036d
@@ -1417,8 +1417,8 @@
     field public static final int tabWidgetStyle = 16842883; // 0x1010083
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
-    field public static final int targetCellHeight = 16844341; // 0x1010635
-    field public static final int targetCellWidth = 16844340; // 0x1010634
+    field public static final int targetCellHeight;
+    field public static final int targetCellWidth;
     field public static final int targetClass = 16842799; // 0x101002f
     field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
@@ -1588,7 +1588,7 @@
     field public static final int useLevel = 16843167; // 0x101019f
     field public static final int userVisible = 16843409; // 0x1010291
     field public static final int usesCleartextTraffic = 16844012; // 0x10104ec
-    field public static final int usesPermissionFlags = 16844356; // 0x1010644
+    field public static final int usesPermissionFlags;
     field public static final int value = 16842788; // 0x1010024
     field public static final int valueFrom = 16843486; // 0x10102de
     field public static final int valueTo = 16843487; // 0x10102df
@@ -1643,10 +1643,10 @@
     field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
-    field public static final int windowBackgroundBlurRadius = 16844331; // 0x101062b
+    field public static final int windowBackgroundBlurRadius;
     field public static final int windowBackgroundFallback = 16844035; // 0x1010503
-    field public static final int windowBlurBehindEnabled = 16844316; // 0x101061c
-    field public static final int windowBlurBehindRadius = 16844315; // 0x101061b
+    field public static final int windowBlurBehindEnabled;
+    field public static final int windowBlurBehindRadius;
     field public static final int windowClipToOutline = 16843947; // 0x10104ab
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -1665,7 +1665,7 @@
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
-    field public static final int windowLayoutAffinity = 16844313; // 0x1010619
+    field public static final int windowLayoutAffinity;
     field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586
     field public static final int windowLightNavigationBar = 16844140; // 0x101056c
     field public static final int windowLightStatusBar = 16844000; // 0x10104e0
@@ -1684,11 +1684,11 @@
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
-    field public static final int windowSplashScreenAnimatedIcon = 16844333; // 0x101062d
-    field public static final int windowSplashScreenAnimationDuration = 16844334; // 0x101062e
-    field public static final int windowSplashScreenBackground = 16844332; // 0x101062c
-    field public static final int windowSplashScreenBrandingImage = 16844335; // 0x101062f
-    field public static final int windowSplashScreenIconBackgroundColor = 16844336; // 0x1010630
+    field public static final int windowSplashScreenAnimatedIcon;
+    field public static final int windowSplashScreenAnimationDuration;
+    field public static final int windowSplashScreenBackground;
+    field public static final int windowSplashScreenBrandingImage;
+    field public static final int windowSplashScreenIconBackgroundColor;
     field @Deprecated public static final int windowSplashscreenContent = 16844132; // 0x1010564
     field @Deprecated public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
     field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
@@ -1736,66 +1736,66 @@
     field @Deprecated public static final int secondary_text_dark_nodisable = 17170438; // 0x1060006
     field @Deprecated public static final int secondary_text_light = 17170439; // 0x1060007
     field @Deprecated public static final int secondary_text_light_nodisable = 17170440; // 0x1060008
-    field public static final int system_accent1_0 = 17170485; // 0x1060035
-    field public static final int system_accent1_100 = 17170487; // 0x1060037
-    field public static final int system_accent1_1000 = 17170496; // 0x1060040
-    field public static final int system_accent1_200 = 17170488; // 0x1060038
-    field public static final int system_accent1_300 = 17170489; // 0x1060039
-    field public static final int system_accent1_400 = 17170490; // 0x106003a
-    field public static final int system_accent1_50 = 17170486; // 0x1060036
-    field public static final int system_accent1_500 = 17170491; // 0x106003b
-    field public static final int system_accent1_600 = 17170492; // 0x106003c
-    field public static final int system_accent1_700 = 17170493; // 0x106003d
-    field public static final int system_accent1_800 = 17170494; // 0x106003e
-    field public static final int system_accent1_900 = 17170495; // 0x106003f
-    field public static final int system_accent2_0 = 17170497; // 0x1060041
-    field public static final int system_accent2_100 = 17170499; // 0x1060043
-    field public static final int system_accent2_1000 = 17170508; // 0x106004c
-    field public static final int system_accent2_200 = 17170500; // 0x1060044
-    field public static final int system_accent2_300 = 17170501; // 0x1060045
-    field public static final int system_accent2_400 = 17170502; // 0x1060046
-    field public static final int system_accent2_50 = 17170498; // 0x1060042
-    field public static final int system_accent2_500 = 17170503; // 0x1060047
-    field public static final int system_accent2_600 = 17170504; // 0x1060048
-    field public static final int system_accent2_700 = 17170505; // 0x1060049
-    field public static final int system_accent2_800 = 17170506; // 0x106004a
-    field public static final int system_accent2_900 = 17170507; // 0x106004b
-    field public static final int system_accent3_0 = 17170509; // 0x106004d
-    field public static final int system_accent3_100 = 17170511; // 0x106004f
-    field public static final int system_accent3_1000 = 17170520; // 0x1060058
-    field public static final int system_accent3_200 = 17170512; // 0x1060050
-    field public static final int system_accent3_300 = 17170513; // 0x1060051
-    field public static final int system_accent3_400 = 17170514; // 0x1060052
-    field public static final int system_accent3_50 = 17170510; // 0x106004e
-    field public static final int system_accent3_500 = 17170515; // 0x1060053
-    field public static final int system_accent3_600 = 17170516; // 0x1060054
-    field public static final int system_accent3_700 = 17170517; // 0x1060055
-    field public static final int system_accent3_800 = 17170518; // 0x1060056
-    field public static final int system_accent3_900 = 17170519; // 0x1060057
-    field public static final int system_neutral1_0 = 17170461; // 0x106001d
-    field public static final int system_neutral1_100 = 17170463; // 0x106001f
-    field public static final int system_neutral1_1000 = 17170472; // 0x1060028
-    field public static final int system_neutral1_200 = 17170464; // 0x1060020
-    field public static final int system_neutral1_300 = 17170465; // 0x1060021
-    field public static final int system_neutral1_400 = 17170466; // 0x1060022
-    field public static final int system_neutral1_50 = 17170462; // 0x106001e
-    field public static final int system_neutral1_500 = 17170467; // 0x1060023
-    field public static final int system_neutral1_600 = 17170468; // 0x1060024
-    field public static final int system_neutral1_700 = 17170469; // 0x1060025
-    field public static final int system_neutral1_800 = 17170470; // 0x1060026
-    field public static final int system_neutral1_900 = 17170471; // 0x1060027
-    field public static final int system_neutral2_0 = 17170473; // 0x1060029
-    field public static final int system_neutral2_100 = 17170475; // 0x106002b
-    field public static final int system_neutral2_1000 = 17170484; // 0x1060034
-    field public static final int system_neutral2_200 = 17170476; // 0x106002c
-    field public static final int system_neutral2_300 = 17170477; // 0x106002d
-    field public static final int system_neutral2_400 = 17170478; // 0x106002e
-    field public static final int system_neutral2_50 = 17170474; // 0x106002a
-    field public static final int system_neutral2_500 = 17170479; // 0x106002f
-    field public static final int system_neutral2_600 = 17170480; // 0x1060030
-    field public static final int system_neutral2_700 = 17170481; // 0x1060031
-    field public static final int system_neutral2_800 = 17170482; // 0x1060032
-    field public static final int system_neutral2_900 = 17170483; // 0x1060033
+    field public static final int system_accent1_0;
+    field public static final int system_accent1_100;
+    field public static final int system_accent1_1000;
+    field public static final int system_accent1_200;
+    field public static final int system_accent1_300;
+    field public static final int system_accent1_400;
+    field public static final int system_accent1_50;
+    field public static final int system_accent1_500;
+    field public static final int system_accent1_600;
+    field public static final int system_accent1_700;
+    field public static final int system_accent1_800;
+    field public static final int system_accent1_900;
+    field public static final int system_accent2_0;
+    field public static final int system_accent2_100;
+    field public static final int system_accent2_1000;
+    field public static final int system_accent2_200;
+    field public static final int system_accent2_300;
+    field public static final int system_accent2_400;
+    field public static final int system_accent2_50;
+    field public static final int system_accent2_500;
+    field public static final int system_accent2_600;
+    field public static final int system_accent2_700;
+    field public static final int system_accent2_800;
+    field public static final int system_accent2_900;
+    field public static final int system_accent3_0;
+    field public static final int system_accent3_100;
+    field public static final int system_accent3_1000;
+    field public static final int system_accent3_200;
+    field public static final int system_accent3_300;
+    field public static final int system_accent3_400;
+    field public static final int system_accent3_50;
+    field public static final int system_accent3_500;
+    field public static final int system_accent3_600;
+    field public static final int system_accent3_700;
+    field public static final int system_accent3_800;
+    field public static final int system_accent3_900;
+    field public static final int system_neutral1_0;
+    field public static final int system_neutral1_100;
+    field public static final int system_neutral1_1000;
+    field public static final int system_neutral1_200;
+    field public static final int system_neutral1_300;
+    field public static final int system_neutral1_400;
+    field public static final int system_neutral1_50;
+    field public static final int system_neutral1_500;
+    field public static final int system_neutral1_600;
+    field public static final int system_neutral1_700;
+    field public static final int system_neutral1_800;
+    field public static final int system_neutral1_900;
+    field public static final int system_neutral2_0;
+    field public static final int system_neutral2_100;
+    field public static final int system_neutral2_1000;
+    field public static final int system_neutral2_200;
+    field public static final int system_neutral2_300;
+    field public static final int system_neutral2_400;
+    field public static final int system_neutral2_50;
+    field public static final int system_neutral2_500;
+    field public static final int system_neutral2_600;
+    field public static final int system_neutral2_700;
+    field public static final int system_neutral2_800;
+    field public static final int system_neutral2_900;
     field public static final int tab_indicator_text = 17170441; // 0x1060009
     field @Deprecated public static final int tertiary_text_dark = 17170448; // 0x1060010
     field @Deprecated public static final int tertiary_text_light = 17170449; // 0x1060011
@@ -1811,9 +1811,9 @@
     field public static final int dialog_min_width_minor = 17104900; // 0x1050004
     field public static final int notification_large_icon_height = 17104902; // 0x1050006
     field public static final int notification_large_icon_width = 17104901; // 0x1050005
-    field public static final int system_app_widget_background_radius = 17104904; // 0x1050008
-    field public static final int system_app_widget_inner_radius = 17104905; // 0x1050009
-    field public static final int system_app_widget_internal_padding = 17104906; // 0x105000a
+    field public static final int system_app_widget_background_radius;
+    field public static final int system_app_widget_inner_radius;
+    field public static final int system_app_widget_internal_padding;
     field public static final int thumbnail_height = 17104897; // 0x1050001
     field public static final int thumbnail_width = 17104898; // 0x1050002
   }
@@ -27093,12 +27093,13 @@
 
   public final class VcnGatewayConnectionConfig {
     method @NonNull public int[] getExposedCapabilities();
+    method @NonNull public String getGatewayConnectionName();
     method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
     method @NonNull public long[] getRetryInterval();
   }
 
   public static final class VcnGatewayConnectionConfig.Builder {
-    ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
+    ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.vcn.VcnControlPlaneConfig);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
     method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
@@ -27122,7 +27123,7 @@
 
   public abstract static class VcnManager.VcnStatusCallback {
     ctor public VcnManager.VcnStatusCallback();
-    method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
+    method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable);
     method public abstract void onStatusChanged(int);
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bfc9144..696494b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -313,15 +313,15 @@
 
   public static final class R.attr {
     field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
-    field public static final int hotwordDetectionService = 16844326; // 0x1010626
+    field public static final int hotwordDetectionService;
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int minExtensionVersion = 16844305; // 0x1010611
-    field public static final int playHomeTransitionSound = 16844358; // 0x1010646
+    field public static final int playHomeTransitionSound;
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
     field public static final int sdkVersion = 16844304; // 0x1010610
     field public static final int supportsAmbientMode = 16844173; // 0x101058d
-    field public static final int throttleDurationMillis = 16844360; // 0x1010648
+    field public static final int throttleDurationMillis;
     field public static final int userRestriction = 16844164; // 0x1010584
   }
 
@@ -350,8 +350,8 @@
   }
 
   public static final class R.string {
-    field public static final int config_customMediaKeyDispatcher = 17039404; // 0x104002c
-    field public static final int config_customMediaSessionPolicyProvider = 17039405; // 0x104002d
+    field public static final int config_customMediaKeyDispatcher;
+    field public static final int config_customMediaSessionPolicyProvider;
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
     field public static final int config_defaultBrowser = 17039394; // 0x1040022
     field public static final int config_defaultCallRedirection = 17039397; // 0x1040025
@@ -364,15 +364,15 @@
     field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
     field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
     field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
-    field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
-    field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
-    field public static final int config_systemContacts = 17039403; // 0x104002b
+    field public static final int config_systemAutomotiveCluster;
+    field public static final int config_systemAutomotiveProjection;
+    field public static final int config_systemContacts;
     field public static final int config_systemGallery = 17039399; // 0x1040027
-    field public static final int config_systemShell = 17039402; // 0x104002a
-    field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
-    field public static final int config_systemTelevisionNotificationHandler = 17039409; // 0x1040031
-    field public static final int config_systemWellbeing = 17039408; // 0x1040030
-    field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
+    field public static final int config_systemShell;
+    field public static final int config_systemSpeechRecognizer;
+    field public static final int config_systemTelevisionNotificationHandler;
+    field public static final int config_systemWellbeing;
+    field public static final int config_systemWifiCoexManager;
   }
 
   public static final class R.style {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 6745a69..7b6f9b3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -58,8 +58,8 @@
   public static final class R.string {
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
     field public static final int config_defaultDialer = 17039395; // 0x1040023
-    field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
-    field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
+    field public static final int config_systemAutomotiveCluster;
+    field public static final int config_systemAutomotiveProjection;
     field public static final int config_systemGallery = 17039399; // 0x1040027
   }
 
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0952b3e..fa9142c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -896,11 +896,13 @@
     };
 
     /**
-     * This change id forces the packages it is applied to to be resizable. We only allow resizing
-     * in fullscreen windowing mode, but not forcing the app into resizable multi-windowing mode.
+     * This change id forces the packages it is applied to be resizable. It won't change whether
+     * the app can be put into multi-windowing mode, but allow the app to resize when the window
+     * container resizes, such as display size change.
      * @hide
      */
     @ChangeId
+    @Overridable
     @Disabled
     @TestApi
     public static final long FORCE_RESIZE_APP = 174042936L; // buganizer id
@@ -910,6 +912,7 @@
      * @hide
      */
     @ChangeId
+    @Overridable
     @Disabled
     @TestApi
     public static final long FORCE_NON_RESIZE_APP = 181136395L; // buganizer id
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7696cbe..7ecb112 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -42,7 +42,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
@@ -162,20 +161,18 @@
         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         intentFilter.addDataScheme("package");
-        Handler handler = BackgroundThread.getHandler();
-        mContext.registerReceiverAsUser(
-                mPackageReceiver, UserHandle.ALL, intentFilter, null, handler);
+        mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);
 
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mExternalReceiver, sdFilter, null, handler);
+        mContext.registerReceiver(mExternalReceiver, sdFilter);
 
         // Register for user-related events
         IntentFilter userFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiver(mUserRemovedReceiver, userFilter, null, handler);
+        mContext.registerReceiver(mUserRemovedReceiver, userFilter);
     }
 
     private void handlePackageEvent(Intent intent, int userId) {
@@ -268,7 +265,7 @@
 
     public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) {
         if (handler == null) {
-            handler = BackgroundThread.getHandler();
+            handler = new Handler(mContext.getMainLooper());
         }
         synchronized (this) {
             mHandler = handler;
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index cdd8265..4c6255d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -376,10 +376,13 @@
             int[] stateSpec = new int[numAttrs];
             for (int i = 0; i < numAttrs; i++) {
                 final int stateResId = attrs.getAttributeNameResource(i);
+                if (stateResId == R.attr.lStar) {
+                    // Non-finalized resource ids cannot be used in switch statements.
+                    continue;
+                }
                 switch (stateResId) {
                     case R.attr.color:
                     case R.attr.alpha:
-                    case R.attr.lStar:
                         // Recognized attribute, ignore.
                         break;
                     default:
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index 236ae8b..11bc443 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -20,7 +20,7 @@
 oneway interface IVcnStatusCallback {
     void onVcnStatusChanged(int statusCode);
     void onGatewayConnectionError(
-            in int[] gatewayNetworkCapabilities,
+            in String gatewayConnectionName,
             int errorCode,
             in String exceptionClass,
             in String exceptionMessage);
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 52cc218..d41c0b4 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -183,12 +183,25 @@
          *
          * @param gatewayConnectionConfig the configuration for an individual gateway connection
          * @return this {@link Builder} instance, for chaining
+         * @throws IllegalArgumentException if a VcnGatewayConnectionConfig has already been set for
+         *     this {@link VcnConfig} with the same GatewayConnection name (as returned via {@link
+         *     VcnGatewayConnectionConfig#getGatewayConnectionName()}).
          */
         @NonNull
         public Builder addGatewayConnectionConfig(
                 @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
             Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null");
 
+            for (final VcnGatewayConnectionConfig vcnGatewayConnectionConfig :
+                    mGatewayConnectionConfigs) {
+                if (vcnGatewayConnectionConfig
+                        .getGatewayConnectionName()
+                        .equals(gatewayConnectionConfig.getGatewayConnectionName())) {
+                    throw new IllegalArgumentException(
+                            "GatewayConnection for specified name already exists");
+                }
+            }
+
             mGatewayConnectionConfigs.add(gatewayConnectionConfig);
             return this;
         }
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index d4e8e2d..75db3820 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -148,6 +148,8 @@
                 TimeUnit.MINUTES.toMillis(5),
                 TimeUnit.MINUTES.toMillis(15)
             };
+    private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
+    @NonNull private final String mGatewayConnectionName;
 
     private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig";
     @NonNull private VcnControlPlaneConfig mCtrlPlaneConfig;
@@ -166,11 +168,13 @@
 
     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
     private VcnGatewayConnectionConfig(
+            @NonNull String gatewayConnectionName,
             @NonNull VcnControlPlaneConfig ctrlPlaneConfig,
             @NonNull Set<Integer> exposedCapabilities,
             @NonNull Set<Integer> underlyingCapabilities,
             @NonNull long[] retryIntervalsMs,
             @IntRange(from = MIN_MTU_V6) int maxMtu) {
+        mGatewayConnectionName = gatewayConnectionName;
         mCtrlPlaneConfig = ctrlPlaneConfig;
         mExposedCapabilities = new TreeSet(exposedCapabilities);
         mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
@@ -192,6 +196,7 @@
         final PersistableBundle underlyingCapsBundle =
                 in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
 
+        mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
         mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle);
         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
@@ -204,6 +209,7 @@
     }
 
     private void validate() {
+        Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
         Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null");
 
         Preconditions.checkArgument(
@@ -242,6 +248,20 @@
     }
 
     /**
+     * Returns the configured Gateway Connection name.
+     *
+     * <p>This name is used by the configuring apps to distinguish between
+     * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as
+     * the identifier in VcnStatusCallback invocations.
+     *
+     * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
+     */
+    @NonNull
+    public String getGatewayConnectionName() {
+        return mGatewayConnectionName;
+    }
+
+    /**
      * Returns control plane configuration.
      *
      * @hide
@@ -364,6 +384,7 @@
                         new ArrayList<>(mUnderlyingCapabilities),
                         PersistableBundleUtils.INTEGER_SERIALIZER);
 
+        result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
         result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle);
         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
         result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
@@ -376,6 +397,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(
+                mGatewayConnectionName,
                 mExposedCapabilities,
                 mUnderlyingCapabilities,
                 Arrays.hashCode(mRetryIntervalsMs),
@@ -389,7 +411,8 @@
         }
 
         final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
-        return mExposedCapabilities.equals(rhs.mExposedCapabilities)
+        return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
+                && mExposedCapabilities.equals(rhs.mExposedCapabilities)
                 && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
                 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
                 && mMaxMtu == rhs.mMaxMtu;
@@ -399,6 +422,7 @@
      * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
      */
     public static final class Builder {
+        @NonNull private final String mGatewayConnectionName;
         @NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig;
         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
         @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@@ -412,12 +436,22 @@
         /**
          * Construct a Builder object.
          *
+         * @param gatewayConnectionName the String GatewayConnection name for this
+         *     VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link
+         *     VcnConfig} must be given a unique name. This name is used by the caller to
+         *     distinguish between VcnGatewayConnectionConfigs configured on a single {@link
+         *     VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
          * @param ctrlPlaneConfig the control plane configuration
          * @see VcnControlPlaneConfig
+         * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
          */
-        public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+        public Builder(
+                @NonNull String gatewayConnectionName,
+                @NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+            Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
             Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null");
 
+            mGatewayConnectionName = gatewayConnectionName;
             mCtrlPlaneConfig = ctrlPlaneConfig;
         }
 
@@ -562,6 +596,7 @@
         @NonNull
         public VcnGatewayConnectionConfig build() {
             return new VcnGatewayConnectionConfig(
+                    mGatewayConnectionName,
                     mCtrlPlaneConfig,
                     mExposedCapabilities,
                     mUnderlyingCapabilities,
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index abd41da..d09094c 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -445,18 +445,16 @@
          * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
          * encounters an error.
          *
-         * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
-         *     for the Gateway Connection that encountered the error, for identification purposes.
-         *     These will be a sorted list with no duplicates and will match {@link
-         *     VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link
-         *     VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
-         *     group.
+         * @param gatewayConnectionName the String GatewayConnection name for the GatewayConnection
+         *     encountering an error. This will match the name for exactly one {@link
+         *     VcnGatewayConnectionConfig} for the {@link VcnConfig} configured for this callback's
+         *     subscription group
          * @param errorCode the code to indicate the error that occurred
          * @param detail Throwable to provide additional information about the error, or {@code
          *     null} if none
          */
         public abstract void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable Throwable detail);
     }
@@ -586,7 +584,7 @@
         // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
@@ -597,7 +595,7 @@
                             mExecutor.execute(
                                     () ->
                                             mCallback.onGatewayConnectionError(
-                                                    networkCapabilities, errorCode, cause)));
+                                                    gatewayConnectionName, errorCode, cause)));
         }
 
         private static Throwable createThrowableByClassName(
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 2b6f336..0331483 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -124,6 +124,30 @@
     public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
 
+    /**
+     * Identifiers of models used for power estimation.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"POWER_MODEL_"}, value = {
+            POWER_MODEL_POWER_PROFILE,
+            POWER_MODEL_MEASURED_ENERGY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PowerModel {
+    }
+
+    /**
+     * Power model that is based on average consumption rates that hardware components
+     * consume in various states.
+     */
+    public static final int POWER_MODEL_POWER_PROFILE = 0;
+
+    /**
+     * Power model that is based on energy consumption measured by on-device power monitors.
+     */
+    public static final int POWER_MODEL_MEASURED_ENERGY = 1;
+
     private final PowerComponents mPowerComponents;
 
     protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
@@ -149,6 +173,16 @@
     }
 
     /**
+     * Returns the ID of the model that was used for power estimation.
+     *
+     * @param componentId The ID of the power component, e.g.
+     *                    {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+     */
+    public @PowerModel int getPowerModel(@BatteryConsumer.PowerComponent int componentId) {
+        return mPowerComponents.getPowerModel(componentId);
+    }
+
+    /**
      * Returns the amount of drain attributed to the specified custom drain type.
      *
      * @param componentId The ID of the custom power component.
@@ -188,9 +222,22 @@
     protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
         final PowerComponents.Builder mPowerComponentsBuilder;
 
-        public BaseBuilder(int customPowerComponentCount, int customTimeComponentCount) {
+        public BaseBuilder(int customPowerComponentCount, int customTimeComponentCount,
+                boolean includePowerModels) {
             mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentCount,
-                    customTimeComponentCount);
+                    customTimeComponentCount, includePowerModels);
+        }
+
+        /**
+         * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
+         *
+         * @param componentId    The ID of the power component, e.g.
+         *                       {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+         * @param componentPower Amount of consumed power in mAh.
+         */
+        @NonNull
+        public T setConsumedPower(@PowerComponent int componentId, double componentPower) {
+            return setConsumedPower(componentId, componentPower, POWER_MODEL_POWER_PROFILE);
         }
 
         /**
@@ -202,8 +249,9 @@
          */
         @SuppressWarnings("unchecked")
         @NonNull
-        public T setConsumedPower(@PowerComponent int componentId, double componentPower) {
-            mPowerComponentsBuilder.setConsumedPower(componentId, componentPower);
+        public T setConsumedPower(@PowerComponent int componentId, double componentPower,
+                @PowerModel int powerModel) {
+            mPowerComponentsBuilder.setConsumedPower(componentId, componentPower, powerModel);
             return (T) this;
         }
 
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index bcd00b2..f288774 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -261,6 +261,7 @@
     public static final class Builder {
         private final int mCustomPowerComponentCount;
         private final int mCustomTimeComponentCount;
+        private final boolean mIncludePowerModels;
         private long mStatsStartTimestampMs;
         private int mDischargePercentage;
         private double mDischargedPowerLowerBoundMah;
@@ -277,8 +278,14 @@
         private List<BatteryStats.HistoryTag> mHistoryTagPool;
 
         public Builder(int customPowerComponentCount, int customTimeComponentCount) {
+            this(customPowerComponentCount, customTimeComponentCount, false);
+        }
+
+        public Builder(int customPowerComponentCount, int customTimeComponentCount,
+                boolean includePowerModels) {
             mCustomPowerComponentCount = customPowerComponentCount;
             mCustomTimeComponentCount = customTimeComponentCount;
+            mIncludePowerModels = includePowerModels;
         }
 
         /**
@@ -360,7 +367,7 @@
             UidBatteryConsumer.Builder builder = mUidBatteryConsumerBuilders.get(uid);
             if (builder == null) {
                 builder = new UidBatteryConsumer.Builder(mCustomPowerComponentCount,
-                        mCustomTimeComponentCount, batteryStatsUid);
+                        mCustomTimeComponentCount, mIncludePowerModels, batteryStatsUid);
                 mUidBatteryConsumerBuilders.put(uid, builder);
             }
             return builder;
@@ -376,7 +383,7 @@
             SystemBatteryConsumer.Builder builder = mSystemBatteryConsumerBuilders.get(drainType);
             if (builder == null) {
                 builder = new SystemBatteryConsumer.Builder(mCustomPowerComponentCount,
-                        mCustomTimeComponentCount, drainType);
+                        mCustomTimeComponentCount, mIncludePowerModels, drainType);
                 mSystemBatteryConsumerBuilders.put(drainType, builder);
             }
             return builder;
@@ -391,7 +398,7 @@
             UserBatteryConsumer.Builder builder = mUserBatteryConsumerBuilders.get(userId);
             if (builder == null) {
                 builder = new UserBatteryConsumer.Builder(mCustomPowerComponentCount,
-                        mCustomTimeComponentCount, userId);
+                        mCustomTimeComponentCount, mIncludePowerModels, userId);
                 mUserBatteryConsumerBuilders.put(userId, builder);
             }
             return builder;
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 85861bc..5080442 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -60,6 +60,12 @@
      */
     public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;
 
+    /**
+     * Indicates that identifiers of power models used for computations of power
+     * consumption should be included in the BatteryUsageStats.
+     */
+    public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS = 4;
+
     private static final long DEFAULT_MAX_STATS_AGE_MS = 5 * 60 * 1000;
 
     private final int mFlags;
@@ -187,6 +193,17 @@
         }
 
         /**
+         * Requests to return identifiers of models that were used for estimation
+         * of power consumption.
+         *
+         * Should only be used for testing and debugging.
+         */
+        public Builder includePowerModels() {
+            mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS;
+            return this;
+        }
+
+        /**
          * Set the client's tolerance for stale battery stats. The data may be up to
          * this many milliseconds out-of-date.
          */
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index d239b23..238f451 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -33,12 +33,14 @@
     private final double[] mPowerComponentsMah;
     private final long[] mTimeComponentsMs;
     private final int mCustomPowerComponentCount;
+    private final byte[] mPowerModels;
 
     PowerComponents(@NonNull Builder builder) {
         mCustomPowerComponentCount = builder.mCustomPowerComponentCount;
         mPowerComponentsMah = builder.mPowerComponentsMah;
         mTimeComponentsMs = builder.mTimeComponentsMs;
         mTotalConsumedPowerMah = builder.getTotalPower();
+        mPowerModels = builder.mPowerModels;
     }
 
     PowerComponents(@NonNull Parcel source) {
@@ -46,6 +48,12 @@
         mCustomPowerComponentCount = source.readInt();
         mPowerComponentsMah = source.createDoubleArray();
         mTimeComponentsMs = source.createLongArray();
+        if (source.readBoolean()) {
+            mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
+            source.readByteArray(mPowerModels);
+        } else {
+            mPowerModels = null;
+        }
     }
 
     /** Writes contents to Parcel */
@@ -54,6 +62,12 @@
         dest.writeInt(mCustomPowerComponentCount);
         dest.writeDoubleArray(mPowerComponentsMah);
         dest.writeLongArray(mTimeComponentsMs);
+        if (mPowerModels != null) {
+            dest.writeBoolean(true);
+            dest.writeByteArray(mPowerModels);
+        } else {
+            dest.writeBoolean(false);
+        }
     }
 
     /**
@@ -103,6 +117,15 @@
         }
     }
 
+    @BatteryConsumer.PowerModel
+    int getPowerModel(@BatteryConsumer.PowerComponent int component) {
+        if (mPowerModels == null) {
+            throw new IllegalStateException(
+                    "Power model IDs were not requested in the BatteryUsageStatsQuery");
+        }
+        return mPowerModels[component];
+    }
+
     /**
      * Returns the amount of time used by the specified component, e.g. CPU, WiFi etc.
      *
@@ -148,14 +171,21 @@
         private final double[] mPowerComponentsMah;
         private final int mCustomPowerComponentCount;
         private final long[] mTimeComponentsMs;
+        private final byte[] mPowerModels;
 
-        Builder(int customPowerComponentCount, int customTimeComponentCount) {
+        Builder(int customPowerComponentCount, int customTimeComponentCount,
+                boolean includePowerModels) {
             mCustomPowerComponentCount = customPowerComponentCount;
             int powerComponentCount =
                     BatteryConsumer.POWER_COMPONENT_COUNT + customPowerComponentCount;
             mPowerComponentsMah = new double[powerComponentCount];
             mTimeComponentsMs =
                     new long[BatteryConsumer.TIME_COMPONENT_COUNT + customTimeComponentCount];
+            if (includePowerModels) {
+                mPowerModels = new byte[BatteryConsumer.POWER_COMPONENT_COUNT];
+            } else {
+                mPowerModels = null;
+            }
         }
 
         /**
@@ -167,7 +197,7 @@
          */
         @NonNull
         public Builder setConsumedPower(@BatteryConsumer.PowerComponent int componentId,
-                double componentPower) {
+                double componentPower, @BatteryConsumer.PowerModel int powerModel) {
             if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) {
                 throw new IllegalArgumentException(
                         "Unsupported power component ID: " + componentId);
@@ -178,6 +208,9 @@
                 throw new IllegalArgumentException(
                         "Unsupported power component ID: " + componentId);
             }
+            if (mPowerModels != null) {
+                mPowerModels[componentId] = (byte) powerModel;
+            }
             return this;
         }
 
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index 5f35332..e973e4c 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -141,8 +141,8 @@
         private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
 
         Builder(int customPowerComponentCount, int customTimeComponentCount,
-                @DrainType int drainType) {
-            super(customPowerComponentCount, customTimeComponentCount);
+                boolean includePowerModels, @DrainType int drainType) {
+            super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
             mDrainType = drainType;
         }
 
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index dfa0c39..87c263b 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -140,8 +140,8 @@
         private boolean mExcludeFromBatteryUsageStats;
 
         public Builder(int customPowerComponentCount, int customTimeComponentCount,
-                @NonNull BatteryStats.Uid batteryStatsUid) {
-            super(customPowerComponentCount, customTimeComponentCount);
+                boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
+            super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
             mBatteryStatsUid = batteryStatsUid;
             mUid = batteryStatsUid.getUid();
         }
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index 94e567f..7832208 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -77,8 +77,9 @@
         private final int mUserId;
         private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
 
-        Builder(int customPowerComponentCount, int customTimeComponentCount, int userId) {
-            super(customPowerComponentCount, customTimeComponentCount);
+        Builder(int customPowerComponentCount, int customTimeComponentCount,
+                boolean includePowerModels, int userId) {
+            super(customPowerComponentCount, customTimeComponentCount, includePowerModels);
             mUserId = userId;
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 259d3ac..1ff625d3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8600,8 +8600,6 @@
                 // available, we cannot compute end-to-end input latency metrics.
                 return;
             }
-            final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED];
-            mReceiver.reportTimeline(inputEventId, gpuCompletedTime, presentTime);
         }
     }
     HardwareRendererObserver mHardwareRendererObserver;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 957e416..6bf4645 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -34,7 +34,7 @@
 
 interface IBatteryStats {
     // These first methods are also called by native code, so must
-    // be kept in sync with frameworks/native/libs/binder/include/binder/IBatteryStats.h
+    // be kept in sync with frameworks/native/libs/binder/include_batterystats/batterystats/IBatteryStats.h
     void noteStartSensor(int uid, int sensor);
     void noteStopSensor(int uid, int sensor);
     void noteStartVideo(int uid);
diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
index 586607e..2f49582 100644
--- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
+++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java
@@ -44,14 +44,15 @@
     @Override
     public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(measuredEnergyUC, query);
         final long durationMs = calculateDuration(batteryStats, rawRealtimeUs,
                 BatteryStats.STATS_SINCE_CHARGED);
-        final double powerMah = getMeasuredOrEstimatedPower(
-                batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(),
-                mPowerEstimator, durationMs, query.shouldForceUsePowerProfileModel());
+        final double powerMah = getMeasuredOrEstimatedPower(powerModel,
+                measuredEnergyUC, mPowerEstimator, durationMs);
         builder.getOrCreateSystemBatteryConsumerBuilder(
                         SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah, powerModel)
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs);
     }
 
@@ -64,10 +65,12 @@
     @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
+        final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC();
         final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType);
-        final double powerMah = getMeasuredOrEstimatedPower(
+        final int powerModel = getPowerModel(measuredEnergyUC);
+        final double powerMah = getMeasuredOrEstimatedPower(powerModel,
                 batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(),
-                mPowerEstimator, durationMs, false);
+                mPowerEstimator, durationMs);
         if (powerMah > 0) {
             BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0);
             bs.usagePowerMah = powerMah;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b0920b0..ac72d29 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -41,7 +41,6 @@
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
-import android.os.BatteryProperty;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Build;
@@ -58,7 +57,6 @@
 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.os.WorkSource.WorkChain;
@@ -150,14 +148,6 @@
 public class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
-
-    // TODO(b/169376495): STOPSHIP if true
-    private static final boolean DEBUG_FOREGROUND_STATS = true;
-
-    private static final boolean ENABLE_FOREGROUND_STATS_COLLECTION =
-            DEBUG_FOREGROUND_STATS && SystemProperties.getBoolean(
-                    "debug.battery_foreground_stats_collection", false);
-
     public static final boolean DEBUG_ENERGY = false;
     private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
     private static final boolean DEBUG_BINDER_STATS = false;
@@ -752,37 +742,6 @@
     long mTrackRunningHistoryElapsedRealtimeMs = 0;
     long mTrackRunningHistoryUptimeMs = 0;
 
-    private static final int FOREGROUND_UID_INITIAL_CAPACITY = 10;
-    private static final int INVALID_UID = -1;
-
-    private final IntArray mForegroundUids = ENABLE_FOREGROUND_STATS_COLLECTION
-            ? new IntArray(FOREGROUND_UID_INITIAL_CAPACITY) :  null;
-
-    // Last recorded battery energy capacity.
-    // This is used for computing foregrund power per application.
-    // See: PowerForUid below
-    private long mLastBatteryEnergyCapacityNwh = 0;
-
-    private static final class PowerForUid {
-        public long energyNwh = 0;
-        // Same as energyNwh, but not tracked for the first 2 minutes;
-        public long filteredEnergyNwh = 0;
-        public double totalHours = 0;
-        public long baseTimeMs = 0;
-
-        double computePower() {
-            // units in nW
-            return totalHours != 0 ? energyNwh / totalHours : -1.0;
-        }
-
-        double computeFilteredPower() {
-            // units in nW
-            return totalHours != 0 ? filteredEnergyNwh / totalHours : -1.0;
-        }
-    }
-    private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
-            ? new HashMap<>() : null;
-
     @NonNull
     final BatteryStatsHistory mBatteryStatsHistory;
 
@@ -1094,7 +1053,6 @@
     private int mNumConnectivityChange;
 
     private int mBatteryVoltageMv = -1;
-    private int mBatteryChargeUah = -1;
     private int mEstimatedBatteryCapacityMah = -1;
 
     private int mMinLearnedBatteryCapacityUah = -1;
@@ -4020,49 +3978,6 @@
         // TODO(b/155216561): It is possible for isolated uids to be in a higher
         // state than its parent uid. We should track the highest state within the union of host
         // and isolated uids rather than only the parent uid.
-
-
-        int uidState = mapToInternalProcessState(state);
-
-        boolean isForeground = (uidState == Uid.PROCESS_STATE_TOP)
-                ||  (uidState == Uid.PROCESS_STATE_FOREGROUND);
-
-
-        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
-            boolean previouslyInForegrond = false;
-            for (int i = 0; i < mForegroundUids.size(); i++) {
-                if (mForegroundUids.get(i) == uid) {
-                    previouslyInForegrond = true;
-                    if (!isForeground) {
-                        // If we were previously in the foreground, remove the uid
-                        // from the foreground set and dirty the slot.
-                        mForegroundUids.set(i, INVALID_UID);
-                        final PowerForUid pfu =
-                                mUidToPower.computeIfAbsent(uid, unused -> new PowerForUid());
-                        pfu.baseTimeMs = 0;
-                        break;
-                    }
-                }
-            }
-
-            if (!previouslyInForegrond && isForeground) {
-                boolean addedToForeground = false;
-                // Check if we have a free slot to clobber...
-                for (int i = 0; i < mForegroundUids.size(); i++) {
-                    if (mForegroundUids.get(i) == INVALID_UID) {
-                        addedToForeground = true;
-                        mForegroundUids.set(i, uid);
-                        break;
-                    }
-                }
-
-                // ...if not, append to the end of the array.
-                if (!addedToForeground) {
-                    mForegroundUids.add(uid);
-                }
-            }
-        }
-
         FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
                 ActivityManager.processStateAmToProto(state));
         getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
@@ -13547,7 +13462,6 @@
                 doWrite = true;
                 resetAllStatsLocked(mSecUptime, mSecRealtime);
                 if (chargeUah > 0 && level > 0) {
-                    mBatteryChargeUah = chargeUah;
                     // Only use the reported coulomb charge value if it is supported and reported.
                     mEstimatedBatteryCapacityMah = (int) ((chargeUah / 1000) / (level / 100.0));
                 }
@@ -13720,48 +13634,7 @@
                 startRecordingHistory(elapsedRealtimeMs, uptimeMs, true);
             }
         }
-
         mBatteryVoltageMv = voltageMv;
-
-        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
-            if (onBattery) {
-                final long energyNwh = (voltageMv * (long) chargeUah);
-                final long energyDelta = mLastBatteryEnergyCapacityNwh - energyNwh;
-                for (int i = 0; i < mForegroundUids.size(); i++) {
-                    final int uid = mForegroundUids.get(i);
-                    if (uid == INVALID_UID) {
-                        continue;
-                    }
-                    final PowerForUid pfu = mUidToPower
-                            .computeIfAbsent(uid, unused -> new PowerForUid());
-                    if (pfu.baseTimeMs <= 0) {
-                        pfu.baseTimeMs = currentTimeMs;
-                    } else {
-                        // Check if mLastBatteryEnergyCapacityNwh > energyNwh,
-                        // to make sure we only count discharges
-                        if (energyDelta > 0) {
-                            pfu.energyNwh += energyDelta;
-                            // Convert from milliseconds to hours
-                            // 1000 ms per second * 3600 seconds per hour
-                            pfu.totalHours += ((double) (currentTimeMs - pfu.baseTimeMs)
-                                    / (1.0 * 1000 * 60 * 60));
-                            // Now convert from 2 minutes to hours
-                            // 2 minutes = 1/30 of an hour
-                            if (pfu.totalHours > (2.0 / 60)) {
-                                pfu.filteredEnergyNwh += energyDelta;
-                            }
-
-                        }
-                        pfu.baseTimeMs = currentTimeMs;
-                    }
-                }
-                mLastBatteryEnergyCapacityNwh = energyNwh;
-            } else if (onBattery != mOnBattery) {
-                // Transition to onBattery = false
-                mUidToPower.values().forEach(v -> v.baseTimeMs = 0);
-            }
-        }
-
         mCurrentBatteryLevel = level;
         if (mDischargePlugLevel < 0) {
             mDischargePlugLevel = level;
@@ -16679,48 +16552,6 @@
     }
 
     public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
-        if (ENABLE_FOREGROUND_STATS_COLLECTION) {
-            long actualChargeUah = -1;
-            long actualEnergyNwh = -1;
-            try {
-                IBatteryPropertiesRegistrar registrar =
-                        IBatteryPropertiesRegistrar.Stub.asInterface(
-                                ServiceManager.getService("batteryproperties"));
-                if (registrar != null) {
-                    BatteryProperty prop = new BatteryProperty();
-                    if (registrar.getProperty(
-                                BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER, prop) == 0) {
-                        actualChargeUah = prop.getLong();
-                    }
-                    prop = new BatteryProperty();
-                    if (registrar.getProperty(
-                                BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER, prop) == 0) {
-                        actualEnergyNwh = prop.getLong();
-                    }
-                }
-            } catch (RemoteException e) {
-                // Ignore.
-            }
-            pw.printf("ActualCharge (uAh): %d\n", (int) actualChargeUah);
-            pw.printf("ActualEnergy (nWh): %d\n", actualEnergyNwh);
-            pw.printf("mBatteryCharge (uAh): %d\n", mBatteryChargeUah);
-            pw.printf("mBatteryVolts (mV): %d\n", mBatteryVoltageMv);
-            pw.printf("est energy (nWh): %d\n", mBatteryVoltageMv * (long) mBatteryChargeUah);
-            pw.printf("mEstimatedBatteryCapacity (mAh): %d\n", mEstimatedBatteryCapacityMah);
-            pw.printf("mMinLearnedBatteryCapacity (uAh): %d\n", mMinLearnedBatteryCapacityUah);
-            pw.printf("mMaxLearnedBatteryCapacity (uAh): %d\n", mMaxLearnedBatteryCapacityUah);
-            pw.printf("est. capacity: %f\n",
-                    (float) actualChargeUah / (mEstimatedBatteryCapacityMah * 1000));
-            pw.printf("mCurrentBatteryLevel: %d\n", mCurrentBatteryLevel);
-            pw.println("Total Power per app:");
-            mUidToPower.entrySet().forEach(e ->
-                    pw.printf("Uid: %d, Total watts (nW): %f\n",
-                            e.getKey(), e.getValue().computePower()));
-            pw.println("Total Power per app after first 2 minutes initial launch:");
-            mUidToPower.entrySet().forEach(e ->
-                    pw.printf("Uid: %d, Total watts (nW): %f\n",
-                            e.getKey(), e.getValue().computeFilteredPower()));
-        }
         if (DEBUG) {
             pw.println("mOnBatteryTimeBase:");
             mOnBatteryTimeBase.dump(pw, "  ");
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index f8ae0c1..49c564b 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -132,9 +132,12 @@
         // TODO(b/174186358): read extra time component number from configuration
         final int customTimeComponentCount = 0;
 
-        final BatteryUsageStats.Builder batteryUsageStatsBuilder =
-                new BatteryUsageStats.Builder(customPowerComponentCount, customTimeComponentCount)
-                        .setStatsStartTimestamp(mStats.getStartClockTime());
+        final boolean includePowerModels = (query.getFlags()
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
+
+        final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
+                customPowerComponentCount, customTimeComponentCount, includePowerModels);
+        batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());
 
         SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
         for (int i = uidStats.size() - 1; i >= 0; i--) {
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 75a9813..a418dff 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -15,8 +15,6 @@
  */
 package com.android.internal.os;
 
-import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
-
 import android.os.BatteryConsumer;
 import android.os.BatteryStats;
 import android.os.BatteryStats.ControllerActivityCounter;
@@ -75,12 +73,13 @@
             }
         }
 
-        final long measuredChargeUC = query.shouldForceUsePowerProfileModel() ?
-                POWER_DATA_UNAVAILABLE : batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
+        final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(measuredChargeUC, query);
         final ControllerActivityCounter activityCounter =
                 batteryStats.getBluetoothControllerActivity();
         final long systemDurationMs = calculateDuration(activityCounter);
-        final double systemPowerMah = calculatePowerMah(measuredChargeUC, activityCounter);
+        final double systemPowerMah =
+                calculatePowerMah(powerModel, measuredChargeUC, activityCounter);
 
         // Subtract what the apps used, but clamp to 0.
         final long systemComponentDurationMs = Math.max(0, systemDurationMs - total.durationMs);
@@ -92,23 +91,22 @@
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
                         systemComponentDurationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
-                        Math.max(systemPowerMah, total.powerMah))
+                        Math.max(systemPowerMah, total.powerMah), powerModel)
                 .setPowerConsumedByApps(total.powerMah);
     }
 
     private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total,
             BatteryUsageStatsQuery query) {
-
-        final long measuredChargeUC = query.shouldForceUsePowerProfileModel() ?
-                POWER_DATA_UNAVAILABLE :
+        final long measuredChargeUC =
                 app.getBatteryStatsUid().getBluetoothMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(measuredChargeUC, query);
         final ControllerActivityCounter activityCounter =
                 app.getBatteryStatsUid().getBluetoothControllerActivity();
         final long durationMs = calculateDuration(activityCounter);
-        final double powerMah = calculatePowerMah(measuredChargeUC, activityCounter);
+        final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter);
 
         app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah);
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah, powerModel);
 
         total.durationMs += durationMs;
         total.powerMah += powerMah;
@@ -132,10 +130,12 @@
 
         BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
         final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(measuredChargeUC);
         final ControllerActivityCounter activityCounter =
                 batteryStats.getBluetoothControllerActivity();
         final long systemDurationMs = calculateDuration(activityCounter);
-        final double systemPowerMah = calculatePowerMah(measuredChargeUC, activityCounter);
+        final double systemPowerMah =
+                calculatePowerMah(powerModel, measuredChargeUC, activityCounter);
 
         // Subtract what the apps used, but clamp to 0.
         final double powerMah = Math.max(0, systemPowerMah - total.powerMah);
@@ -165,9 +165,10 @@
             PowerAndDuration total) {
 
         final long measuredChargeUC = u.getBluetoothMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(measuredChargeUC);
         final ControllerActivityCounter activityCounter = u.getBluetoothControllerActivity();
         final long durationMs = calculateDuration(activityCounter);
-        final double powerMah = calculatePowerMah(measuredChargeUC, activityCounter);
+        final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter);
 
         app.bluetoothRunningTimeMs = durationMs;
         app.bluetoothPowerMah = powerMah;
@@ -189,10 +190,12 @@
     }
 
     /** Returns bluetooth power usage based on the best data available. */
-    private double calculatePowerMah(long measuredChargeUC, ControllerActivityCounter counter) {
-        if (measuredChargeUC != POWER_DATA_UNAVAILABLE) {
+    private double calculatePowerMah(@BatteryConsumer.PowerModel int powerModel,
+            long measuredChargeUC, ControllerActivityCounter counter) {
+        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
             return uCtoMah(measuredChargeUC);
         }
+
         if (counter == null) {
             return 0;
         }
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index b15543a..4aafec5 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -91,10 +91,12 @@
 
     private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
             BatteryUsageStatsQuery query, Result result) {
-        calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED,
-                query.shouldForceUsePowerProfileModel(), result);
+        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC, query);
+        calculatePowerAndDuration(u, powerModel, consumptionUC, BatteryStats.STATS_SINCE_CHARGED,
+                result);
 
-        app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah)
+        app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah, powerModel)
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs)
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND,
                         result.durationFgMs)
@@ -114,7 +116,9 @@
     }
 
     private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
-        calculatePowerAndDuration(u, statsType, false, result);
+        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC);
+        calculatePowerAndDuration(u, powerModel, consumptionUC, statsType, result);
 
         app.cpuPowerMah = result.powerMah;
         app.cpuTimeMs = result.durationMs;
@@ -122,16 +126,20 @@
         app.packageWithHighestDrain = result.packageWithHighestDrain;
     }
 
-    private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType,
-            boolean forceUsePowerProfileModel, Result result) {
+    private void calculatePowerAndDuration(BatteryStats.Uid u,
+            @BatteryConsumer.PowerModel int powerModel, long consumptionUC, int statsType,
+            Result result) {
         long durationMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
 
         final double powerMah;
-        final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
-        if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) {
-            powerMah = calculateUidModeledPowerMah(u, statsType);
-        } else {
-            powerMah = uCtoMah(consumptionUC);
+        switch(powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                powerMah = uCtoMah(consumptionUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                powerMah = calculateUidModeledPowerMah(u, statsType);
+                break;
         }
 
         if (DEBUG && (durationMs != 0 || powerMah != 0)) {
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
index 97c4fd8..0e0870d 100644
--- a/core/java/com/android/internal/os/GnssPowerCalculator.java
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -52,28 +52,30 @@
                 builder.getUidBatteryConsumerBuilders();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-            calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs, rawUptimeUs, query,
-                    averageGnssPowerMa);
+            final long consumptionUC =
+                    app.getBatteryStatsUid().getGnssMeasuredBatteryConsumptionUC();
+            final int powerModel = getPowerModel(consumptionUC, query);
+            calculateApp(app, app.getBatteryStatsUid(), powerModel, rawRealtimeUs,
+                    averageGnssPowerMa, consumptionUC);
         }
     }
 
     private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
-            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
-            double averageGnssPowerMa) {
+            @BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,
+            double averageGnssPowerMa, long measuredChargeUC) {
         final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
-
-        final long measuredChargeUC = u.getGnssMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable = !query.shouldForceUsePowerProfileModel()
-                && measuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE;
-
         final double powerMah;
-        if (isMeasuredPowerAvailable) {
-            powerMah = uCtoMah(measuredChargeUC);
-        } else {
-            powerMah = computePower(durationMs, averageGnssPowerMa);
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                powerMah = uCtoMah(measuredChargeUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                powerMah = computePower(durationMs, averageGnssPowerMa);
         }
+
         app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS, durationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah);
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah, powerModel);
     }
 
     @Override
@@ -83,24 +85,28 @@
         for (int i = sippers.size() - 1; i >= 0; i--) {
             final BatterySipper app = sippers.get(i);
             if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(app, app.uidObj, rawRealtimeUs, statsType, averageGnssPowerMa, false);
+                final long consumptionUC =
+                        app.uidObj.getGnssMeasuredBatteryConsumptionUC();
+                final int powerModel = getPowerModel(consumptionUC);
+                calculateApp(app, app.uidObj, powerModel, rawRealtimeUs, averageGnssPowerMa,
+                        consumptionUC);
             }
         }
     }
 
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            int statsType, double averageGnssPowerMa, boolean shouldForceUsePowerProfileModel) {
+    private void calculateApp(BatterySipper app, BatteryStats.Uid u,
+            @BatteryConsumer.PowerModel int powerModel, long rawRealtimeUs,
+            double averageGnssPowerMa, long measuredChargeUC) {
         final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
 
-        final long measuredChargeUC = u.getGnssMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable = shouldForceUsePowerProfileModel
-                && measuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE;
-
         final double powerMah;
-        if (isMeasuredPowerAvailable) {
-            powerMah = uCtoMah(measuredChargeUC);
-        } else {
-            powerMah = computePower(durationMs, averageGnssPowerMa);
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                powerMah = uCtoMah(measuredChargeUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                powerMah = computePower(durationMs, averageGnssPowerMa);
         }
 
         app.gpsTimeMs = durationMs;
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index f6ef30c..d441d45 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -97,37 +97,41 @@
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
             final BatteryStats.Uid uid = app.getBatteryStatsUid();
-            calculateApp(app, uid, powerPerPacketMah, total,
-                    query.shouldForceUsePowerProfileModel());
+            calculateApp(app, uid, powerPerPacketMah, total, query);
         }
 
-        calculateRemaining(total, batteryStats, rawRealtimeUs,
-                query.shouldForceUsePowerProfileModel());
+        final long consumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC, query);
+        calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);
 
         if (total.remainingPowerMah != 0 || total.totalAppPowerMah != 0) {
             builder.getOrCreateSystemBatteryConsumerBuilder(
-                    SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO)
+                        SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO)
                     .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
                             total.durationMs)
                     .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
-                            total.remainingPowerMah + total.totalAppPowerMah)
+                            total.remainingPowerMah + total.totalAppPowerMah,
+                            powerModel)
                     .setPowerConsumedByApps(total.totalAppPowerMah);
         }
     }
 
     private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
             double powerPerPacketMah, PowerAndDuration total,
-            boolean shouldForceUsePowerProfileModel) {
+            BatteryUsageStatsQuery query) {
         final long radioActiveDurationMs = calculateDuration(u, BatteryStats.STATS_SINCE_CHARGED);
         total.totalAppDurationMs += radioActiveDurationMs;
 
-        final double powerMah = calculatePower(u, powerPerPacketMah, radioActiveDurationMs,
-                shouldForceUsePowerProfileModel);
+        final long consumptionUC = u.getMobileRadioMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC, query);
+        final double powerMah = calculatePower(u, powerModel, powerPerPacketMah,
+                radioActiveDurationMs, consumptionUC);
         total.totalAppPowerMah += powerMah;
 
         app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
-                radioActiveDurationMs)
-                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah);
+                        radioActiveDurationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah,
+                        powerModel);
     }
 
     @Override
@@ -140,12 +144,14 @@
             final BatterySipper app = sippers.get(i);
             if (app.drainType == BatterySipper.DrainType.APP) {
                 final BatteryStats.Uid u = app.uidObj;
-                calculateApp(app, u, statsType, mobilePowerPerPacket, total, false);
+                calculateApp(app, u, statsType, mobilePowerPerPacket, total);
             }
         }
 
         BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
-        calculateRemaining(total, batteryStats, rawRealtimeUs, false);
+        final long consumptionUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC);
+        calculateRemaining(total, powerModel, batteryStats, rawRealtimeUs, consumptionUC);
         if (total.remainingPowerMah != 0) {
             if (total.signalDurationMs != 0) {
                 radio.noCoveragePercent =
@@ -162,12 +168,13 @@
     }
 
     private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
-            double powerPerPacketMah, PowerAndDuration total,
-            boolean shouldForceUsePowerProfileModel) {
+            double powerPerPacketMah, PowerAndDuration total) {
         app.mobileActive = calculateDuration(u, statsType);
 
-        app.mobileRadioPowerMah = calculatePower(u, powerPerPacketMah, app.mobileActive,
-                shouldForceUsePowerProfileModel);
+        final long consumptionUC =  u.getMobileRadioMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC);
+        app.mobileRadioPowerMah = calculatePower(u, powerModel, powerPerPacketMah, app.mobileActive,
+                consumptionUC);
         total.totalAppDurationMs += app.mobileActive;
 
         // Add cost of mobile traffic.
@@ -193,13 +200,9 @@
         return u.getMobileRadioActiveTime(statsType) / 1000;
     }
 
-    private double calculatePower(BatteryStats.Uid u, double powerPerPacketMah,
-            long radioActiveDurationMs, boolean shouldForceUsePowerProfileModel) {
-
-        final long measuredChargeUC = u.getMobileRadioMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable = !shouldForceUsePowerProfileModel
-                && measuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE;
-        if (isMeasuredPowerAvailable) {
+    private double calculatePower(BatteryStats.Uid u, @BatteryConsumer.PowerModel int powerModel,
+            double powerPerPacketMah, long radioActiveDurationMs, long measuredChargeUC) {
+        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
             return uCtoMah(measuredChargeUC);
         }
 
@@ -220,23 +223,20 @@
         }
     }
 
-    private void calculateRemaining(MobileRadioPowerCalculator.PowerAndDuration total,
-            BatteryStats batteryStats, long rawRealtimeUs,
-            boolean shouldForceUsePowerProfileModel) {
+    private void calculateRemaining(PowerAndDuration total,
+            @BatteryConsumer.PowerModel int powerModel, BatteryStats batteryStats,
+            long rawRealtimeUs, long consumptionUC) {
         long signalTimeMs = 0;
         double powerMah = 0;
 
-        final long measuredChargeUC = batteryStats.getMobileRadioMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable = !shouldForceUsePowerProfileModel
-                && measuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE;
-        if (isMeasuredPowerAvailable) {
-            powerMah = uCtoMah(measuredChargeUC);
+        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+            powerMah = uCtoMah(consumptionUC);
         }
 
         for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
             long strengthTimeMs = batteryStats.getPhoneSignalStrengthTime(i, rawRealtimeUs,
                     BatteryStats.STATS_SINCE_CHARGED) / 1000;
-            if (!isMeasuredPowerAvailable) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
                 final double p = calcIdlePowerAtSignalStrengthMah(strengthTimeMs, i);
                 if (DEBUG && p != 0) {
                     Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
@@ -256,7 +256,7 @@
                 BatteryStats.STATS_SINCE_CHARGED) / 1000;
         long remainingActiveTimeMs = radioActiveTimeMs - total.totalAppDurationMs;
 
-        if (!isMeasuredPowerAvailable) {
+        if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
             final double p = calcScanTimePowerMah(scanningTimeMs);
             if (DEBUG && p != 0) {
                 Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index 72385e2..d139b4f 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -15,6 +15,8 @@
  */
 package com.android.internal.os;
 
+import android.annotation.NonNull;
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
@@ -114,20 +116,49 @@
     public void reset() {
     }
 
+    protected static @BatteryConsumer.PowerModel int getPowerModel(
+            long measuredEnergyUC, @NonNull BatteryUsageStatsQuery query) {
+        if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE
+                && !query.shouldForceUsePowerProfileModel()) {
+            return BatteryConsumer.POWER_MODEL_MEASURED_ENERGY;
+        }
+        return BatteryConsumer.POWER_MODEL_POWER_PROFILE;
+    }
+
+    protected static @BatteryConsumer.PowerModel int getPowerModel(long measuredEnergyUC) {
+        return measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE
+                ? BatteryConsumer.POWER_MODEL_MEASURED_ENERGY
+                : BatteryConsumer.POWER_MODEL_POWER_PROFILE;
+    }
+
     /**
      * Returns either the measured energy converted to mAh or a usage-based estimate.
      */
-    protected static double getMeasuredOrEstimatedPower(long measuredEnergyUC,
-            UsageBasedPowerEstimator powerEstimator, long durationMs,
-            boolean forceUsePowerProfileModel) {
-        if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE
-                && !forceUsePowerProfileModel) {
-            return uCtoMah(measuredEnergyUC);
+    protected static double getMeasuredOrEstimatedPower(@BatteryConsumer.PowerModel int powerModel,
+            long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) {
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                return uCtoMah(measuredEnergyUC);
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                return powerEstimator.calculatePower(durationMs);
         }
-        return powerEstimator.calculatePower(durationMs);
     }
 
     /**
+     * Returns either the measured energy converted to mAh or a usage-based estimate.
+     */
+    protected static double getMeasuredOrEstimatedPower(
+            long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) {
+        if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
+            return uCtoMah(measuredEnergyUC);
+        } else {
+            return powerEstimator.calculatePower(durationMs);
+        }
+    }
+
+
+    /**
      * Converts charge in mAh to string.
      */
     public static String formatCharge(double power) {
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index ad57444..0267def 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -62,9 +62,10 @@
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
         final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
 
-        final boolean useEnergyData = calculateTotalDurationAndPower(totalPowerAndDuration,
-                batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
-                query.shouldForceUsePowerProfileModel());
+        final long consumptionUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC, query);
+        calculateTotalDurationAndPower(totalPowerAndDuration, powerModel, batteryStats,
+                rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED, consumptionUC);
 
         double totalAppPower = 0;
 
@@ -73,29 +74,32 @@
         // but the method depends on the data source.
         final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                 builder.getUidBatteryConsumerBuilders();
-        if (useEnergyData) {
-            final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
-            for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
-                final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-                calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.getBatteryStatsUid(),
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
+                for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+                    final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+                    calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.getBatteryStatsUid(),
+                            rawRealtimeUs);
+                    app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
+                                    appPowerAndDuration.durationMs)
+                            .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
+                                    appPowerAndDuration.powerMah, powerModel);
+                    totalAppPower += appPowerAndDuration.powerMah;
+                }
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                smearScreenBatteryDrain(uidBatteryConsumerBuilders, totalPowerAndDuration,
                         rawRealtimeUs);
-                app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
-                                appPowerAndDuration.durationMs)
-                        .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
-                                appPowerAndDuration.powerMah);
-                totalAppPower += appPowerAndDuration.powerMah;
-            }
-        } else {
-            smearScreenBatteryDrain(uidBatteryConsumerBuilders, totalPowerAndDuration,
-                    rawRealtimeUs);
-            totalAppPower = totalPowerAndDuration.powerMah;
+                totalAppPower = totalPowerAndDuration.powerMah;
         }
 
         builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE,
                         totalPowerAndDuration.durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE,
-                        Math.max(totalPowerAndDuration.powerMah, totalAppPower))
+                        Math.max(totalPowerAndDuration.powerMah, totalAppPower), powerModel)
                 .setPowerConsumedByApps(totalAppPower);
     }
 
@@ -106,8 +110,10 @@
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
         final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
-        final boolean useEnergyData = calculateTotalDurationAndPower(totalPowerAndDuration,
-                batteryStats, rawRealtimeUs, statsType, false);
+        final long consumptionUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC);
+        calculateTotalDurationAndPower(totalPowerAndDuration, powerModel, batteryStats,
+                rawRealtimeUs, statsType, consumptionUC);
         if (totalPowerAndDuration.powerMah == 0) {
             return;
         }
@@ -121,41 +127,42 @@
 
         // Now deal with each app's BatterySipper. The results are stored in the screenPowerMah
         // field, which is considered smeared, but the method depends on the data source.
-        if (useEnergyData) {
-            final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
-            for (int i = sippers.size() - 1; i >= 0; i--) {
-                final BatterySipper app = sippers.get(i);
-                if (app.drainType == BatterySipper.DrainType.APP) {
-                    calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.uidObj, rawRealtimeUs);
-                    app.screenPowerMah = appPowerAndDuration.powerMah;
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
+                for (int i = sippers.size() - 1; i >= 0; i--) {
+                    final BatterySipper app = sippers.get(i);
+                    if (app.drainType == BatterySipper.DrainType.APP) {
+                        calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.uidObj,
+                                rawRealtimeUs);
+                        app.screenPowerMah = appPowerAndDuration.powerMah;
+                    }
                 }
-            }
-        } else {
-            smearScreenBatterySipper(sippers, bs, rawRealtimeUs);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                smearScreenBatterySipper(sippers, bs, rawRealtimeUs);
         }
     }
 
     /**
-     * Stores duration and power information in totalPowerAndDuration and returns true if measured
-     * energy data is available and should be used by the model.
+     * Stores duration and power information in totalPowerAndDuration.
      */
-    private boolean calculateTotalDurationAndPower(PowerAndDuration totalPowerAndDuration,
-            BatteryStats batteryStats, long rawRealtimeUs, int statsType,
-            boolean forceUsePowerProfileModel) {
+    private void calculateTotalDurationAndPower(PowerAndDuration totalPowerAndDuration,
+            @BatteryConsumer.PowerModel int powerModel, BatteryStats batteryStats,
+            long rawRealtimeUs, int statsType, long consumptionUC) {
         totalPowerAndDuration.durationMs = calculateDuration(batteryStats, rawRealtimeUs,
                 statsType);
 
-        if (!forceUsePowerProfileModel) {
-            final long chargeUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC();
-            if (chargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) {
-                totalPowerAndDuration.powerMah = uCtoMah(chargeUC);
-                return true;
-            }
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                totalPowerAndDuration.powerMah = uCtoMah(consumptionUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats,
+                        rawRealtimeUs, statsType, totalPowerAndDuration.durationMs);
         }
-
-        totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats,
-                rawRealtimeUs, statsType, totalPowerAndDuration.durationMs);
-        return false;
     }
 
     private void calculateAppUsingMeasuredEnergy(PowerAndDuration appPowerAndDuration,
@@ -245,7 +252,8 @@
                 final long durationMs = activityTimeArray.get(app.getUid(), 0);
                 final double powerMah = totalScreenPowerMah * durationMs / totalActivityTimeMs;
                 app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs)
-                        .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah);
+                        .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah,
+                                BatteryConsumer.POWER_MODEL_POWER_PROFILE);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index d95506b..11219ec 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -15,8 +15,6 @@
  */
 package com.android.internal.os;
 
-import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
-
 import android.os.BatteryConsumer;
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
@@ -92,10 +90,12 @@
                 builder.getUidBatteryConsumerBuilders();
         for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
             final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
-            calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), rawRealtimeUs,
-                    BatteryStats.STATS_SINCE_CHARGED,
-                    batteryStats.hasWifiActivityReporting(),
-                    query.shouldForceUsePowerProfileModel());
+            final long consumptionUC =
+                    app.getBatteryStatsUid().getWifiMeasuredBatteryConsumptionUC();
+            final int powerModel = getPowerModel(consumptionUC, query);
+            calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), powerModel,
+                    rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
+                    batteryStats.hasWifiActivityReporting(), consumptionUC);
 
             totalAppDurationMs += powerDurationAndTraffic.durationMs;
             totalAppPowerMah += powerDurationAndTraffic.powerMah;
@@ -103,7 +103,7 @@
             app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
                     powerDurationAndTraffic.durationMs);
             app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
-                    powerDurationAndTraffic.powerMah);
+                    powerDurationAndTraffic.powerMah, powerModel);
 
             if (app.getUid() == Process.WIFI_UID) {
                 systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
@@ -111,17 +111,17 @@
             }
         }
 
-        calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs,
-                BatteryStats.STATS_SINCE_CHARGED,
-                batteryStats.hasWifiActivityReporting(),
-                query.shouldForceUsePowerProfileModel(),
-                totalAppDurationMs, totalAppPowerMah);
+        final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC, query);
+        calculateRemaining(powerDurationAndTraffic, powerModel, batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED, batteryStats.hasWifiActivityReporting(),
+                totalAppDurationMs, totalAppPowerMah, consumptionUC);
 
         systemBatteryConsumerBuilder
                 .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
                         powerDurationAndTraffic.durationMs)
                 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
-                        totalAppPowerMah + powerDurationAndTraffic.powerMah)
+                        totalAppPowerMah + powerDurationAndTraffic.powerMah, powerModel)
                 .setPowerConsumedByApps(totalAppPowerMah);
     }
 
@@ -144,8 +144,11 @@
         for (int i = sippers.size() - 1; i >= 0; i--) {
             final BatterySipper app = sippers.get(i);
             if (app.drainType == BatterySipper.DrainType.APP) {
-                calculateApp(powerDurationAndTraffic, app.uidObj, rawRealtimeUs, statsType,
-                        batteryStats.hasWifiActivityReporting(), /* force use power model*/ false);
+                final long consumptionUC =
+                        app.uidObj.getWifiMeasuredBatteryConsumptionUC();
+                final int powerModel = getPowerModel(consumptionUC);
+                calculateApp(powerDurationAndTraffic, app.uidObj, powerModel, rawRealtimeUs,
+                        statsType, batteryStats.hasWifiActivityReporting(), consumptionUC);
 
                 totalAppDurationMs += powerDurationAndTraffic.durationMs;
                 totalAppPowerMah += powerDurationAndTraffic.powerMah;
@@ -164,9 +167,11 @@
             }
         }
 
-        calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs, statsType,
-                batteryStats.hasWifiActivityReporting(), /* force use power model*/ false,
-                totalAppDurationMs, totalAppPowerMah);
+        final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC();
+        final int powerModel = getPowerModel(consumptionUC);
+        calculateRemaining(powerDurationAndTraffic, powerModel, batteryStats, rawRealtimeUs,
+                statsType, batteryStats.hasWifiActivityReporting(), totalAppDurationMs,
+                totalAppPowerMah, consumptionUC);
 
         bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
         bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
@@ -176,9 +181,10 @@
         }
     }
 
-    private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic, BatteryStats.Uid u,
-            long rawRealtimeUs, int statsType,
-            boolean hasWifiActivityReporting, boolean shouldForceUsePowerProfileModel) {
+    private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic,
+            BatteryStats.Uid u, @BatteryConsumer.PowerModel int powerModel,
+            long rawRealtimeUs, int statsType, boolean hasWifiActivityReporting,
+            long consumptionUC) {
 
         powerDurationAndTraffic.wifiRxPackets = u.getNetworkActivityPackets(
                 BatteryStats.NETWORK_WIFI_RX_DATA,
@@ -193,11 +199,8 @@
                 BatteryStats.NETWORK_WIFI_TX_DATA,
                 statsType);
 
-        final long measuredChargeUC = u.getWifiMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable
-                = !shouldForceUsePowerProfileModel && measuredChargeUC != POWER_DATA_UNAVAILABLE;
-        if (isMeasuredPowerAvailable) {
-            powerDurationAndTraffic.powerMah = uCtoMah(measuredChargeUC);
+        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+            powerDurationAndTraffic.powerMah = uCtoMah(consumptionUC);
         }
 
         if (hasWifiActivityReporting && mHasWifiPowerController) {
@@ -208,7 +211,7 @@
                 final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
 
                 powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
-                if (!isMeasuredPowerAvailable) {
+                if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
                     powerDurationAndTraffic.powerMah
                             = calcPowerFromControllerDataMah(rxTime, txTime, idleTime);
                 }
@@ -223,7 +226,7 @@
             final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
             powerDurationAndTraffic.durationMs = wifiRunningTime;
 
-            if (!isMeasuredPowerAvailable) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
                 final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
                 long batchTimeMs = 0;
                 for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
@@ -243,19 +246,17 @@
     }
 
     private void calculateRemaining(PowerDurationAndTraffic powerDurationAndTraffic,
-            BatteryStats stats, long rawRealtimeUs, int statsType,
-            boolean hasWifiActivityReporting, boolean shouldForceUsePowerProfileModel,
-            long totalAppDurationMs, double totalAppPowerMah) {
+            @BatteryConsumer.PowerModel int powerModel, BatteryStats stats, long rawRealtimeUs,
+            int statsType, boolean hasWifiActivityReporting, long totalAppDurationMs,
+            double totalAppPowerMah, long consumptionUC) {
 
         long totalDurationMs;
         double totalPowerMah = 0;
 
-        final long measuredChargeUC = stats.getWifiMeasuredBatteryConsumptionUC();
-        final boolean isMeasuredPowerAvailable
-                = !shouldForceUsePowerProfileModel && measuredChargeUC != POWER_DATA_UNAVAILABLE;
-        if (isMeasuredPowerAvailable) {
-            totalPowerMah = uCtoMah(measuredChargeUC);
+        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+            totalPowerMah = uCtoMah(consumptionUC);
         }
+
         if (hasWifiActivityReporting && mHasWifiPowerController) {
             final BatteryStats.ControllerActivityCounter counter =
                     stats.getWifiControllerActivity();
@@ -266,7 +267,7 @@
 
             totalDurationMs = idleTimeMs + rxTimeMs + txTimeMs;
 
-            if (!isMeasuredPowerAvailable) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
                 totalPowerMah = counter.getPowerCounter().getCountLocked(statsType)
                         / (double) (1000 * 60 * 60);
                 if (totalPowerMah == 0) {
@@ -276,7 +277,7 @@
             }
         } else {
             totalDurationMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000;
-            if (!isMeasuredPowerAvailable) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
                 totalPowerMah = calcGlobalPowerWithoutControllerDataMah(totalDurationMs);
             }
         }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6f9a381..f0a7a36 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -26,6 +26,7 @@
 #include <nativehelper/JNIHelp.h>
 #include "core_jni_helpers.h"
 
+#include <android/media/AudioVibratorInfo.h>
 #include <audiomanager/AudioManager.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioSystem.h>
@@ -176,7 +177,12 @@
     jmethodID postRoutingUpdatedFromNative;
 } gAudioPolicyEventHandlerMethods;
 
-static struct { jmethodID add; } gListMethods;
+jclass gListClass;
+static struct {
+    jmethodID add;
+    jmethodID get;
+    jmethodID size;
+} gListMethods;
 
 static jclass gAudioDescriptorClass;
 static jmethodID gAudiODescriptorCstor;
@@ -195,6 +201,13 @@
 jclass gAudioProfileClass;
 jmethodID gAudioProfileCstor;
 
+jclass gVibratorClass;
+static struct {
+    jmethodID getId;
+    jmethodID getResonantFrequency;
+    jmethodID getQFactor;
+} gVibratorMethods;
+
 static Mutex gLock;
 
 enum AudioError {
@@ -2627,6 +2640,29 @@
     return jStatus;
 }
 
+static jint android_media_AudioSystem_setVibratorInfos(JNIEnv *env, jobject thiz,
+                                                       jobject jVibrators) {
+    if (!env->IsInstanceOf(jVibrators, gListClass)) {
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    const jint size = env->CallIntMethod(jVibrators, gListMethods.size);
+    std::vector<media::AudioVibratorInfo> vibratorInfos;
+    for (jint i = 0; i < size; ++i) {
+        ScopedLocalRef<jobject> jVibrator(env,
+                                          env->CallObjectMethod(jVibrators, gListMethods.get, i));
+        if (!env->IsInstanceOf(jVibrator.get(), gVibratorClass)) {
+            return (jint)AUDIO_JAVA_BAD_VALUE;
+        }
+        media::AudioVibratorInfo vibratorInfo;
+        vibratorInfo.id = env->CallIntMethod(jVibrator.get(), gVibratorMethods.getId);
+        vibratorInfo.resonantFrequency =
+                env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getResonantFrequency);
+        vibratorInfo.qFactor = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getQFactor);
+        vibratorInfos.push_back(vibratorInfo);
+    }
+    return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] =
@@ -2757,7 +2793,9 @@
           (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
          {"removeUserIdDeviceAffinities", "(I)I",
           (void *)android_media_AudioSystem_removeUserIdDeviceAffinities},
-         {"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid}};
+         {"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid},
+         {"setVibratorInfos", "(Ljava/util/List;)I",
+          (void *)android_media_AudioSystem_setVibratorInfos}};
 
 static const JNINativeMethod gEventHandlerMethods[] = {
     {"native_setup",
@@ -2959,7 +2997,10 @@
             android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "native_release", "()V");
 
     jclass listClass = FindClassOrDie(env, "java/util/List");
+    gListClass = MakeGlobalRefOrDie(env, listClass);
     gListMethods.add = GetMethodIDOrDie(env, listClass, "add", "(Ljava/lang/Object;)Z");
+    gListMethods.get = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+    gListMethods.size = GetMethodIDOrDie(env, listClass, "size", "()I");
 
     jclass audioProfileClass = FindClassOrDie(env, "android/media/AudioProfile");
     gAudioProfileClass = MakeGlobalRefOrDie(env, audioProfileClass);
@@ -2969,6 +3010,13 @@
     gAudioDescriptorClass = MakeGlobalRefOrDie(env, audioDescriptorClass);
     gAudiODescriptorCstor = GetMethodIDOrDie(env, audioDescriptorClass, "<init>", "(II[B)V");
 
+    jclass vibratorClass = FindClassOrDie(env, "android/os/Vibrator");
+    gVibratorClass = MakeGlobalRefOrDie(env, vibratorClass);
+    gVibratorMethods.getId = GetMethodIDOrDie(env, vibratorClass, "getId", "()I");
+    gVibratorMethods.getResonantFrequency =
+            GetMethodIDOrDie(env, vibratorClass, "getResonantFrequency", "()F");
+    gVibratorMethods.getQFactor = GetMethodIDOrDie(env, vibratorClass, "getQFactor", "()F");
+
     AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback);
 
     RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3ebb10e..c144451 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2758,8 +2758,12 @@
     <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
         android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
 
-    <!-- Allows an application to start foreground services from background, can only be granted to
-         privileged apps or app that is SMS/EMERGENCY/SYSTEM GALLERY roles. -->
+    <!-- Allows an application to start foreground services from the background at any time.
+         <em>This permission is not for use by third-party applications</em>,
+         with the only exception being if the app is the default SMS app.
+         Otherwise, it's only usable by privileged apps, app verifier app, and apps with
+         any of the EMERGENCY or SYSTEM GALLERY roles.
+         -->
     <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
                 android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
 
@@ -5580,7 +5584,6 @@
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
                 android:protectionLevel="signature|privileged" />
-    <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
     <!-- @SystemApi Allows an app to override compat change config on release builds.
         Only ChangeIds that are annotated as @Overridable can be overridden on release builds.
         @hide -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9e159f9..6cccdb5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3030,12 +3030,12 @@
   <!-- ===============================================================
      Resources added in version S of the platform
 
-     NOTE: add <public> elements within a <public-group> like so:
+     NOTE: add <public> elements within a <staging-public-group> like so:
 
-     <public-group type="attr" first-id="0x01010531">
+     <staging-public-group type="attr" first-id="0x01010531">
          <public name="exampleAttr1" />
          <public name="exampleAttr2" />
-     </public-group>
+     </staging-public-group>
 
      To add a new public-group block, choose an id value that is 1 greater
      than the last of that item above. For example, the last "attr" id
@@ -3044,7 +3044,7 @@
      =============================================================== -->
   <eat-comment />
 
-  <public-group type="attr" first-id="0x01010617">
+  <staging-public-group type="attr" first-id="0x01010617">
     <public name="rollbackDataPolicy" />
     <public name="allowClickWhenDisabled" />
     <public name="windowLayoutAffinity" />
@@ -3099,13 +3099,13 @@
     <!-- @hide @SystemApi -->
     <public name="throttleDurationMillis" />
     <public name="showInInputMethodPicker" />
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="drawable" first-id="0x010800b5">
+  <staging-public-group type="drawable" first-id="0x010800b5">
     <!-- drawable definitions go here -->
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="color" first-id="0x0106001d">
+  <staging-public-group type="color" first-id="0x0106001d">
     <!-- color definitions go here -->
 
     <!-- Material design dynamic system palette:-->
@@ -3171,26 +3171,26 @@
     <public name="system_accent3_800" />
     <public name="system_accent3_900" />
     <public name="system_accent3_1000" />
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="dimen" first-id="0x01050008">
+  <staging-public-group type="dimen" first-id="0x01050008">
     <!-- dimension definitions go here -->
 
     <!-- System-provided dimensions for app widgets. -->
     <public name="system_app_widget_background_radius" />
     <public name="system_app_widget_inner_radius" />
     <public name="system_app_widget_internal_padding" />
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="bool" first-id="0x01110007">
+  <staging-public-group type="bool" first-id="0x01110007">
     <!-- boolean definitions go here -->
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="style" first-id="0x010302e5">
+  <staging-public-group type="style" first-id="0x010302e5">
     <!-- style definitions go here -->
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="string" first-id="0x01040028">
+  <staging-public-group type="string" first-id="0x01040028">
     <!-- @hide @SystemApi @TestApi -->
     <public name="config_systemAutomotiveCluster" />
     <!-- @hide @SystemApi @TestApi -->
@@ -3211,11 +3211,11 @@
     <public name="config_systemWellbeing" />
     <!-- @hide @SystemApi -->
     <public name="config_systemTelevisionNotificationHandler" />
-  </public-group>
+  </staging-public-group>
 
-  <public-group type="id" first-id="0x01020055">
+  <staging-public-group type="id" first-id="0x01020055">
     <!-- id definitions go here -->
-  </public-group>
+  </staging-public-group>
 
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
index dbe5773..0f3bb1d 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetrics.java
@@ -16,261 +16,99 @@
 
 package com.android.frameworks.core.batterystatsloadtests;
 
-import android.os.Process;
-
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
+import android.util.DebugUtils;
+import android.util.Range;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class PowerMetrics {
-    private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
-    private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
-    private static final String PACKAGE_SYSTEMUI = "com.android.systemui";
-    private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
-            PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI};
 
     enum MetricKind {
         POWER,
         DURATION,
     }
 
-    public static final String METRIC_APP_POWER = "appPower";
-    public static final String METRIC_APP_POWER_EXCLUDE_SYSTEM_FROM_TOTAL = "appPowerExcludeSystem";
-    public static final String METRIC_APP_POWER_EXCLUDE_SMEARED = "appPowerExcludeSmeared";
-    public static final String METRIC_SCREEN_POWER = "screenPower";
-    public static final String METRIC_WIFI_POWER = "wifiPower";
-    public static final String METRIC_SYSTEM_SERVICE_CPU_POWER = "systemService";
-    public static final String METRIC_OTHER_POWER = "otherPower";
-    public static final String METRIC_CPU_POWER = "cpuPower";
-    public static final String METRIC_RAM_POWER = "ramPower";
-    public static final String METRIC_WAKELOCK_POWER = "wakelockPower";
-    public static final String METRIC_MOBILE_RADIO_POWER = "mobileRadioPower";
-    public static final String METRIC_BLUETOOTH_POWER = "bluetoothPower";
-    public static final String METRIC_GPS_POWER = "gpsPower";
-    public static final String METRIC_CAMERA_POWER = "cameraPower";
-    public static final String METRIC_FLASHLIGHT_POWER = "flashlightPower";
-    public static final String METRIC_SENSORS_POWER = "sensorsPower";
-    public static final String METRIC_AUDIO_POWER = "audioPower";
-    public static final String METRIC_VIDEO_POWER = "videoPower";
-    public static final String METRIC_CPU_TIME = "cpuTime";
-    public static final String METRIC_CPU_FOREGROUND_TIME = "cpuForegroundTime";
-    public static final String METRIC_WAKELOCK_TIME = "wakelockTime";
-    public static final String METRIC_WIFI_RUNNING_TIME = "wifiRunningTime";
-    public static final String METRIC_BLUETOOTH_RUNNING_TIME = "bluetoothRunningTime";
-    public static final String METRIC_GPS_TIME = "gpsTime";
-    public static final String METRIC_CAMERA_TIME = "cameraTime";
-    public static final String METRIC_FLASHLIGHT_TIME = "flashlightTime";
-    public static final String METRIC_AUDIO_TIME = "audioTime";
-    public static final String METRIC_VIDEO_TIME = "videoTime";
-
     public static class Metric {
-        public String metricType;
+        public String metricName;
         public MetricKind metricKind;
-        public String title;
+        public String statusKeyPrefix;
         public double value;
         public double total;
     }
 
-    private final double mMinDrainedPower;
-    private final double mMaxDrainedPower;
+    private final double mDrainedPower;
 
     private List<Metric> mMetrics = new ArrayList<>();
 
-    public PowerMetrics(BatteryStatsHelper batteryStatsHelper, int uid) {
-        mMinDrainedPower = batteryStatsHelper.getMinDrainedPower();
-        mMaxDrainedPower = batteryStatsHelper.getMaxDrainedPower();
+    public PowerMetrics(BatteryUsageStats batteryUsageStats, int uid) {
+        final Range<Double> dischargedPowerRange = batteryUsageStats.getDischargedPowerRange();
+        mDrainedPower = (dischargedPowerRange.getLower() + dischargedPowerRange.getUpper()) / 2;
+        double[] totalPowerPerComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
+        long[] totalDurationPerComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT];
 
-        List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
-
-        double totalPowerMah = 0;
-        double totalSmearedPowerMah = 0;
-        double totalPowerExcludeSystemMah = 0;
-        double totalScreenPower = 0;
-        double totalProportionalSmearMah = 0;
-        double totalCpuPowerMah = 0;
-        double totalSystemServiceCpuPowerMah = 0;
-        double totalUsagePowerMah = 0;
-        double totalWakeLockPowerMah = 0;
-        double totalMobileRadioPowerMah = 0;
-        double totalWifiPowerMah = 0;
-        double totalBluetoothPowerMah = 0;
-        double totalGpsPowerMah = 0;
-        double totalCameraPowerMah = 0;
-        double totalFlashlightPowerMah = 0;
-        double totalSensorPowerMah = 0;
-        double totalAudioPowerMah = 0;
-        double totalVideoPowerMah = 0;
-
-        long totalCpuTimeMs = 0;
-        long totalCpuFgTimeMs = 0;
-        long totalWakeLockTimeMs = 0;
-        long totalWifiRunningTimeMs = 0;
-        long totalBluetoothRunningTimeMs = 0;
-        long totalGpsTimeMs = 0;
-        long totalCameraTimeMs = 0;
-        long totalFlashlightTimeMs = 0;
-        long totalAudioTimeMs = 0;
-        long totalVideoTimeMs = 0;
-
-        BatterySipper uidSipper = null;
-        for (BatterySipper sipper : usageList) {
-            if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
-                totalScreenPower = sipper.sumPower();
+        UidBatteryConsumer selectedBatteryConsumer = null;
+        for (UidBatteryConsumer uidBatteryConsumer : batteryUsageStats.getUidBatteryConsumers()) {
+            if (uidBatteryConsumer.getUid() == uid) {
+                selectedBatteryConsumer = uidBatteryConsumer;
             }
 
-            if (isHiddenDrainType(sipper.drainType)) {
-                continue;
+            for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT;
+                    component++) {
+                totalPowerPerComponentMah[component] += uidBatteryConsumer.getConsumedPower(
+                        component);
             }
 
-            if (sipper.drainType == BatterySipper.DrainType.APP && sipper.getUid() == uid) {
-                uidSipper = sipper;
+            for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+                totalDurationPerComponentMs[component] +=
+                        uidBatteryConsumer.getUsageDurationMillis(component);
             }
-
-            totalPowerMah += sipper.sumPower();
-            totalSmearedPowerMah += sipper.totalSmearedPowerMah;
-            totalProportionalSmearMah += sipper.proportionalSmearMah;
-
-            if (!isSystemSipper(sipper)) {
-                totalPowerExcludeSystemMah += sipper.totalSmearedPowerMah;
-            }
-
-            totalCpuPowerMah += sipper.cpuPowerMah;
-            totalSystemServiceCpuPowerMah += sipper.systemServiceCpuPowerMah;
-            totalUsagePowerMah += sipper.usagePowerMah;
-            totalWakeLockPowerMah += sipper.wakeLockPowerMah;
-            totalMobileRadioPowerMah += sipper.mobileRadioPowerMah;
-            totalWifiPowerMah += sipper.wifiPowerMah;
-            totalBluetoothPowerMah += sipper.bluetoothPowerMah;
-            totalGpsPowerMah += sipper.gpsPowerMah;
-            totalCameraPowerMah += sipper.cameraPowerMah;
-            totalFlashlightPowerMah += sipper.flashlightPowerMah;
-            totalSensorPowerMah += sipper.sensorPowerMah;
-            totalAudioPowerMah += sipper.audioPowerMah;
-            totalVideoPowerMah += sipper.videoPowerMah;
-
-            totalCpuTimeMs += sipper.cpuTimeMs;
-            totalCpuFgTimeMs += sipper.cpuFgTimeMs;
-            totalWakeLockTimeMs += sipper.wakeLockTimeMs;
-            totalWifiRunningTimeMs += sipper.wifiRunningTimeMs;
-            totalBluetoothRunningTimeMs += sipper.bluetoothRunningTimeMs;
-            totalGpsTimeMs += sipper.gpsTimeMs;
-            totalCameraTimeMs += sipper.cameraTimeMs;
-            totalFlashlightTimeMs += sipper.flashlightTimeMs;
-            totalAudioTimeMs += sipper.audioTimeMs;
-            totalVideoTimeMs += sipper.videoTimeMs;
         }
 
-        if (uidSipper == null) {
+        if (selectedBatteryConsumer == null) {
             return;
         }
 
-        addMetric(METRIC_APP_POWER, MetricKind.POWER, "Total power",
-                uidSipper.totalSmearedPowerMah, totalSmearedPowerMah);
-        addMetric(METRIC_APP_POWER_EXCLUDE_SYSTEM_FROM_TOTAL, MetricKind.POWER,
-                "Total power excluding system",
-                uidSipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
-        addMetric(METRIC_SCREEN_POWER, MetricKind.POWER, "Screen, smeared",
-                uidSipper.screenPowerMah, totalScreenPower);
-        addMetric(METRIC_OTHER_POWER, MetricKind.POWER, "Other, smeared",
-                uidSipper.proportionalSmearMah, totalProportionalSmearMah);
-        addMetric(METRIC_APP_POWER_EXCLUDE_SMEARED, MetricKind.POWER, "Excluding smeared",
-                uidSipper.totalPowerMah, totalPowerMah);
-        addMetric(METRIC_CPU_POWER, MetricKind.POWER, "CPU",
-                uidSipper.cpuPowerMah, totalCpuPowerMah);
-        addMetric(METRIC_SYSTEM_SERVICE_CPU_POWER, MetricKind.POWER, "System services",
-                uidSipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
-        addMetric(METRIC_RAM_POWER, MetricKind.POWER, "RAM",
-                uidSipper.usagePowerMah, totalUsagePowerMah);
-        addMetric(METRIC_WAKELOCK_POWER, MetricKind.POWER, "Wake lock",
-                uidSipper.wakeLockPowerMah, totalWakeLockPowerMah);
-        addMetric(METRIC_MOBILE_RADIO_POWER, MetricKind.POWER, "Mobile radio",
-                uidSipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
-        addMetric(METRIC_WIFI_POWER, MetricKind.POWER, "WiFi",
-                uidSipper.wifiPowerMah, totalWifiPowerMah);
-        addMetric(METRIC_BLUETOOTH_POWER, MetricKind.POWER, "Bluetooth",
-                uidSipper.bluetoothPowerMah, totalBluetoothPowerMah);
-        addMetric(METRIC_GPS_POWER, MetricKind.POWER, "GPS",
-                uidSipper.gpsPowerMah, totalGpsPowerMah);
-        addMetric(METRIC_CAMERA_POWER, MetricKind.POWER, "Camera",
-                uidSipper.cameraPowerMah, totalCameraPowerMah);
-        addMetric(METRIC_FLASHLIGHT_POWER, MetricKind.POWER, "Flashlight",
-                uidSipper.flashlightPowerMah, totalFlashlightPowerMah);
-        addMetric(METRIC_SENSORS_POWER, MetricKind.POWER, "Sensors",
-                uidSipper.sensorPowerMah, totalSensorPowerMah);
-        addMetric(METRIC_AUDIO_POWER, MetricKind.POWER, "Audio",
-                uidSipper.audioPowerMah, totalAudioPowerMah);
-        addMetric(METRIC_VIDEO_POWER, MetricKind.POWER, "Video",
-                uidSipper.videoPowerMah, totalVideoPowerMah);
+        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+            addMetric(getPowerMetricName(component), MetricKind.POWER,
+                    selectedBatteryConsumer.getConsumedPower(component),
+                    totalPowerPerComponentMah[component]);
+        }
 
-        addMetric(METRIC_CPU_TIME, MetricKind.DURATION, "CPU time",
-                uidSipper.cpuTimeMs, totalCpuTimeMs);
-        addMetric(METRIC_CPU_FOREGROUND_TIME, MetricKind.DURATION, "CPU foreground time",
-                uidSipper.cpuFgTimeMs, totalCpuFgTimeMs);
-        addMetric(METRIC_WAKELOCK_TIME, MetricKind.DURATION, "Wake lock time",
-                uidSipper.wakeLockTimeMs, totalWakeLockTimeMs);
-        addMetric(METRIC_WIFI_RUNNING_TIME, MetricKind.DURATION, "WiFi running time",
-                uidSipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
-        addMetric(METRIC_BLUETOOTH_RUNNING_TIME, MetricKind.DURATION, "Bluetooth time",
-                uidSipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
-        addMetric(METRIC_GPS_TIME, MetricKind.DURATION, "GPS time",
-                uidSipper.gpsTimeMs, totalGpsTimeMs);
-        addMetric(METRIC_CAMERA_TIME, MetricKind.DURATION, "Camera time",
-                uidSipper.cameraTimeMs, totalCameraTimeMs);
-        addMetric(METRIC_FLASHLIGHT_TIME, MetricKind.DURATION, "Flashlight time",
-                uidSipper.flashlightTimeMs, totalFlashlightTimeMs);
-        addMetric(METRIC_AUDIO_TIME, MetricKind.DURATION, "Audio time",
-                uidSipper.audioTimeMs, totalAudioTimeMs);
-        addMetric(METRIC_VIDEO_TIME, MetricKind.DURATION, "Video time",
-                uidSipper.videoTimeMs, totalVideoTimeMs);
+        for (int component = 0; component < BatteryConsumer.TIME_COMPONENT_COUNT; component++) {
+            addMetric(getTimeMetricName(component), MetricKind.DURATION,
+                    selectedBatteryConsumer.getUsageDurationMillis(component),
+                    totalDurationPerComponentMs[component]);
+        }
+    }
+
+    static String getTimeMetricName(int componentId) {
+        return "TIME_" + DebugUtils.constantToString(BatteryConsumer.class,
+                "TIME_COMPONENT_", componentId);
+    }
+
+    static String getPowerMetricName(int componentId) {
+        return "POWER_" + DebugUtils.constantToString(BatteryConsumer.class,
+                "POWER_COMPONENT_", componentId);
     }
 
     public List<Metric> getMetrics() {
         return mMetrics;
     }
 
-    public double getMinDrainedPower() {
-        return mMinDrainedPower;
+    public double getDrainedPower() {
+        return mDrainedPower;
     }
 
-    public double getMaxDrainedPower() {
-        return mMaxDrainedPower;
-    }
-
-    protected boolean isHiddenDrainType(BatterySipper.DrainType drainType) {
-        return drainType == BatterySipper.DrainType.IDLE
-                || drainType == BatterySipper.DrainType.CELL
-                || drainType == BatterySipper.DrainType.SCREEN
-                || drainType == BatterySipper.DrainType.UNACCOUNTED
-                || drainType == BatterySipper.DrainType.OVERCOUNTED
-                || drainType == BatterySipper.DrainType.BLUETOOTH
-                || drainType == BatterySipper.DrainType.WIFI;
-    }
-
-    private boolean isSystemSipper(BatterySipper sipper) {
-        final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
-        if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
-            return true;
-        } else if (sipper.mPackages != null) {
-            for (final String packageName : sipper.mPackages) {
-                for (final String systemPackage : PACKAGES_SYSTEM) {
-                    if (systemPackage.equals(packageName)) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    private void addMetric(String metricType, MetricKind metricKind, String title, double amount,
+    private void addMetric(String metricType, MetricKind metricKind, double amount,
             double totalAmount) {
         Metric metric = new Metric();
-        metric.metricType = metricType;
+        metric.metricName = metricType;
         metric.metricKind = metricKind;
-        metric.title = title;
+        metric.statusKeyPrefix = metricKind.toString().toLowerCase();
         metric.value = amount;
         metric.total = totalAmount;
         mMetrics.add(metric);
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
index 254458c..5b5da60 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/PowerMetricsCollector.java
@@ -19,47 +19,43 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.BatteryConsumer;
 import android.os.BatteryManager;
-import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
 import android.os.Bundle;
+import android.os.ConditionVariable;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.UserManager;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.TimeUtils;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.SystemUtil;
-import com.android.internal.os.BatteryStatsHelper;
-import com.android.internal.os.LoggingPrintStream;
-
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import java.io.PrintStream;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 public class PowerMetricsCollector implements TestRule {
     private final String mTag;
     private final float mBatteryDrainThresholdPct;
     private final int mTimeoutMillis;
 
+    private final Instrumentation mInstrumentation;
     private final Context mContext;
-    private final UserManager mUserManager;
     private final int mUid;
-    private final BatteryStatsHelper mStatsHelper;
-    private final CountDownLatch mSuspendingBatteryInput = new CountDownLatch(1);
+    private final ConditionVariable mSuspendingBatteryInput = new ConditionVariable();
 
     private long mStartTime;
     private volatile float mInitialBatteryLevel;
@@ -68,29 +64,34 @@
     private PowerMetrics mInitialPowerMetrics;
     private PowerMetrics mFinalPowerMetrics;
     private List<PowerMetrics.Metric> mPowerMetricsDelta;
-    private Intent mBatteryStatus;
+    private final BatteryStatsManager mBatteryStatsManager;
+    private final BroadcastReceiver mBatteryLevelReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            handleBatteryStatus(intent);
+        }
+    };
+    private final Bundle mStatus = new Bundle();
+    private final StringWriter mReportStringWriter = new StringWriter();
+    private final IndentingPrintWriter mReportWriter =
+            new IndentingPrintWriter(mReportStringWriter);
 
     @Override
     public Statement apply(Statement base, Description description) {
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                BroadcastReceiver batteryBroadcastReceiver = new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        handleBatteryStatus(intent);
-                    }
-                };
-                mBatteryStatus = mContext.registerReceiver(batteryBroadcastReceiver,
-                        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
                 disableCharger();
                 try {
-                    prepareBatteryLevelMonitor();
                     mStartTime = SystemClock.uptimeMillis();
+                    mContext.registerReceiver(mBatteryLevelReceiver,
+                            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
                     base.evaluate();
                     captureFinalPowerStatsData();
+                    mStatus.putString("report", mReportStringWriter.toString());
+                    mInstrumentation.sendStatus(Activity.RESULT_OK, mStatus);
                 } finally {
-                    mContext.unregisterReceiver(batteryBroadcastReceiver);
+                    mContext.unregisterReceiver(mBatteryLevelReceiver);
                     enableCharger();
                 }
             }
@@ -102,35 +103,41 @@
         mBatteryDrainThresholdPct = batteryDrainThresholdPct;
         mTimeoutMillis = timeoutMillis;
 
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        mContext = instrumentation.getContext();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getContext();
         mUid = Process.myUid();
-        mUserManager = mContext.getSystemService(UserManager.class);
-        // TODO(b/175324611): Use BatteryUsageStats instead
-        mStatsHelper = new BatteryStatsHelper(mContext, false /* collectBatteryBroadcast */);
-        mStatsHelper.create((Bundle) null);
+        mBatteryStatsManager = mContext.getSystemService(BatteryStatsManager.class);
     }
 
-    private void disableCharger() throws InterruptedException {
-        SystemUtil.runShellCommand("dumpsys battery suspend_input");
-        final boolean success = mSuspendingBatteryInput.await(10, TimeUnit.SECONDS);
-        assertTrue("Timed out waiting for battery input to be suspended", success);
+    private void disableCharger() {
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!isCharging(intent)) {
+                    mInitialBatteryLevel = mCurrentBatteryLevel = getBatteryLevel(intent);
+                    mSuspendingBatteryInput.open();
+                }
+            }
+        };
+        final Intent intent = mContext.registerReceiver(
+                receiver,
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+
+        if (isCharging(intent)) {
+            mBatteryStatsManager.suspendBatteryInput();
+            final boolean success = mSuspendingBatteryInput.block(10000);
+            assertTrue("Timed out waiting for battery input to be suspended", success);
+        }
+
+        mContext.unregisterReceiver(receiver);
     }
 
     private void enableCharger() {
-        SystemUtil.runShellCommand("dumpsys battery reset");
+        mBatteryStatsManager.resetBattery(/* forceUpdate */false);
     }
 
     private PowerMetrics readBatteryStatsData() {
-        mStatsHelper.clearStats();
-        mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
-                mUserManager.getUserProfiles());
-        return new PowerMetrics(mStatsHelper, mUid);
-    }
-
-    protected void prepareBatteryLevelMonitor() {
-        handleBatteryStatus(mBatteryStatus);
-        mInitialBatteryLevel = mCurrentBatteryLevel;
+        return new PowerMetrics(mBatteryStatsManager.getBatteryUsageStats(), mUid);
     }
 
     protected void handleBatteryStatus(Intent intent) {
@@ -138,36 +145,35 @@
             return;
         }
 
-        final boolean isCharging = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
-
-        if (mSuspendingBatteryInput.getCount() > 0) {
-            if (!isCharging) {
-                mSuspendingBatteryInput.countDown();
-            }
-            return;
-        }
-
-        if (isCharging) {
+        if (isCharging(intent)) {
             fail("Device must remain disconnected from the power source "
                     + "for the duration of the test");
         }
 
-        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
-        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
-
-        mCurrentBatteryLevel = level * 100 / (float) scale;
+        mCurrentBatteryLevel = getBatteryLevel(intent);
         Log.i(mTag, "Battery level = " + mCurrentBatteryLevel);
 
         // We delay tracking until the battery level drops.  If the resolution of
         // battery level is 1%, and the initially reported level is 73, we don't know whether
         // it's 73.1 or 73.7. Once it drops to 72, we can be confident that the real battery
-        // level it is very close to 72.0 and can start tracking.
+        // level is very close to 72.0 and can start tracking.
         if (mInitialPowerMetrics == null && mCurrentBatteryLevel < mInitialBatteryLevel) {
             mInitialBatteryLevel = mCurrentBatteryLevel;
             mInitialPowerMetrics = readBatteryStatsData();
         }
     }
 
+    private boolean isCharging(Intent intent) {
+        return intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
+    }
+
+    private float getBatteryLevel(Intent intent) {
+        int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+        int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+
+        return level * 100 / (float) scale;
+    }
+
     private void captureFinalPowerStatsData() {
         if (mFinalPowerMetrics != null) {
             return;
@@ -181,7 +187,7 @@
         for (PowerMetrics.Metric initialMetric : initialPowerMetrics) {
             PowerMetrics.Metric finalMetric = null;
             for (PowerMetrics.Metric metric : finalPowerMetrics) {
-                if (metric.title.equals(initialMetric.title)) {
+                if (metric.metricName.equals(initialMetric.metricName)) {
                     finalMetric = metric;
                     break;
                 }
@@ -189,9 +195,9 @@
 
             if (finalMetric != null) {
                 PowerMetrics.Metric delta = new PowerMetrics.Metric();
-                delta.metricType = initialMetric.metricType;
+                delta.metricName = initialMetric.metricName;
                 delta.metricKind = initialMetric.metricKind;
-                delta.title = initialMetric.title;
+                delta.statusKeyPrefix = initialMetric.statusKeyPrefix;
                 delta.total = finalMetric.total - initialMetric.total;
                 delta.value = finalMetric.value - initialMetric.value;
                 mPowerMetricsDelta.add(delta);
@@ -230,73 +236,80 @@
         return mIterations;
     }
 
-    public void dumpMetrics() {
-        dumpMetrics(new LoggingPrintStream() {
-            @Override
-            protected void log(String line) {
-                Log.i(mTag, line);
-            }
-        });
+    public void report(String line) {
+        mReportWriter.println(line);
     }
 
-    public void dumpMetrics(PrintStream out) {
+    public void reportMetrics() {
         List<PowerMetrics.Metric> initialPowerMetrics = mInitialPowerMetrics.getMetrics();
         List<PowerMetrics.Metric> finalPowerMetrics = mFinalPowerMetrics.getMetrics();
 
-        out.println("== Power metrics at test start");
-        dumpPowerStatsData(out, initialPowerMetrics);
+        mReportWriter.println("Power metrics at test start");
+        mReportWriter.increaseIndent();
+        reportPowerStatsData(initialPowerMetrics);
+        mReportWriter.decreaseIndent();
 
-        out.println("== Power metrics at test end");
-        dumpPowerStatsData(out, finalPowerMetrics);
+        mReportWriter.println("Power metrics at test end");
+        mReportWriter.increaseIndent();
+        reportPowerStatsData(finalPowerMetrics);
+        mReportWriter.decreaseIndent();
 
-        out.println("== Power metrics delta");
-        dumpPowerStatsData(out, mPowerMetricsDelta);
+        mReportWriter.println("Power metrics delta");
+        mReportWriter.increaseIndent();
+        reportPowerStatsData(mPowerMetricsDelta);
+        mReportWriter.decreaseIndent();
     }
 
-    protected void dumpPowerStatsData(PrintStream out, List<PowerMetrics.Metric> metrics) {
+    protected void reportPowerStatsData(List<PowerMetrics.Metric> metrics) {
         Locale locale = Locale.getDefault();
         for (PowerMetrics.Metric metric : metrics) {
             double proportion = metric.total != 0 ? metric.value * 100 / metric.total : 0;
             switch (metric.metricKind) {
                 case POWER:
-                    out.println(
-                            String.format(locale, "    %-30s %7.1f mAh %4.1f%%", metric.title,
+                    mReportWriter.println(
+                            String.format(locale, "%-40s %7.1f mAh %4.1f%%", metric.metricName,
                                     metric.value, proportion));
                     break;
                 case DURATION:
-                    out.println(
-                            String.format(locale, "    %-30s %,7d ms  %4.1f%%", metric.title,
+                    mReportWriter.println(
+                            String.format(locale, "%-40s %,7d ms  %4.1f%%", metric.metricName,
                                     (long) metric.value, proportion));
                     break;
             }
         }
     }
 
-    public void dumpMetricAsPercentageOfDrainedPower(String metricType) {
-        double minDrainedPower =
-                mFinalPowerMetrics.getMinDrainedPower() - mInitialPowerMetrics.getMinDrainedPower();
-        double maxDrainedPower =
-                mFinalPowerMetrics.getMaxDrainedPower() - mInitialPowerMetrics.getMaxDrainedPower();
+    public void reportMetricAsPercentageOfDrainedPower(
+            @BatteryConsumer.PowerComponent int component) {
+        double drainedPower =
+                mFinalPowerMetrics.getDrainedPower() - mInitialPowerMetrics.getDrainedPower();
 
-        PowerMetrics.Metric metric = getMetric(metricType);
+        PowerMetrics.Metric metric = getPowerMetric(component);
         double metricDelta = metric.value;
 
-        if (maxDrainedPower - minDrainedPower < 0.1f) {
-            Log.i(mTag, String.format(Locale.getDefault(),
-                    "%s power consumed by the test: %.1f of %.1f mAh (%.1f%%)",
-                    metric.title, metricDelta, maxDrainedPower,
-                    metricDelta / maxDrainedPower * 100));
-        } else {
-            Log.i(mTag, String.format(Locale.getDefault(),
-                    "%s power consumed by the test: %.1f of %.1f - %.1f mAh (%.1f%% - %.1f%%)",
-                    metric.title, metricDelta, minDrainedPower, maxDrainedPower,
-                    metricDelta / minDrainedPower * 100, metricDelta / maxDrainedPower * 100));
-        }
+        final double percent = metricDelta / drainedPower * 100;
+        mStatus.putDouble(metric.statusKeyPrefix, metricDelta);
+        mStatus.putDouble(metric.statusKeyPrefix + "_pct", percent);
+
+        mReportWriter.println(String.format(Locale.getDefault(),
+                "%s power consumed by the test: %.1f of %.1f mAh (%.1f%%)",
+                metric.metricName, metricDelta, drainedPower, percent));
     }
 
-    public PowerMetrics.Metric getMetric(String metricType) {
+    public PowerMetrics.Metric getPowerMetric(@BatteryConsumer.PowerComponent int component) {
+        final String name = PowerMetrics.getPowerMetricName(component);
         for (PowerMetrics.Metric metric : mPowerMetricsDelta) {
-            if (metric.metricType.equals(metricType)) {
+            if (metric.metricName.equals(name)) {
+                return metric;
+            }
+        }
+        return null;
+    }
+
+    public PowerMetrics.Metric getTimeMetric(@BatteryConsumer.TimeComponent int component) {
+        final String name = PowerMetrics.getTimeMetricName(component);
+        for (PowerMetrics.Metric metric : mPowerMetricsDelta) {
+            if (metric.metricName.equals(name)) {
                 return metric;
             }
         }
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java
index 488469d..1ebc743 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/SystemServiceCallLoadTest.java
@@ -23,7 +23,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
-import android.util.Log;
+import android.os.BatteryConsumer;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -58,12 +58,12 @@
             assertNotNull(resolveInfo);
         }
 
-        mPowerMetricsCollector.dumpMetrics();
+        mPowerMetricsCollector.reportMetrics();
 
-        Log.i(TAG, "==");
-        Log.i(TAG, "Total system server calls made " + mPowerMetricsCollector.getIterationCount());
+        mPowerMetricsCollector.report(
+                "Total system server calls made: " + mPowerMetricsCollector.getIterationCount());
 
-        mPowerMetricsCollector.dumpMetricAsPercentageOfDrainedPower(
-                PowerMetrics.METRIC_SYSTEM_SERVICE_CPU_POWER);
+        mPowerMetricsCollector.reportMetricAsPercentageOfDrainedPower(
+                BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES);
     }
 }
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java
index 27495da..15bb3fc 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/src/com/android/frameworks/core/batterystatsloadtests/WiFiLoadTest.java
@@ -16,7 +16,7 @@
 
 package com.android.frameworks.core.batterystatsloadtests;
 
-import android.util.Log;
+import android.os.BatteryConsumer;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -59,14 +59,15 @@
             }
         }
 
-        mPowerMetricsCollector.dumpMetrics();
+        mPowerMetricsCollector.reportMetrics();
 
-        Log.i(TAG, "==");
-        Log.i(TAG, "WiFi running time: " + (long) mPowerMetricsCollector.getMetric(
-                PowerMetrics.METRIC_WIFI_RUNNING_TIME).value);
-        Log.i(TAG, "Total bytes read over WiFi: " + totalBytesRead);
+        mPowerMetricsCollector.report(
+                "WiFi running time: " + (long) mPowerMetricsCollector.getTimeMetric(
+                        BatteryConsumer.POWER_COMPONENT_WIFI).value);
 
-        mPowerMetricsCollector.dumpMetricAsPercentageOfDrainedPower(
-                PowerMetrics.METRIC_WIFI_POWER);
+        mPowerMetricsCollector.report("Total bytes read over WiFi: " + totalBytesRead);
+
+        mPowerMetricsCollector.reportMetricAsPercentageOfDrainedPower(
+                        BatteryConsumer.POWER_COMPONENT_WIFI);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
index c67f901..cf47efd 100644
--- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.SystemBatteryConsumer;
 import android.view.Display;
 
@@ -71,6 +70,8 @@
         // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
                 .isWithin(PRECISION).of(27.777778);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
 
     @Test
@@ -85,8 +86,7 @@
         AmbientDisplayPowerCalculator calculator =
                 new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         SystemBatteryConsumer consumer =
                 mStatsRule.getSystemBatteryConsumer(
@@ -95,5 +95,7 @@
                 .isEqualTo(90 * MINUTE_IN_MS);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
                 .isWithin(PRECISION).of(15.0);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 80ab36e..1e614c4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -43,6 +43,12 @@
 import java.util.Arrays;
 
 public class BatteryUsageStatsRule implements TestRule {
+    public static final BatteryUsageStatsQuery POWER_PROFILE_MODEL_ONLY =
+            new BatteryUsageStatsQuery.Builder()
+                    .powerProfileModeledOnly()
+                    .includePowerModels()
+                    .build();
+
     private final PowerProfile mPowerProfile;
     private final MockClocks mMockClocks = new MockClocks();
     private final MockBatteryStatsImpl mBatteryStats = new MockBatteryStatsImpl(mMockClocks) {
@@ -156,7 +162,8 @@
     }
 
     BatteryUsageStats apply(PowerCalculator... calculators) {
-        return apply(BatteryUsageStatsQuery.DEFAULT, calculators);
+        return apply(new BatteryUsageStatsQuery.Builder().includePowerModels().build(),
+                calculators);
     }
 
     BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
@@ -165,8 +172,10 @@
         final int customMeasuredEnergiesCount = customMeasuredEnergiesMicroJoules != null
                 ? customMeasuredEnergiesMicroJoules.length
                 : 0;
+        final boolean includePowerModels = (query.getFlags()
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                customMeasuredEnergiesCount, 0);
+                customMeasuredEnergiesCount, 0, includePowerModels);
         SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
         for (int i = 0; i < uidStats.size(); i++) {
             builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 2769b16..1a87c10 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.annotation.Nullable;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.UidTraffic;
 import android.os.BatteryConsumer;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
@@ -41,7 +43,8 @@
     public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
             .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0)
             .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0)
-            .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0);
+            .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0)
+            .initMeasuredEnergyStatsLocked(0);
 
     @Test
     public void testTimerBasedModel() {
@@ -60,16 +63,15 @@
         BluetoothPowerCalculator calculator =
                 new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull();
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.24722, 15000);
+                0.24722, 15000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
-                0.51944, 9000, 0.51944, 0.36111);
+                0.51944, 9000, 0.51944, 0.36111, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -89,16 +91,40 @@
         BluetoothPowerCalculator calculator =
                 new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
+
+        assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull();
+        assertBluetoothPowerAndDuration(
+                mStatsRule.getUidBatteryConsumer(APP_UID),
+                0.2, 15000, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+        assertBluetoothPowerAndDuration(
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+                0.45, 9000, 0.45, 0.3, BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+    }
+
+    @Test
+    public void testMeasuredEnergyBasedModel() {
+        final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
+                BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0, 100000);
+        info.setUidTraffic(new UidTraffic[]{
+                new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
+                new UidTraffic(APP_UID, 3000, 4000)
+        });
+        mStatsRule.getBatteryStats().updateBluetoothStateLocked(info, 1200000, 1000, 1000);
+
+        final BluetoothPowerCalculator calculator =
+                new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
+
+        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().includePowerModels().build(),
                 calculator);
 
         assertThat(mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID)).isNull();
         assertBluetoothPowerAndDuration(
                 mStatsRule.getUidBatteryConsumer(APP_UID),
-                0.2, 15000);
+                0.22950, 8416, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertBluetoothPowerAndDuration(
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
-                0.45, 9000, 0.45, 0.3);
+                0.43712, 3584, 0.43712, 0.33329, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
 
     private void setDurationsAndPower(
@@ -111,12 +137,14 @@
     }
 
     private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
-            double powerMah, int durationMs) {
+            double powerMah, int durationMs, @BatteryConsumer.PowerModel int powerModel) {
         assertThat(batteryConsumer).isNotNull();
 
         double consumedPower = batteryConsumer.getConsumedPower(
                 BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
         assertThat(consumedPower).isWithin(PRECISION).of(powerMah);
+        assertThat(batteryConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_BLUETOOTH))
+                .isEqualTo(powerModel);
 
         long usageDurationMillis = batteryConsumer.getUsageDurationMillis(
                 BatteryConsumer.TIME_COMPONENT_BLUETOOTH);
@@ -125,8 +153,9 @@
     }
 
     private void assertBluetoothPowerAndDuration(@Nullable SystemBatteryConsumer batteryConsumer,
-            double powerMah, int durationMs, double consumedPower, double attributedPower) {
-        assertBluetoothPowerAndDuration(batteryConsumer, powerMah, durationMs);
+            double powerMah, int durationMs, double consumedPower, double attributedPower,
+            @BatteryConsumer.PowerModel int powerModel) {
+        assertBluetoothPowerAndDuration(batteryConsumer, powerMah, durationMs, powerModel);
 
         assertThat(batteryConsumer.getConsumedPower())
                 .isWithin(PRECISION).of(consumedPower);
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 496415a..31abbc2 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
 
@@ -142,14 +141,15 @@
         CpuPowerCalculator calculator =
                 new CpuPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
         assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
                 .isEqualTo(3333);
         assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(1.092233);
+        assertThat(uidConsumer1.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
 
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
@@ -157,6 +157,8 @@
                 .isEqualTo(7777);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(2.672322);
+        assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
     }
 
@@ -210,6 +212,8 @@
                 .isEqualTo(3333);
         assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(3.18877);
+        assertThat(uidConsumer1.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
 
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
@@ -217,6 +221,8 @@
                 .isEqualTo(7777);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
                 .isWithin(PRECISION).of(7.44072);
+        assertThat(uidConsumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_CPU))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
index eed61cb..95c3b4e 100644
--- a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
 
@@ -54,14 +53,15 @@
         GnssPowerCalculator calculator =
                 new GnssPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
                 .isEqualTo(1000);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(0.1);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -87,11 +87,15 @@
                 .isEqualTo(1000);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(2.77777);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
         UidBatteryConsumer consumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(consumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
                 .isEqualTo(2000);
         assertThat(consumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
                 .isWithin(PRECISION).of(5.55555);
+        assertThat(consumer2.getPowerModel(BatteryConsumer.POWER_COMPONENT_GNSS))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 813bc9f..3505e8c 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -26,7 +26,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkStats;
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.SystemBatteryConsumer;
 import android.os.UidBatteryConsumer;
@@ -99,13 +98,14 @@
         MobileRadioPowerCalculator calculator =
                 new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         SystemBatteryConsumer consumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(2.2444);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(consumer.getConsumedPower())
                 .isWithin(PRECISION).of(2.2444);
         assertThat(consumer.getPowerConsumedByApps())
@@ -114,6 +114,8 @@
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(0.8);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     @Test
@@ -163,11 +165,15 @@
         // 100000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) + 1.53934 (apps)= 4.31711 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(4.31711);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(consumer.getPowerConsumedByApps())
                 .isWithin(PRECISION).of(1.53934);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isWithin(PRECISION).of(1.53934);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
index d296afa..9cd6ea8 100644
--- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java
@@ -20,7 +20,6 @@
 
 import android.app.ActivityManager;
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.SystemBatteryConsumer;
 import android.os.UidBatteryConsumer;
@@ -91,6 +90,8 @@
         // 600000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s)  = 166.66666 mAh
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
                 .isWithin(PRECISION).of(166.66666);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(consumer.getConsumedPower())
                 .isWithin(PRECISION).of(166.66666);
         assertThat(consumer.getPowerConsumedByApps())
@@ -105,6 +106,8 @@
         // Uid1 charge = 200000000 + 5 / 45 * 300000000 mAs = 64.81 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(64.81481);
+        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
@@ -115,6 +118,8 @@
         // Uid2 charge = 40 / 45 * 300000000 + 100000000 mAs = 101.85 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(101.85185);
+        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
     }
 
     @Test
@@ -144,8 +149,7 @@
         ScreenPowerCalculator calculator =
                 new ScreenPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         SystemBatteryConsumer consumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
@@ -153,6 +157,8 @@
                 .isEqualTo(80 * MINUTE_IN_MS);
         assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
                 .isWithin(PRECISION).of(92.0);
+        assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_USAGE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(consumer.getConsumedPower())
                 .isWithin(PRECISION).of(92.0);
         assertThat(consumer.getPowerConsumedByApps())
@@ -166,6 +172,8 @@
         // Uid1 charge = 20 / 80 * 92.0 = 23.0 mAh
         assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(23.0);
+        assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
@@ -175,6 +183,8 @@
         // Uid2 charge = 60 / 80 * 92.0 = 69.0 mAh
         assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
                 .isWithin(PRECISION).of(69.0);
+        assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
     }
 
     private void setProcState(int uid, int procState, boolean resumed, long realtimeMs,
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index 5df91dd..2e501db 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -24,7 +24,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkStats;
 import android.os.BatteryConsumer;
-import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
 import android.os.SystemBatteryConsumer;
 import android.os.UidBatteryConsumer;
@@ -85,14 +84,15 @@
         batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 1000, 1000);
 
         WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
                 .isEqualTo(1423);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.2214666);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         SystemBatteryConsumer systemConsumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
@@ -100,6 +100,8 @@
                 .isEqualTo(5577);
         assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(1.11153);
+        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(systemConsumer.getPowerConsumedByApps())
                 .isWithin(PRECISION).of(0.466333);
     }
@@ -120,6 +122,8 @@
         /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.2214666 / (0.2214666 + 0.645200) * 1_000_000 / 3600000);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
         SystemBatteryConsumer systemConsumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
@@ -128,6 +132,8 @@
         /* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(1.11153 / (0.2214666 + 0.645200) * 1_000_000 / 3600000);
+        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(systemConsumer.getPowerConsumedByApps())
                 .isWithin(PRECISION).of(0.14946);
     }
@@ -153,14 +159,15 @@
         batteryStats.updateWifiState(/* energyInfo */ null, POWER_DATA_UNAVAILABLE, 1000, 1000);
 
         WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
-        mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
-                calculator);
+        mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
                 .isEqualTo(1000);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.8231573);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
 
         SystemBatteryConsumer systemConsumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
@@ -168,6 +175,8 @@
                 .isEqualTo(2222);
         assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(2.575000);
+        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
         assertThat(systemConsumer.getPowerConsumedByApps())
                 .isWithin(PRECISION).of(1.69907);
     }
@@ -189,6 +198,8 @@
         /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(0.8231573 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);
+        assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
 
         SystemBatteryConsumer systemConsumer =
                 mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
@@ -197,6 +208,8 @@
         /* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
         assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
                 .isWithin(PRECISION).of(2.575000 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);
+        assertThat(systemConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
         assertThat(systemConsumer.getPowerConsumedByApps())
                 .isWithin(PRECISION).of(0.277777);
     }
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 94d5c22..fb08974 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -49,23 +49,12 @@
     private Runnable mOnUpdate;
     private long mStartTime;
     private boolean mForceSoftware;
-    private final ValueAnimator mSparkle = ValueAnimator.ofFloat(0, 1);
+    private boolean mAnimateSparkle;
 
     RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
             boolean forceSoftware) {
         mProperties = properties;
         mForceSoftware = forceSoftware;
-
-        mSparkle.addUpdateListener(anim -> {
-            final long now = AnimationUtils.currentAnimationTimeMillis();
-            final long elapsed = now - mStartTime - ENTER_ANIM_DURATION;
-            final float phase = (float) elapsed / 800;
-            mProperties.getShader().setNoisePhase(phase);
-            notifyUpdate();
-        });
-        mSparkle.setDuration(ENTER_ANIM_DURATION);
-        mSparkle.setInterpolator(LINEAR_INTERPOLATOR);
-        mSparkle.setRepeatCount(ValueAnimator.INFINITE);
     }
 
     @NonNull RippleAnimationSession enter(Canvas canvas) {
@@ -99,6 +88,16 @@
         return this;
     }
 
+    public boolean shouldAnimateSparkle() {
+        return mAnimateSparkle;
+    }
+
+    public float getSparklePhase() {
+        final long now = AnimationUtils.currentAnimationTimeMillis();
+        final long elapsed = now - mStartTime;
+        return  (float) elapsed / 800;
+    }
+
     private boolean isHwAccelerated(Canvas canvas) {
         return canvas.isHardwareAccelerated() && !mForceSoftware;
     }
@@ -115,7 +114,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                mSparkle.end();
+                mAnimateSparkle = false;
                 Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                 if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
             }
@@ -149,7 +148,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                mSparkle.end();
+                mAnimateSparkle = false;
                 Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                 if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
             }
@@ -176,9 +175,7 @@
         expand.addListener(new AnimatorListener(this));
         expand.setInterpolator(FAST_OUT_LINEAR_IN);
         expand.start();
-        if (!mSparkle.isRunning()) {
-            mSparkle.start();
-        }
+        mAnimateSparkle = true;
     }
 
     private void enterSoftware() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 3bd0a43..8b8cbbc 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -48,7 +48,6 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.os.Build;
-import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.view.animation.LinearInterpolator;
 
@@ -152,8 +151,7 @@
     private static final int MAX_RIPPLES = 10;
     private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
     /** Temporary flag for teamfood. **/
-    private static final boolean FORCE_PATTERNED_STYLE =
-            SystemProperties.getBoolean("persist.material.patternedripple", false);
+    private static final boolean FORCE_PATTERNED_STYLE = true;
 
     private final Rect mTempRect = new Rect();
 
@@ -861,6 +859,15 @@
         }
         for (int i = 0; i < mRunningAnimations.size(); i++) {
             RippleAnimationSession s = mRunningAnimations.get(i);
+            if (s.shouldAnimateSparkle()) {
+                final float phase = s.getSparklePhase();
+                if (useCanvasProps) {
+                    s.getCanvasProperties().getShader().setNoisePhase(phase);
+                } else {
+                    s.getProperties().getShader().setNoisePhase(phase);
+                }
+                invalidateSelf();
+            }
             if (useCanvasProps) {
                 RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
                         CanvasProperty<Paint>>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index af4ccad..5c3af3e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -42,7 +42,7 @@
  * Controller class of PiP animations (both from and to PiP mode).
  */
 public class PipAnimationController {
-    private static final float FRACTION_START = 0f;
+    static final float FRACTION_START = 0f;
     private static final float FRACTION_END = 1f;
 
     public static final int ANIM_TYPE_BOUNDS = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 99ec100..f6b63eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -25,6 +25,7 @@
 import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
+import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
@@ -352,9 +353,19 @@
             // updated right after applying the windowing mode change.
             final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
                     mPictureInPictureParams, destinationBounds);
-            scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
+            final PipAnimationController.PipTransitionAnimator<?> animator =
+                    scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
                     0 /* startingAngle */, sourceHintRect, direction,
                     animationDurationMs, null /* updateBoundsCallback */);
+            if (animator != null) {
+                // Even though the animation was started above, re-apply the transaction for the
+                // first frame using the SurfaceControl.Transaction supplied by the
+                // SyncTransactionQueue. This is necessary because the initial surface transform
+                // may not be applied until the next frame if a different Transaction than the one
+                // supplied is used, resulting in 1 frame not being cropped to the source rect
+                // hint during expansion that causes a visible jank/flash. See b/184166183.
+                animator.applySurfaceControlTransaction(mLeash, t, FRACTION_START);
+            }
             mState = State.EXITING_PIP;
         });
     }
@@ -768,22 +779,24 @@
      * Animates resizing of the pinned stack given the duration and start bounds.
      * This always animates the angle to zero from the starting angle.
      */
-    private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
-            float startingAngle, Rect sourceHintRect,
+    private @Nullable PipAnimationController.PipTransitionAnimator<?> scheduleAnimateResizePip(
+            Rect currentBounds, Rect destinationBounds, float startingAngle, Rect sourceHintRect,
             @PipAnimationController.TransitionDirection int direction, int durationMs,
             Consumer<Rect> updateBoundsCallback) {
         if (!mState.isInPip()) {
             // TODO: tend to use shouldBlockResizeRequest here as well but need to consider
             // the fact that when in exitPip, scheduleAnimateResizePip is executed in the window
             // container transaction callback and we want to set the mState immediately.
-            return;
+            return null;
         }
 
-        animateResizePip(currentBounds, destinationBounds, sourceHintRect, direction, durationMs,
+        final PipAnimationController.PipTransitionAnimator<?> animator = animateResizePip(
+                currentBounds, destinationBounds, sourceHintRect, direction, durationMs,
                 startingAngle);
         if (updateBoundsCallback != null) {
             updateBoundsCallback.accept(destinationBounds);
         }
+        return animator;
     }
 
     /**
@@ -968,28 +981,26 @@
                         destinationBounds.height());
                 mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest);
 
-                mMainExecutor.execute(() -> {
-                    // Start animation to fade out the snapshot.
-                    final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
-                    animator.setDuration(mEnterAnimationDuration);
-                    animator.addUpdateListener(animation -> {
-                        final float alpha = (float) animation.getAnimatedValue();
-                        final SurfaceControl.Transaction transaction =
-                                mSurfaceControlTransactionFactory.getTransaction();
-                        transaction.setAlpha(snapshotSurface, alpha);
-                        transaction.apply();
-                    });
-                    animator.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            final SurfaceControl.Transaction tx =
-                                    mSurfaceControlTransactionFactory.getTransaction();
-                            tx.remove(snapshotSurface);
-                            tx.apply();
-                        }
-                    });
-                    animator.start();
+                // Start animation to fade out the snapshot.
+                final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f);
+                animator.setDuration(mEnterAnimationDuration);
+                animator.addUpdateListener(animation -> {
+                    final float alpha = (float) animation.getAnimatedValue();
+                    final SurfaceControl.Transaction transaction =
+                            mSurfaceControlTransactionFactory.getTransaction();
+                    transaction.setAlpha(snapshotSurface, alpha);
+                    transaction.apply();
                 });
+                animator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        final SurfaceControl.Transaction tx =
+                                mSurfaceControlTransactionFactory.getTransaction();
+                        tx.remove(snapshotSurface);
+                        tx.apply();
+                    }
+                });
+                animator.start();
             });
         } else {
             applyFinishBoundsResize(wct, direction);
@@ -1050,26 +1061,28 @@
         return WINDOWING_MODE_UNDEFINED;
     }
 
-    private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect,
+    private @Nullable PipAnimationController.PipTransitionAnimator<?> animateResizePip(
+            Rect currentBounds, Rect destinationBounds, Rect sourceHintRect,
             @PipAnimationController.TransitionDirection int direction, int durationMs,
             float startingAngle) {
         // Could happen when exitPip
         if (mToken == null || mLeash == null) {
             Log.w(TAG, "Abort animation, invalid leash");
-            return;
+            return null;
         }
         final int rotationDelta = mWaitForFixedRotation
                 ? ((mNextRotation - mPipBoundsState.getDisplayLayout().rotation()) + 4) % 4
                 : Surface.ROTATION_0;
         Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
                 ? mPipBoundsState.getBounds() : currentBounds;
-        mPipAnimationController
+        final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
                 .getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds,
-                        sourceHintRect, direction, startingAngle, rotationDelta)
-                .setTransitionDirection(direction)
+                        sourceHintRect, direction, startingAngle, rotationDelta);
+        animator.setTransitionDirection(direction)
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(durationMs)
                 .start();
+        return animator;
     }
 
     /**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8134d6f..7220379 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -27,6 +27,7 @@
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
 import android.os.Build;
+import android.os.Vibrator;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.Pair;
@@ -1937,6 +1938,14 @@
     public static native int getDevicesForRoleAndCapturePreset(
             int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices);
 
+    /**
+     * @hide
+     * Set the vibrators' information. The value will be used to initialize HapticGenerator.
+     * @param vibrators a list of all available vibrators
+     * @return command completion status
+     */
+    public static native int setVibratorInfos(@NonNull List<Vibrator> vibrators);
+
     // Items shared with audio service
 
     /**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 822d22b..4968bd1 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1684,7 +1684,6 @@
     private MediaCodecInfo mCodecInfo;
     private final Object mCodecInfoLock = new Object();
     private MediaCrypto mCrypto;
-    private String mPlaybackId;
 
     private static final int EVENT_CALLBACK = 1;
     private static final int EVENT_SET_CALLBACK = 2;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 2448d48..50a326e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -219,6 +219,15 @@
     private Map<String, Object> mMap;
 
     /**
+     * A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte
+     * hexadecimal string that is used to associate metrics from multiple media codec instances
+     * to the same playback or recording session.
+     * The associated value is a string.
+     * @hide
+     */
+    public static final String LOG_SESSION_ID = "log-session-id";
+
+    /**
      * A key describing the mime type of the MediaFormat.
      * The associated value is a string.
      */
diff --git a/native/android/OWNERS b/native/android/OWNERS
index d414ed4..6f7def8 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -2,3 +2,7 @@
 per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
 per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
 per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS
+
+per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c6472de..bcc22f6 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1405,6 +1405,8 @@
     <string name="user_switch_to_user">Switch to <xliff:g id="user_name" example="John Doe">%s</xliff:g></string>
     <!-- Dialog message when creating a new user [CHAR LIMIT=40] -->
     <string name="creating_new_user_dialog_message">Creating new user…</string>
+    <!-- Text shown to notify that the creation of new user has failed. [CHAR LIMIT=40] -->
+    <string name="add_user_failed">Failed to create a new user</string>
 
     <!-- Title for the preference to enter the nickname of the user to display in the user switcher [CHAR LIMIT=25]-->
     <string name="user_nickname">Nickname</string>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6cf2bb6..b6b5ae5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -458,6 +458,9 @@
     <!-- Permission required for CTS test - SystemMediaRouter2Test -->
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
 
+    <!-- Permission required for CTS test - CtsRotationResolverServiceDeviceTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_ROTATION_RESOLVER" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint.xml b/packages/SystemUI/res/drawable/ic_fingerprint.xml
index e5f3360..91d72a7 100644
--- a/packages/SystemUI/res/drawable/ic_fingerprint.xml
+++ b/packages/SystemUI/res/drawable/ic_fingerprint.xml
@@ -15,45 +15,25 @@
 -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="72dp"
+        android:height="72dp"
         android:tint="?attr/wallpaperTextColor"
-        android:alpha=".75"
-        android:viewportHeight="32.0"
-        android:viewportWidth="32.0">
+        android:viewportWidth="72"
+        android:viewportHeight="72">
     <path
-        android:fillColor="#ffffff"
-        android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0
-         -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,
-         -2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z" />
-    <path
-        android:fillColor="#ffffff"
-        android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,
-        -1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8
-        -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0
-         -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z" />
-    <path
-        android:fillColor="#ffffff"
-        android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,
-        -3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,
-        0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,
-        2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0
-        C13.7,29.5 13.5,29.6 13.3,29.6z" />
-    <path
-        android:fillColor="#ffffff"
-        android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,
-        -6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,
-        1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,
-        0.8C23.4,27.1 22.8,27.1 22.6,27.1z" />
-    <path
-        android:fillColor="#ffffff"
-        android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,
-        -1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,
-        2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,
-        5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,
-        0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,
-        -3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,
-        -1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,
-        4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,
-        29.9z" />
+        android:pathData=
+            "M25.5,16.3283C28.47,14.8433 31.9167,14 35.5834,14C39.2501,14 42.6968,
+            14.8433 45.6668,16.3283
+            M20,28.6669C22.7683,24.3402 28.7084,21.3335 35.5834,21.3335C42.4585,
+            21.3335 48.3985,24.3402 51.1669,28.6669
+            M22.8607,47.0002C21.834,44.3235 21.834,41.5002 21.834,41.5002C21.834,
+            34.4051 27.7374,28.6667 35.5841,28.6667C43.4308,28.6667 49.3341,34.4051 49.3341,41.5002
+            M49.3344,41.5003V42.0319C49.3344,44.7636 47.1161,47.0003 44.3661,47.0003C41.9461,
+            47.0003 39.8744,45.2403 39.471,42.857L38.9577,39.7769C38.591,37.5953 36.7027,
+            36.0002 34.5027,36.0002C26.5826,36.0002 29.846,49.1087 35.291,50.6487
+            M44.9713,54.6267C42.5513,56.7167 39.2879,58.0001 35.5846,58.0001C32.2296,
+            58.0001 29.2229,56.9551 26.8945,55.195"
+        android:strokeWidth="3"
+        android:strokeColor="#ffffff"
+        android:strokeLineCap="round"/>
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
index 7cb44b3..4165830 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
@@ -16,8 +16,5 @@
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
         <solid android:color="?android:attr/colorBackgroundFloating"/>
-        <corners
-            android:topLeftRadius="?android:attr/dialogCornerRadius"
-            android:topRightRadius="?android:attr/dialogCornerRadius" />
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/layout/disabled_udfps_view.xml b/packages/SystemUI/res/layout/disabled_udfps_view.xml
index aab8661..13d3065 100644
--- a/packages/SystemUI/res/layout/disabled_udfps_view.xml
+++ b/packages/SystemUI/res/layout/disabled_udfps_view.xml
@@ -16,9 +16,7 @@
   -->
 <com.android.keyguard.DisabledUdfpsView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/disabled_udfps_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:background="@drawable/circle_white"
 />
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1d82518..bd92299 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -610,6 +610,21 @@
     <!-- Determines whether the shell features all run on another thread. -->
     <bool name="config_enableShellMainThread">false</bool>
 
+    <!-- Default udfps icon. Same path as ic_fingerprint.xml -->
+    <string name="config_udfpsIcon" translatable="false">
+        M25.5,16.3283C28.47,14.8433 31.9167,14 35.5834,14C39.2501,14 42.6968,14.8433 45.6668,16.3283
+        M20,28.6669C22.7683,24.3402 28.7084,21.3335 35.5834,21.3335C42.4585,21.3335 48.3985,
+        24.3402 51.1669,28.6669
+        M22.8607,47.0002C21.834,44.3235 21.834,41.5002 21.834,41.5002C21.834,
+        34.4051 27.7374,28.6667 35.5841,28.6667C43.4308,28.6667 49.3341,34.4051 49.3341,41.5002
+        M49.3344,41.5003V42.0319C49.3344,44.7636 47.1161,47.0003 44.3661,47.0003C41.9461,
+        47.0003 39.8744,45.2403 39.471,42.857L38.9577,
+        39.7769C38.591,37.5953 36.7027,36.0002 34.5027,
+        36.0002C26.5826,36.0002 29.846,49.1087 35.291,50.6487
+        M44.9713,54.6267C42.5513,56.7167 39.2879,58.0001 35.5846,58.0001C32.2296,
+        58.0001 29.2229,56.9551 26.8945,55.195
+    </string>
+
     <!-- package name of a built-in camera app to use to restrict implicit intent resolution
          when the double-press power gesture is used. Ignored if empty. -->
     <string translatable="false" name="config_cameraGesturePackage"></string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 91e0466..c1ac5e4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1091,7 +1091,7 @@
 
     <!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either
          direction that elements aer moved to prevent burn-in on AOD-->
-    <dimen name="udfps_burn_in_offset_x">8dp</dimen>
+    <dimen name="udfps_burn_in_offset_x">2dp</dimen>
     <dimen name="udfps_burn_in_offset_y">8dp</dimen>
 
     <dimen name="corner_size">8dp</dimen>
@@ -1407,6 +1407,9 @@
     <!-- rounded_slider_track_width / 2 -->
     <dimen name="rounded_slider_track_corner_radius">4dp</dimen>
 
+    <!-- inset for ic_lock_open within a DisabledUdfpsView -->
+    <dimen name="udfps_unlock_icon_inset">16dp</dimen>
+
     <!-- Location on the screen of the center of the physical power button. This is a reasonable
     default that should be overridden by device-specific overlays. -->
     <dimen name="physical_power_button_center_screen_location_y">620px</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
index 118f98d..ed465de0e 100644
--- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -18,27 +18,31 @@
 
 import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
 
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.hardware.biometrics.BiometricSourceType;
 import android.view.View;
 import android.view.ViewGroup;
 
 import androidx.annotation.NonNull;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /**
- * Controls when to show the DisabledUdfpsView to unlock the device on the lockscreen.
- * If the device is not authenticated, the bouncer will show.
+ * Controls when to show the DisabledUdfpsView affordance (unlock icon or circle) on lock screen.
  *
- * This tap target will only show when:
+ * This view only exists when:
  * - User has UDFPS enrolled
  * - UDFPS is currently unavailable see {@link KeyguardUpdateMonitor#shouldListenForUdfps}
  */
@@ -47,21 +51,26 @@
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final KeyguardViewController mKeyguardViewController;
     @NonNull private final StatusBarStateController mStatusBarStateController;
+    @NonNull private final KeyguardStateController mKeyguardStateController;
+    @NonNull private final Drawable mButton;
+    @NonNull private final Drawable mUnlockIcon;
 
     private boolean mIsDozing;
     private boolean mIsBouncerShowing;
     private boolean mIsKeyguardShowing;
     private boolean mRunningFPS;
-    private boolean mAuthenticated;
+    private boolean mCanDismissLockScreen;
 
     private boolean mShowButton;
+    private boolean mShowUnlockIcon;
 
     public DisabledUdfpsController(
             @NonNull DisabledUdfpsView view,
             @NonNull StatusBarStateController statusBarStateController,
             @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
             @NonNull AuthController authController,
-            @NonNull KeyguardViewController keyguardViewController
+            @NonNull KeyguardViewController keyguardViewController,
+            @NonNull KeyguardStateController keyguardStateController
     ) {
         super(view);
         mView.setOnClickListener(mOnClickListener);
@@ -70,25 +79,38 @@
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mKeyguardViewController = keyguardViewController;
+        mKeyguardStateController = keyguardStateController;
+
+        final Context context = view.getContext();
+        mButton = context.getResources().getDrawable(
+                com.android.systemui.R.drawable.circle_white, context.getTheme());
+        mUnlockIcon = new InsetDrawable(context.getResources().getDrawable(
+                com.android.internal.R.drawable.ic_lock_open, context.getTheme()),
+                context.getResources().getDimensionPixelSize(
+                        com.android.systemui.R.dimen.udfps_unlock_icon_inset));
     }
 
     @Override
     protected void onViewAttached() {
         mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
-        mIsKeyguardShowing = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+        mIsKeyguardShowing = mKeyguardStateController.isShowing();
         mIsDozing = mStatusBarStateController.isDozing();
         mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
-        mAuthenticated = false;
-        updateButtonVisibility();
+        mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+        mUnlockIcon.setTint(Utils.getColorAttrDefaultColor(mView.getContext(),
+                R.attr.wallpaperTextColorAccent));
+        updateVisibility();
 
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
         mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mKeyguardStateController.addCallback(mKeyguardStateCallback);
     }
 
     @Override
     protected void onViewDetached() {
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
+        mKeyguardStateController.removeCallback(mKeyguardStateCallback);
     }
 
     /**
@@ -100,30 +122,41 @@
         }
     }
 
-    private void updateButtonVisibility() {
-        mShowButton = !mAuthenticated && !mIsDozing && mIsKeyguardShowing
-                && !mIsBouncerShowing && !mRunningFPS;
+    private void updateVisibility() {
+        mShowButton = !mCanDismissLockScreen && !mRunningFPS && isLockScreen();
+        mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
+
         if (mShowButton) {
+            mView.setImageDrawable(mButton);
+            mView.setVisibility(View.VISIBLE);
+        } else if (mShowUnlockIcon) {
+            mView.setImageDrawable(mUnlockIcon);
             mView.setVisibility(View.VISIBLE);
         } else {
             mView.setVisibility(View.INVISIBLE);
         }
     }
 
+    private boolean isLockScreen() {
+        return mIsKeyguardShowing && !mIsDozing && !mIsBouncerShowing;
+    }
+
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("DisabledUdfpsController state:");
         pw.println("  mShowBouncerButton: " + mShowButton);
+        pw.println("  mShowUnlockIcon: " + mShowUnlockIcon);
         pw.println("  mIsDozing: " + mIsDozing);
         pw.println("  mIsKeyguardShowing: " + mIsKeyguardShowing);
         pw.println("  mIsBouncerShowing: " + mIsBouncerShowing);
         pw.println("  mRunningFPS: " + mRunningFPS);
-        pw.println("  mAuthenticated: " + mAuthenticated);
+        pw.println("  mCanDismissLockScreen: " + mCanDismissLockScreen);
     }
 
     private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
+            // if the device is locked, shows bouncer, else goes to launcher
             mKeyguardViewController.showBouncer(/* scrim */ true);
         }
     };
@@ -131,15 +164,9 @@
     private StatusBarStateController.StateListener mStatusBarStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
-                public void onStateChanged(int newState) {
-                    mIsKeyguardShowing = newState == StatusBarState.KEYGUARD;
-                    updateButtonVisibility();
-                }
-
-                @Override
                 public void onDozingChanged(boolean isDozing) {
                     mIsDozing = isDozing;
-                    updateButtonVisibility();
+                    updateVisibility();
                 }
             };
 
@@ -148,7 +175,7 @@
                 @Override
                 public void onKeyguardBouncerChanged(boolean bouncer) {
                     mIsBouncerShowing = bouncer;
-                    updateButtonVisibility();
+                    updateVisibility();
                 }
 
                 @Override
@@ -157,21 +184,29 @@
                     if (biometricSourceType == FINGERPRINT) {
                         mRunningFPS = running;
                     }
-                    mAuthenticated &= !mRunningFPS;
-                    updateButtonVisibility();
-                }
 
-                @Override
-                public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
-                    mAuthenticated = true;
-                    updateButtonVisibility();
-                }
-
-                @Override
-                public void onUserUnlocked() {
-                    mAuthenticated = true;
-                    updateButtonVisibility();
+                    updateVisibility();
                 }
             };
+
+    private final KeyguardStateController.Callback mKeyguardStateCallback =
+            new KeyguardStateController.Callback() {
+        @Override
+        public void onKeyguardShowingChanged() {
+            updateIsKeyguardShowing();
+            updateVisibility();
+        }
+
+        @Override
+        public void onUnlockedChanged() {
+            updateIsKeyguardShowing();
+            mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+            updateVisibility();
+        }
+
+        private void updateIsKeyguardShowing() {
+            mIsKeyguardShowing = mKeyguardStateController.isShowing()
+                    && !mKeyguardStateController.isKeyguardGoingAway();
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
index d8ab780..8ae753e 100644
--- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
@@ -22,14 +22,13 @@
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.util.AttributeSet;
 import android.view.Surface;
-import android.widget.Button;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 
 /**
- * A full screen view with an oval target where the UDFPS sensor is.
- * Controlled by {@link DisabledUdfpsController}.
+ * A view positioned in the area of the UDPFS sensor.
  */
-public class DisabledUdfpsView extends Button {
+public class DisabledUdfpsView extends ImageView {
     @NonNull private final RectF mSensorRect;
     @NonNull private final Context mContext;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 27a2ac3..864563e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -427,6 +427,7 @@
     public void onTrustChanged(boolean enabled, int userId, int flags) {
         Assert.isMainThread();
         mUserHasTrust.put(userId, enabled);
+        updateBiometricListeningState();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -627,6 +628,7 @@
         }
         // Don't send cancel if authentication succeeds
         mFingerprintCancelSignal = null;
+        updateBiometricListeningState();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -810,6 +812,7 @@
         }
         // Don't send cancel if authentication succeeds
         mFaceCancelSignal = null;
+        updateBiometricListeningState();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2109,6 +2112,7 @@
     boolean shouldListenForUdfps() {
         return shouldListenForFingerprint()
                 && !mBouncer
+                && !getUserCanSkipBouncer(getCurrentUser())
                 && mStrongAuthTracker.hasUserAuthenticatedSinceBoot();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 078ec9f..29db04b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -45,6 +45,7 @@
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.HbmTypes.HbmType;
 import com.android.systemui.dagger.SysUISingleton;
@@ -88,6 +89,7 @@
     @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
     @NonNull private final DumpManager mDumpManager;
     @NonNull private final AuthRippleController mAuthRippleController;
+    @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
     @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -307,7 +309,8 @@
             @NonNull StatusBar statusBar,
             @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             @NonNull DumpManager dumpManager,
-            @NonNull AuthRippleController authRippleController) {
+            @NonNull AuthRippleController authRippleController,
+            @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor) {
         mContext = context;
         mInflater = inflater;
         // The fingerprint manager is queried for UDFPS before this class is constructed, so the
@@ -320,6 +323,7 @@
         mKeyguardViewManager = statusBarKeyguardViewManager;
         mDumpManager = dumpManager;
         mAuthRippleController = authRippleController;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -486,6 +490,8 @@
                         mStatusBarStateController,
                         mStatusBar,
                         mKeyguardViewManager,
+                        mKeyguardUpdateMonitor,
+                        mFgExecutor,
                         mDumpManager
                 );
             case IUdfpsOverlayController.REASON_AUTH_BP:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
index 18f5416..55ed5aa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
@@ -18,9 +18,13 @@
 
 import android.content.Context;
 import android.graphics.ColorFilter;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.PathShape;
+import android.util.PathParser;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -32,15 +36,30 @@
  * sensor area.
  */
 public abstract class UdfpsDrawable extends Drawable {
-    @NonNull protected final Context mContext;
-    @NonNull protected final Drawable mFingerprintDrawable;
+    static final float DEFAULT_STROKE_WIDTH = 3f;
+
+    @NonNull final Context mContext;
+    @NonNull final ShapeDrawable mFingerprintDrawable;
+    private final Paint mPaint;
     private boolean mIlluminationShowing;
 
     int mAlpha = 255; // 0 - 255
     public UdfpsDrawable(@NonNull Context context) {
         mContext = context;
-        mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
+        final String fpPath = context.getResources().getString(R.string.config_udfpsIcon);
+        mFingerprintDrawable = new ShapeDrawable(
+                new PathShape(PathParser.createPathFromPathData(fpPath), 72, 72));
         mFingerprintDrawable.mutate();
+
+        mPaint = mFingerprintDrawable.getPaint();
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setStrokeCap(Paint.Cap.ROUND);
+        setStrokeWidth(DEFAULT_STROKE_WIDTH);
+    }
+
+    void setStrokeWidth(float strokeWidth) {
+        mPaint.setStrokeWidth(strokeWidth);
+        invalidateSelf();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
index 12c15a0..71ed3f8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -27,6 +28,7 @@
 
 import com.android.internal.graphics.ColorUtils;
 import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeReceiver;
 
@@ -37,6 +39,7 @@
 
     private static final String TAG = "UdfpsAnimationKeyguard";
     private final int mAmbientDisplayColor;
+    static final float DEFAULT_AOD_STROKE_WIDTH = 1f;
 
     @NonNull private final Context mContext;
     private int mLockScreenColor;
@@ -48,22 +51,31 @@
     private float mBurnInOffsetX;
     private float mBurnInOffsetY;
 
+    private final ValueAnimator mHintAnimator = ValueAnimator.ofFloat(
+            UdfpsKeyguardDrawable.DEFAULT_STROKE_WIDTH,
+            .5f,
+            UdfpsKeyguardDrawable.DEFAULT_STROKE_WIDTH);
+
     UdfpsKeyguardDrawable(@NonNull Context context) {
         super(context);
         mContext = context;
 
-        // TODO: move burn-in to view
         mMaxBurnInOffsetX = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
         mMaxBurnInOffsetY = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
 
+        mHintAnimator.setDuration(2000);
+        mHintAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mHintAnimator.addUpdateListener(anim -> setStrokeWidth((float) anim.getAnimatedValue()));
+
         mLockScreenColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
         mAmbientDisplayColor = Color.WHITE;
-        updateAodPositionAndColor();
+
+        updateIcon();
     }
 
-    private void updateAodPositionAndColor() {
+    private void updateIcon() {
         mBurnInOffsetX = MathUtils.lerp(0f,
                 getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
                         - mMaxBurnInOffsetX,
@@ -75,12 +87,14 @@
 
         mFingerprintDrawable.setTint(ColorUtils.blendARGB(mLockScreenColor,
                 mAmbientDisplayColor, mInterpolatedDarkAmount));
+        setStrokeWidth(MathUtils.lerp(DEFAULT_STROKE_WIDTH, DEFAULT_AOD_STROKE_WIDTH,
+                mInterpolatedDarkAmount));
         invalidateSelf();
     }
 
     @Override
     public void dozeTimeTick() {
-        updateAodPositionAndColor();
+        updateIcon();
     }
 
     @Override
@@ -88,17 +102,25 @@
         if (isIlluminationShowing()) {
             return;
         }
+        canvas.save();
+        canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
         mFingerprintDrawable.draw(canvas);
+        canvas.restore();
+    }
+
+    void animateHint() {
+        mHintAnimator.start();
     }
 
     void onDozeAmountChanged(float linear, float eased) {
+        mHintAnimator.cancel();
         mInterpolatedDarkAmount = eased;
-        updateAodPositionAndColor();
+        updateIcon();
     }
 
     void setLockScreenColor(int color) {
         if (mLockScreenColor == color) return;
         mLockScreenColor = color;
-        updateAodPositionAndColor();
+        updateIcon();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index e274843..4590182 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -85,7 +85,6 @@
 
     @Override
     public boolean dozeTimeTick() {
-        // TODO: burnin
         mFingerprintDrawable.dozeTimeTick();
         return true;
     }
@@ -100,13 +99,16 @@
 
     void onDozeAmountChanged(float linear, float eased) {
         mFingerprintDrawable.onDozeAmountChanged(linear, eased);
-        invalidate();
+    }
+
+    void animateHint() {
+        mFingerprintDrawable.animateHint();
     }
 
     /**
      * Animates in the bg protection circle behind the fp icon to highlight the icon.
      */
-    void animateHighlightFp() {
+    void animateUdfpsBouncer() {
         if (mBgProtection.getVisibility() == View.VISIBLE && mBgProtection.getAlpha() == 1f) {
             // already fully highlighted, don't re-animate
             return;
@@ -154,7 +156,7 @@
     /**
      * Animates out the bg protection circle behind the fp icon to unhighlight the icon.
      */
-    void animateUnhighlightFp(@Nullable Runnable onEndAnimation) {
+    void animateAwayUdfpsBouncer(@Nullable Runnable onEndAnimation) {
         if (mBgProtection.getVisibility() == View.GONE) {
             // already hidden
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 1f652db..9d846fa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -17,32 +17,53 @@
 package com.android.systemui.biometrics;
 
 import android.annotation.NonNull;
+import android.hardware.biometrics.BiometricSourceType;
 
+import androidx.annotation.Nullable;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /**
  * Class that coordinates non-HBM animations during keyguard authentication.
+ *
+ * Highlights the udfps icon when:
+ * - Face authentication has failed
+ * - Face authentication has been run for > 2 seconds
  */
 public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
-    @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
+    private static final long AFTER_FACE_AUTH_HINT_DELAY = 2000;
 
-    private boolean mForceShow;
+    @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
+    @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @NonNull private final DelayableExecutor mExecutor;
+
+    @Nullable private Runnable mCancelRunnable;
+    private boolean mShowBouncer;
     private boolean mQsExpanded;
+    private boolean mFaceDetectRunning;
+    private boolean mHintShown;
 
     protected UdfpsKeyguardViewController(
             @NonNull UdfpsKeyguardView view,
             @NonNull StatusBarStateController statusBarStateController,
             @NonNull StatusBar statusBar,
             @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
+            @NonNull DelayableExecutor mainDelayableExecutor,
             @NonNull DumpManager dumpManager) {
         super(view, statusBarStateController, statusBar, dumpManager);
         mKeyguardViewManager = statusBarKeyguardViewManager;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mExecutor = mainDelayableExecutor;
     }
 
     @Override
@@ -53,6 +74,9 @@
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
+        mHintShown = false;
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+        updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning());
 
         final float dozeAmount = mStatusBarStateController.getDozeAmount();
         mStatusBarStateController.addCallback(mStateListener);
@@ -64,31 +88,40 @@
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+        mFaceDetectRunning = false;
+
         mStatusBarStateController.removeCallback(mStateListener);
-        mAlternateAuthInterceptor.resetForceShow();
+        mAlternateAuthInterceptor.hideAlternateAuthBouncer();
         mKeyguardViewManager.setAlternateAuthInterceptor(null);
+
+        if (mCancelRunnable != null) {
+            mCancelRunnable.run();
+            mCancelRunnable = null;
+        }
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dump(fd, pw, args);
-        pw.println("mForceShow=" + mForceShow);
+        pw.println("mShowBouncer=" + mShowBouncer);
+        pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
     }
 
     /**
-     * Overrides non-force show logic in shouldPauseAuth to still auth.
+     * Overrides non-bouncer show logic in shouldPauseAuth to still auth.
      */
-    private void forceShow(boolean forceShow) {
-        if (mForceShow == forceShow) {
+    private void showBouncer(boolean forceShow) {
+        if (mShowBouncer == forceShow) {
             return;
         }
 
-        mForceShow = forceShow;
+        mShowBouncer = forceShow;
         updatePauseAuth();
-        if (mForceShow) {
-            mView.animateHighlightFp();
+        if (mShowBouncer) {
+            mView.animateUdfpsBouncer();
         } else {
-            mView.animateUnhighlightFp(() -> mKeyguardViewManager.cancelPostAuthActions());
+            mView.animateAwayUdfpsBouncer(() -> mKeyguardViewManager.cancelPostAuthActions());
         }
     }
 
@@ -98,7 +131,7 @@
      * is expanded, so this can be overridden with the forceShow method.
      */
     public boolean shouldPauseAuth() {
-        if (mForceShow) {
+        if (mShowBouncer) {
             return false;
         }
 
@@ -109,12 +142,42 @@
         return super.shouldPauseAuth();
     }
 
+    private void cancelDelayedHint() {
+        if (mCancelRunnable != null) {
+            mCancelRunnable.run();
+            mCancelRunnable = null;
+        }
+    }
+
+    private void updateFaceDetectRunning(boolean running) {
+        if (mFaceDetectRunning == running) {
+            return;
+        }
+
+        // show udfps hint a few seconds after face auth started running
+        if (!mFaceDetectRunning && running && !mHintShown && mCancelRunnable == null) {
+            // Face detect started running, show udfps hint after a delay
+            mCancelRunnable = mExecutor.executeDelayed(() -> showHint(false),
+                    AFTER_FACE_AUTH_HINT_DELAY);
+        }
+
+        mFaceDetectRunning = running;
+    }
+
+    private void showHint(boolean forceShow) {
+        cancelDelayedHint();
+        if (!mHintShown || forceShow) {
+            mHintShown = true;
+            mView.animateHint();
+        }
+    }
+
     private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
         @Override
         public void onDozeAmountChanged(float linear, float eased) {
             mView.onDozeAmountChanged(linear, eased);
-            if (linear != 0) forceShow(false);
+            if (linear != 0) showBouncer(false);
         }
 
         @Override
@@ -123,31 +186,56 @@
         }
     };
 
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+                public void onBiometricRunningStateChanged(boolean running,
+                        BiometricSourceType biometricSourceType) {
+                    if (biometricSourceType == BiometricSourceType.FACE) {
+                        updateFaceDetectRunning(running);
+                    }
+                }
+
+                public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
+                    if (biometricSourceType == BiometricSourceType.FACE) {
+                        // show udfps hint when face auth fails
+                        showHint(true);
+                    }
+                }
+
+                public void onBiometricAuthenticated(int userId,
+                        BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
+                    if (biometricSourceType == BiometricSourceType.FACE) {
+                        // cancel delayed hint if face auth succeeded
+                        cancelDelayedHint();
+                    }
+                }
+            };
+
     private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor =
             new StatusBarKeyguardViewManager.AlternateAuthInterceptor() {
                 @Override
-                public boolean showAlternativeAuthMethod() {
-                    if (mForceShow) {
+                public boolean showAlternateAuthBouncer() {
+                    if (mShowBouncer) {
                         return false;
                     }
 
-                    forceShow(true);
+                    showBouncer(true);
                     return true;
                 }
 
                 @Override
-                public boolean resetForceShow() {
-                    if (!mForceShow) {
+                public boolean hideAlternateAuthBouncer() {
+                    if (!mShowBouncer) {
                         return false;
                     }
 
-                    forceShow(false);
+                    showBouncer(false);
                     return true;
                 }
 
                 @Override
-                public boolean isShowingAlternateAuth() {
-                    return mForceShow;
+                public boolean isShowingAlternateAuthBouncer() {
+                    return mShowBouncer;
                 }
 
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 1c5715c..fd80d50 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -59,6 +59,7 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.view.IWindowManager;
 import android.view.ViewConfiguration;
@@ -328,6 +329,12 @@
 
     @Provides
     @Singleton
+    static SubscriptionManager provideSubcriptionManager(Context context) {
+        return context.getSystemService(SubscriptionManager.class);
+    }
+
+    @Provides
+    @Singleton
     @Nullable
     static TelecomManager provideTelecomManager(Context context) {
         return context.getSystemService(TelecomManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 0d73a5a..5b986b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -66,7 +66,7 @@
         return getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
                 && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 "camera_toggle_enabled",
-                false));
+                true));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index b8d8792..42bd77b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -67,7 +67,7 @@
                 .hasSystemFeature(FEATURE_MICROPHONE_TOGGLE)
                 && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 "mic_toggle_enabled",
-                false));
+                true));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index a38cf61..555df5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3543,7 +3543,8 @@
                     mStatusBarStateController,
                     mUpdateMonitor,
                     mAuthController,
-                    mStatusBarKeyguardViewManager);
+                    mStatusBarKeyguardViewManager,
+                    mKeyguardStateController);
             mDisabledUdfpsController.init();
         } else if (mDisabledUdfpsController != null && !udfpsEnrolled) {
             mDisabledUdfpsController.destroy();
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 0b6bbcd..ef2444e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -479,7 +479,7 @@
             if (mAlternateAuthInterceptor != null) {
                 mAfterKeyguardGoneAction = r;
                 mKeyguardGoneCancelAction = cancelAction;
-                if (mAlternateAuthInterceptor.showAlternativeAuthMethod()) {
+                if (mAlternateAuthInterceptor.showAlternateAuthBouncer()) {
                     mStatusBar.updateScrimController();
                 }
                 return;
@@ -529,7 +529,8 @@
      * Stop showing any alternate auth methods
      */
     public void resetAlternateAuth() {
-        if (mAlternateAuthInterceptor != null && mAlternateAuthInterceptor.resetForceShow()) {
+        if (mAlternateAuthInterceptor != null
+                && mAlternateAuthInterceptor.hideAlternateAuthBouncer()) {
             mStatusBar.updateScrimController();
         }
     }
@@ -1141,12 +1142,12 @@
 
     public boolean isShowingAlternateAuth() {
         return mAlternateAuthInterceptor != null
-                && mAlternateAuthInterceptor.isShowingAlternateAuth();
+                && mAlternateAuthInterceptor.isShowingAlternateAuthBouncer();
     }
 
     public boolean isShowingAlternateAuthOrAnimating() {
         return mAlternateAuthInterceptor != null
-                && (mAlternateAuthInterceptor.isShowingAlternateAuth()
+                && (mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()
                 || mAlternateAuthInterceptor.isAnimating());
     }
 
@@ -1174,24 +1175,25 @@
 
     /**
      * Delegate used to send show/reset events to an alternate authentication method instead of the
-     * bouncer.
+     * regular pin/pattern/password bouncer.
      */
     public interface AlternateAuthInterceptor {
         /**
-         * @return whether alternative auth method was newly shown
+         * Show alternate authentication bouncer.
+         * @return whether alternate auth method was newly shown
          */
-        boolean showAlternativeAuthMethod();
+        boolean showAlternateAuthBouncer();
 
         /**
-         * reset the state to the default (only keyguard showing, no auth methods showing)
-         * @return whether alternative auth method was newly hidden
+         * Hide alternate authentication bouncer
+         * @return whether the alternate auth method was newly hidden
          */
-        boolean resetForceShow();
+        boolean hideAlternateAuthBouncer();
 
         /**
-         * @return true if alternative auth method is showing
+         * @return true if the alternate auth bouncer is showing
          */
-        boolean isShowingAlternateAuth();
+        boolean isShowingAlternateAuthBouncer();
 
         /**
          * print information for the alternate auth interceptor registered
@@ -1199,12 +1201,12 @@
         void dump(PrintWriter pw);
 
         /**
-         * @return true if the new auth method is currently animating in or out.
+         * @return true if the new auth method bouncer is currently animating in or out.
          */
         boolean isAnimating();
 
         /**
-         * Set whether qs is currently expanded
+         * Set whether qs is currently expanded.
          */
         void setQsExpanded(boolean expanded);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index b96cb5e..7ac6d63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -21,6 +21,7 @@
 import android.telephony.SubscriptionInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
@@ -32,6 +33,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.inject.Inject;
+
 
 /**
  * Implements network listeners and forwards the calls along onto other listeners but on
@@ -60,12 +63,9 @@
     private int mHistoryIndex;
     private String mLastCallback;
 
-    public CallbackHandler() {
-        super(Looper.getMainLooper());
-    }
-
+    @Inject
     @VisibleForTesting
-    CallbackHandler(Looper looper) {
+    CallbackHandler(@Main Looper looper) {
         super(looper);
     }
 
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 cfaeb0e..f683603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -85,6 +85,7 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -171,6 +172,8 @@
     private NetworkCapabilities mLastDefaultNetworkCapabilities;
     // Handler that all broadcasts are received on.
     private final Handler mReceiverHandler;
+    private final Looper mBgLooper;
+    private final Executor mBgExecutor;
     // Handler that all callbacks are made on.
     private final CallbackHandler mCallbackHandler;
 
@@ -198,6 +201,9 @@
     public NetworkControllerImpl(
             Context context,
             @Background Looper bgLooper,
+            @Background Executor bgExecutor,
+            SubscriptionManager subscriptionManager,
+            CallbackHandler callbackHandler,
             DeviceProvisionedController deviceProvisionedController,
             BroadcastDispatcher broadcastDispatcher,
             ConnectivityManager connectivityManager,
@@ -212,8 +218,11 @@
                 telephonyListenerManager,
                 wifiManager,
                 networkScoreManager,
-                SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
-                new CallbackHandler(),
+                subscriptionManager,
+                Config.readConfig(context),
+                bgLooper,
+                bgExecutor,
+                callbackHandler,
                 accessPointController,
                 new DataUsageController(context),
                 new SubscriptionDefaults(),
@@ -230,6 +239,7 @@
             WifiManager wifiManager,
             NetworkScoreManager networkScoreManager,
             SubscriptionManager subManager, Config config, Looper bgLooper,
+            Executor bgExecutor,
             CallbackHandler callbackHandler,
             AccessPointControllerImpl accessPointController,
             DataUsageController dataUsageController,
@@ -241,6 +251,8 @@
         mTelephonyListenerManager = telephonyListenerManager;
         mConfig = config;
         mReceiverHandler = new Handler(bgLooper);
+        mBgLooper = bgLooper;
+        mBgExecutor = bgExecutor;
         mCallbackHandler = callbackHandler;
         mDataSaverController = new DataSaverControllerImpl(context);
         mBroadcastDispatcher = broadcastDispatcher;
@@ -377,21 +389,23 @@
         // TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks
         // exclusively for status bar icons.
         mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
-        // Register the listener on our bg looper
+        // Run the listener on our bg looper
         mPhoneStateListener = subId -> {
-            // For data switching from A to B, we assume B is validated for up to 2 seconds iff:
-            // 1) A and B are in the same subscription group e.g. CBRS data switch. And
-            // 2) A was validated before the switch.
-            // This is to provide smooth transition for UI without showing cross during data
-            // switch.
-            if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
-                if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
-                mForceCellularValidated = true;
-                mReceiverHandler.removeCallbacks(mClearForceValidated);
-                mReceiverHandler.postDelayed(mClearForceValidated, 2000);
-            }
-            mActiveMobileDataSubscription = subId;
-            doUpdateMobileControllers();
+            mBgExecutor.execute(() -> {
+                // For data switching from A to B, we assume B is validated for up to 2 seconds if:
+                // 1) A and B are in the same subscription group e.g. CBRS data switch. And
+                // 2) A was validated before the switch.
+                // This is to provide smooth transition for UI without showing cross during data
+                // switch.
+                if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
+                    if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
+                    mForceCellularValidated = true;
+                    mReceiverHandler.removeCallbacks(mClearForceValidated);
+                    mReceiverHandler.postDelayed(mClearForceValidated, 2000);
+                }
+                mActiveMobileDataSubscription = subId;
+                doUpdateMobileControllers();
+            });
         };
 
         mDemoModeController.addCallback(this);
@@ -428,7 +442,7 @@
             mobileSignalController.registerListener();
         }
         if (mSubscriptionListener == null) {
-            mSubscriptionListener = new SubListener();
+            mSubscriptionListener = new SubListener(mBgLooper);
         }
         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
         mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
@@ -1336,6 +1350,10 @@
     }
 
     private class SubListener extends OnSubscriptionsChangedListener {
+        SubListener(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void onSubscriptionsChanged() {
             updateMobileControllers();
@@ -1346,10 +1364,5 @@
      * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
      * get created will also run on the BG Looper.
      */
-    private final Runnable mRegisterListeners = new Runnable() {
-        @Override
-        public void run() {
-            registerListeners();
-        }
-    };
+    private final Runnable mRegisterListeners = () -> registerListeners();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java
index 95216c5..728907f 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/telephony/TelephonyCallback.java
@@ -54,9 +54,11 @@
 
     @Override
     public void onActiveDataSubscriptionIdChanged(int subId) {
-        mActiveDataSubscriptionIdListeners.forEach(listener -> {
-            listener.onActiveDataSubscriptionIdChanged(subId);
-        });
+        List<ActiveDataSubscriptionIdListener> listeners;
+        synchronized (mActiveDataSubscriptionIdListeners) {
+            listeners = new ArrayList<>(mActiveDataSubscriptionIdListeners);
+        }
+        listeners.forEach(listener -> listener.onActiveDataSubscriptionIdChanged(subId));
     }
 
     void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
@@ -69,9 +71,11 @@
 
     @Override
     public void onCallStateChanged(int state) {
-        mCallStateListeners.forEach(listener -> {
-            listener.onCallStateChanged(state);
-        });
+        List<CallStateListener> listeners;
+        synchronized (mCallStateListeners) {
+            listeners = new ArrayList<>(mCallStateListeners);
+        }
+        listeners.forEach(listener -> listener.onCallStateChanged(state));
     }
 
     void addCallStateListener(CallStateListener listener) {
@@ -84,9 +88,11 @@
 
     @Override
     public void onServiceStateChanged(@NonNull ServiceState serviceState) {
-        mServiceStateListeners.forEach(listener -> {
-            listener.onServiceStateChanged(serviceState);
-        });
+        List<ServiceStateListener> listeners;
+        synchronized (mServiceStateListeners) {
+            listeners = new ArrayList<>(mServiceStateListeners);
+        }
+        listeners.forEach(listener -> listener.onServiceStateChanged(serviceState));
     }
 
     void addServiceStateListener(ServiceStateListener listener) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 44c3b26..cfcb7bb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -881,6 +881,36 @@
     }
 
     @Test
+    public void testShouldNotListenForUdfps_whenTrustEnabled() {
+        // GIVEN a "we should listen for udfps" state
+        setKeyguardBouncerVisibility(false /* isVisible */);
+        mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+        when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+        // WHEN trust is enabled (ie: via smartlock)
+        mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
+                KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
+
+        // THEN we shouldn't listen for udfps
+        assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+    }
+
+    @Test
+    public void testShouldNotListenForUdfps_whenFaceAuthenticated() {
+        // GIVEN a "we should listen for udfps" state
+        setKeyguardBouncerVisibility(false /* isVisible */);
+        mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+        when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+        // WHEN face authenticated
+        mKeyguardUpdateMonitor.onFaceAuthenticated(
+                KeyguardUpdateMonitor.getCurrentUser(), false);
+
+        // THEN we shouldn't listen for udfps
+        assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+    }
+
+    @Test
     public void testRequireUnlockForNfc_Broadcast() {
         KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
         mKeyguardUpdateMonitor.registerCallback(callback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index d3694dd..beca965 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -43,6 +43,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
@@ -100,6 +101,8 @@
     @Mock
     private AuthRippleController mAuthRippleController;
     @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock
     private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
 
     private FakeExecutor mFgExecutor;
@@ -151,7 +154,8 @@
                 mStatusBar,
                 mStatusBarKeyguardViewManager,
                 mDumpManager,
-                mAuthRippleController);
+                mAuthRippleController,
+                mKeyguardUpdateMonitor);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 4410992..879cdbfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -27,12 +27,14 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -59,6 +61,10 @@
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock
     private DumpManager mDumpManager;
+    @Mock
+    private DelayableExecutor mExecutor;
+    @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private UdfpsKeyguardViewController mController;
 
@@ -82,6 +88,8 @@
                 mStatusBarStateController,
                 mStatusBar,
                 mStatusBarKeyguardViewManager,
+                mKeyguardUpdateMonitor,
+                mExecutor,
                 mDumpManager);
     }
 
@@ -168,13 +176,13 @@
         sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
         assertTrue(mController.shouldPauseAuth());
 
-        mAltAuthInterceptor.showAlternativeAuthMethod(); // force show
+        mAltAuthInterceptor.showAlternateAuthBouncer(); // force show
         assertFalse(mController.shouldPauseAuth());
-        assertTrue(mAltAuthInterceptor.isShowingAlternateAuth());
+        assertTrue(mAltAuthInterceptor.isShowingAlternateAuthBouncer());
 
-        mAltAuthInterceptor.resetForceShow(); // stop force show
+        mAltAuthInterceptor.hideAlternateAuthBouncer(); // stop force show
         assertTrue(mController.shouldPauseAuth());
-        assertFalse(mAltAuthInterceptor.isShowingAlternateAuth());
+        assertFalse(mAltAuthInterceptor.isShowingAlternateAuthBouncer());
     }
 
     @Test
@@ -184,13 +192,13 @@
         captureStatusBarStateListeners();
         captureAltAuthInterceptor();
 
-        mAltAuthInterceptor.showAlternativeAuthMethod(); // alt auth force show
+        mAltAuthInterceptor.showAlternateAuthBouncer(); // alt auth force show
 
         // WHEN view is detached
         mController.onViewDetached();
 
         // THEN alt auth state reports not showing
-        assertFalse(mAltAuthInterceptor.isShowingAlternateAuth());
+        assertFalse(mAltAuthInterceptor.isShowingAlternateAuthBouncer());
     }
 
     private void sendStatusBarStateChanged(int statusBarState) {
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 ef33172..566c717 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
@@ -77,6 +77,8 @@
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.telephony.TelephonyListenerManager;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.After;
 import org.junit.Before;
@@ -123,6 +125,7 @@
     protected DeviceProvisionedListener mUserCallback;
     protected Instrumentation mInstrumentation;
     protected DemoModeController mDemoModeController;
+    protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
 
     protected int mSubId;
 
@@ -222,6 +225,7 @@
                 mMockSm,
                 mConfig,
                 TestableLooper.get(this).getLooper(),
+                mFakeExecutor,
                 mCallbackHandler,
                 mock(AccessPointControllerImpl.class),
                 mock(DataUsageController.class),
@@ -291,7 +295,8 @@
         NetworkControllerImpl networkControllerNoMobile =
                 new NetworkControllerImpl(mContext, mMockCm, mMockTm, mTelephonyListenerManager,
                         mMockWm, mMockNsm, mMockSm,
-                        mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
+                        mConfig, TestableLooper.get(this).getLooper(), mFakeExecutor,
+                        mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults,
                         mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);
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 f4ad819..6219faf 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
@@ -108,7 +108,7 @@
         mConfig.show4gForLte = true;
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
                 mTelephonyListenerManager, mMockWm,
-                mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
+                mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class),
                 mock(DataUsageController.class), mMockSubDefaults,
                 mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);
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 3c5cbb6..8d3e403 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
@@ -63,7 +63,7 @@
         // Create a new NetworkController as this is currently handled in constructor.
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
                 mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
-                Looper.getMainLooper(), mCallbackHandler,
+                Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController);
@@ -83,7 +83,7 @@
 
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
                 mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
-                Looper.getMainLooper(), mCallbackHandler,
+                Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController);
@@ -151,7 +151,7 @@
         // Create a new NetworkController as this is currently handled in constructor.
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
                 mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
-                Looper.getMainLooper(), mCallbackHandler,
+                Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
                 mDemoModeController);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 483f67a..82538b6 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -637,6 +637,8 @@
                     return association;
                 }
             }));
+
+            restartBleScan();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index d66d82d1..ed579f2 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -40,7 +40,6 @@
 import android.net.vcn.IVcnStatusCallback;
 import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
-import android.net.vcn.VcnManager;
 import android.net.vcn.VcnManager.VcnErrorCode;
 import android.net.vcn.VcnManager.VcnStatusCode;
 import android.net.vcn.VcnUnderlyingNetworkPolicy;
@@ -531,11 +530,12 @@
 
         if (mVcns.containsKey(subscriptionGroup)) {
             final Vcn vcn = mVcns.get(subscriptionGroup);
-            final boolean isActive = vcn.isActive();
+            final int status = vcn.getStatus();
             vcn.updateConfig(config);
 
+            // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
             // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
-            if (!isActive) {
+            if (status == VCN_STATUS_CODE_SAFE_MODE) {
                 // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
                 notifyAllPermissionedStatusCallbacksLocked(
                         subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
@@ -768,7 +768,7 @@
             synchronized (mLock) {
                 final Vcn vcn = mVcns.get(subGrp);
                 if (vcn != null) {
-                    if (vcn.isActive()) {
+                    if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) {
                         isVcnManagedNetwork = true;
                     }
 
@@ -879,20 +879,23 @@
                 // now that callback is registered, send it the VCN's current status
                 final VcnConfig vcnConfig = mConfigs.get(subGroup);
                 final Vcn vcn = mVcns.get(subGroup);
-                final int vcnStatus;
+                final int vcnStatus =
+                        vcn == null ? VCN_STATUS_CODE_NOT_CONFIGURED : vcn.getStatus();
+                final int resultStatus;
                 if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
+                    resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
                 } else if (vcn == null) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE;
-                } else if (vcn.isActive()) {
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE;
+                    resultStatus = VCN_STATUS_CODE_INACTIVE;
+                } else if (vcnStatus == VCN_STATUS_CODE_ACTIVE
+                        || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) {
+                    resultStatus = vcnStatus;
                 } else {
-                    // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
-                    vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+                    Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus);
+                    resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
                 }
 
                 try {
-                    cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+                    cbInfo.mCallback.onVcnStatusChanged(resultStatus);
                 } catch (RemoteException e) {
                     Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
                 }
@@ -930,7 +933,7 @@
 
         /** Called by a Vcn to signal that an error occurred. */
         void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
@@ -959,7 +962,7 @@
 
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
@@ -975,7 +978,7 @@
                         Binder.withCleanCallingIdentity(
                                 () ->
                                         cbInfo.mCallback.onGatewayConnectionError(
-                                                networkCapabilities,
+                                                gatewayConnectionName,
                                                 errorCode,
                                                 exceptionClass,
                                                 exceptionMessage));
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index c360190..5c2fd26 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -279,7 +279,7 @@
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mHandler = new MessageHandler(injector.getMessageHandlerLooper());
         mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
-        mAuthenticatorCache.setListener(this, mHandler);
+        mAuthenticatorCache.setListener(this, null /* Handler */);
 
         sThis.set(this);
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d513ba4..c1ab6cc 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -191,6 +191,15 @@
     // calling startForeground() before we ANR + stop it.
     static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
 
+    // Foreground service types that always get immediate notification display,
+    // expressed in the same bitmask format that ServiceRecord.foregroundServiceType
+    // uses.
+    static final int FGS_IMMEDIATE_DISPLAY_MASK =
+            ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
+                    | ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
+                    | ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
+                    | ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
+
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -2020,15 +2029,12 @@
                 }
                 // or is this an type of FGS that always shows immediately?
                 if (!showNow) {
-                    switch (r.foregroundServiceType) {
-                        case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK:
-                        case ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL:
-                        case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION:
-                            if (DEBUG_FOREGROUND_SERVICE) {
-                                Slog.d(TAG_SERVICE, "FGS " + r
-                                        + " type gets immediate display");
-                            }
-                            showNow = true;
+                    if ((r.foregroundServiceType & FGS_IMMEDIATE_DISPLAY_MASK) != 0) {
+                        if (DEBUG_FOREGROUND_SERVICE) {
+                            Slog.d(TAG_SERVICE, "FGS " + r
+                                    + " type gets immediate display");
+                        }
+                        showNow = true;
                     }
                 }
             } else {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 57de708..b103def 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -34,7 +34,7 @@
 import android.app.GameManager;
 import android.app.GameManager.GameMode;
 import android.app.IGameManagerService;
-import android.compat.Compatibility;
+import android.app.compat.PackageOverride;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -61,13 +61,12 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.CompatibilityOverrideConfig;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 
 import java.io.FileDescriptor;
-import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -87,6 +86,10 @@
     static final int REMOVE_SETTINGS = 2;
     static final int POPULATE_GAME_MODE_SETTINGS = 3;
     static final int WRITE_SETTINGS_DELAY = 10 * 1000;  // 10 seconds
+    static final PackageOverride COMPAT_ENABLED = new PackageOverride.Builder().setEnabled(true)
+            .build();
+    static final PackageOverride COMPAT_DISABLED = new PackageOverride.Builder().setEnabled(false)
+            .build();
 
     private final Context mContext;
     private final Object mLock = new Object();
@@ -578,17 +581,14 @@
     private void disableCompatScale(String packageName) {
         final long uid = Binder.clearCallingIdentity();
         try {
-            final HashSet<Long> disabledSet = new HashSet<>();
-            disabledSet.add(DOWNSCALED);
-            final CompatibilityChangeConfig changeConfig = new CompatibilityChangeConfig(
-                    new Compatibility.ChangeConfig(new HashSet<>(), disabledSet));
-            // TODO: switch to new API provided by aosp/1599153 once merged
+            final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();
+            overrides.put(DOWNSCALED, COMPAT_DISABLED);
+            final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig(
+                    overrides);
             try {
-                mPlatformCompat.setOverridesForTest(changeConfig, packageName);
-            } catch (SecurityException e) {
-                Slog.e(TAG, "Missing compat override permission", e);
+                mPlatformCompat.setOverridesOnReleaseBuilds(changeConfig, packageName);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to call IPlatformCompat#setOverridesForTest", e);
+                Slog.e(TAG, "Failed to call IPlatformCompat#setOverridesOnReleaseBuilds", e);
             }
         } finally {
             Binder.restoreCallingIdentity(uid);
@@ -598,25 +598,20 @@
     private void enableCompatScale(String packageName, long scaleId) {
         final long uid = Binder.clearCallingIdentity();
         try {
-            final HashSet<Long> disabledSet = new HashSet<>();
-            final HashSet<Long> enabledSet = new HashSet<>();
-            disabledSet.add(DOWNSCALE_50);
-            disabledSet.add(DOWNSCALE_60);
-            disabledSet.add(DOWNSCALE_70);
-            disabledSet.add(DOWNSCALE_80);
-            disabledSet.add(DOWNSCALE_90);
-            disabledSet.remove(scaleId);
-            enabledSet.add(DOWNSCALED);
-            enabledSet.add(scaleId);
-            final CompatibilityChangeConfig changeConfig = new CompatibilityChangeConfig(
-                    new Compatibility.ChangeConfig(enabledSet, disabledSet));
-            // TODO: switch to new API provided by aosp/1599153 once merged
+            final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();
+            overrides.put(DOWNSCALED, COMPAT_ENABLED);
+            overrides.put(DOWNSCALE_50, COMPAT_DISABLED);
+            overrides.put(DOWNSCALE_60, COMPAT_DISABLED);
+            overrides.put(DOWNSCALE_70, COMPAT_DISABLED);
+            overrides.put(DOWNSCALE_80, COMPAT_DISABLED);
+            overrides.put(DOWNSCALE_90, COMPAT_DISABLED);
+            overrides.put(scaleId, COMPAT_ENABLED);
+            final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig(
+                    overrides);
             try {
-                mPlatformCompat.setOverridesForTest(changeConfig, packageName);
-            } catch (SecurityException e) {
-                Slog.e(TAG, "Missing compat override permission", e);
+                mPlatformCompat.setOverridesOnReleaseBuilds(changeConfig, packageName);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to call IPlatformCompat#setOverridesForTest", e);
+                Slog.e(TAG, "Failed to call IPlatformCompat#setOverridesOnReleaseBuilds", e);
             }
         } finally {
             Binder.restoreCallingIdentity(uid);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 16a9626..2de2fdf 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -128,6 +128,7 @@
 import android.os.UserManager;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.os.VibratorManager;
 import android.provider.Settings;
 import android.provider.Settings.System;
 import android.service.notification.ZenModeConfig;
@@ -1092,6 +1093,33 @@
         }
     }
 
+    private void updateVibratorInfos() {
+        VibratorManager vibratorManager = mContext.getSystemService(VibratorManager.class);
+        if (vibratorManager == null) {
+            Slog.e(TAG, "Vibrator manager is not found");
+            return;
+        }
+        int[] vibratorIds = vibratorManager.getVibratorIds();
+        if (vibratorIds.length == 0) {
+            Slog.d(TAG, "No vibrator found");
+            return;
+        }
+        List<Vibrator> vibrators = new ArrayList<>(vibratorIds.length);
+        for (int id : vibratorIds) {
+            Vibrator vibrator = vibratorManager.getVibrator(id);
+            if (vibrator != null) {
+                vibrators.add(vibrator);
+            } else {
+                Slog.w(TAG, "Vibrator(" + id + ") is not found");
+            }
+        }
+        if (vibrators.isEmpty()) {
+            Slog.w(TAG, "Cannot find any available vibrator");
+            return;
+        }
+        AudioSystem.setVibratorInfos(vibrators);
+    }
+
     public void onSystemReady() {
         mSystemReady = true;
         scheduleLoadSoundEffects();
@@ -1149,6 +1177,8 @@
         setMicMuteFromSwitchInput();
 
         initMinStreamVolumeWithoutModifyAudioSettings();
+
+        updateVibratorInfos();
     }
 
     RoleObserver mRoleObserver;
@@ -1231,7 +1261,7 @@
         // Restore call state
         synchronized (mDeviceBroker.mSetModeLock) {
             onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
-                    mContext.getPackageName());
+                    mContext.getPackageName(), true /*force*/);
         }
         final int forSys;
         synchronized (mSettingsLock) {
@@ -1341,6 +1371,9 @@
 
         setMicrophoneMuteNoCallerCheck(getCurrentUserId()); // will also update the mic mute cache
         setMicMuteFromSwitchInput();
+
+        // Restore vibrator info
+        updateVibratorInfos();
     }
 
     private void onReinitVolumes(@NonNull String caller) {
@@ -4614,7 +4647,8 @@
     }
 
     @GuardedBy("mDeviceBroker.mSetModeLock")
-    void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage) {
+    void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage,
+                           boolean force) {
         if (requestedMode == AudioSystem.MODE_CURRENT) {
             requestedMode = getMode();
         }
@@ -4631,7 +4665,7 @@
             Log.v(TAG, "onUpdateAudioMode() new mode: " + mode + ", current mode: "
                     + mMode.get() + " requested mode: " + requestedMode);
         }
-        if (mode != mMode.get()) {
+        if (mode != mMode.get() || force) {
             final long identity = Binder.clearCallingIdentity();
             int status = mAudioSystem.setPhoneState(mode, uid);
             Binder.restoreCallingIdentity(identity);
@@ -7402,8 +7436,8 @@
                         h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid()));
                         h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid()));
                         if (wasActive != h.isActive()) {
-                            onUpdateAudioMode(AudioSystem.MODE_CURRENT,
-                                    android.os.Process.myPid(), mContext.getPackageName());
+                            onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
+                                    mContext.getPackageName(), false /*force*/);
                         }
                     }
                     break;
@@ -7428,7 +7462,7 @@
 
                 case MSG_UPDATE_AUDIO_MODE:
                     synchronized (mDeviceBroker.mSetModeLock) {
-                        onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj);
+                        onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
                     }
                     break;
             }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 972071c..24e867a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -52,7 +52,6 @@
 import com.android.server.biometrics.sensors.AuthenticationClient;
 import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
-import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.InvalidationRequesterClient;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.PerformanceTracker;
@@ -153,7 +152,10 @@
                             prop.commonProps.maxEnrollmentsPerUser,
                             componentInfo,
                             prop.sensorType,
-                            true /* resetLockoutRequiresHardwareAuthToken */);
+                            true /* resetLockoutRequiresHardwareAuthToken */,
+                            prop.sensorLocations[0].sensorLocationX,
+                            prop.sensorLocations[0].sensorLocationY,
+                            prop.sensorLocations[0].sensorRadius);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
                     internalProp, gestureAvailabilityDispatcher);
 
@@ -388,7 +390,7 @@
     public void scheduleRemove(int sensorId, @NonNull IBinder token,
             @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
             @NonNull String opPackageName) {
-        scheduleRemoveSpecifiedIds(sensorId, token, new int[] {fingerId}, userId, receiver,
+        scheduleRemoveSpecifiedIds(sensorId, token, new int[]{fingerId}, userId, receiver,
                 opPackageName);
     }
 
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 069c5c3..ab9de77 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -118,7 +118,7 @@
         if (!mIsQuitting) {
             mRouteSelectionCallback = new RouteSelectionCallback();
             mConnectivityManager.requestBackgroundNetwork(
-                    getBaseNetworkRequestBuilder().build(), mHandler, mRouteSelectionCallback);
+                    getRouteSelectionRequest(), mHandler, mRouteSelectionCallback);
 
             mWifiBringupCallback = new NetworkBringupCallback();
             mConnectivityManager.requestBackgroundNetwork(
@@ -149,12 +149,48 @@
         }
     }
 
-    private NetworkRequest getWifiNetworkRequest() {
+    /**
+     * Builds the Route selection request
+     *
+     * <p>This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue
+     * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier
+     * owned networks may be selected, as the request specifies only subIds in the VCN's
+     * subscription group, while the VCN networks are excluded by virtue of not having subIds set on
+     * the VCN-exposed networks.
+     */
+    private NetworkRequest getRouteSelectionRequest() {
         return getBaseNetworkRequestBuilder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
                 .build();
     }
 
+    /**
+     * Builds the WiFi bringup request
+     *
+     * <p>This request is built specifically to match only carrier-owned WiFi networks, but is also
+     * built to ONLY keep Carrier WiFi Networks alive (but never bring them up). This is a result of
+     * the WifiNetworkFactory not advertising a list of subIds, and therefore not accepting this
+     * request. As such, it will bind to a Carrier WiFi Network that has already been brought up,
+     * but will NEVER bring up a Carrier WiFi network itself.
+     */
+    private NetworkRequest getWifiNetworkRequest() {
+        return getBaseNetworkRequestBuilder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+                .build();
+    }
+
+    /**
+     * Builds a Cellular bringup request for a given subId
+     *
+     * <p>This request is filed in order to ensure that the Telephony stack always has a
+     * NetworkRequest to bring up a VCN underlying cellular network. It is required in order to
+     * ensure that even when a VCN (appears as Cellular) satisfies the default request, Telephony
+     * will bring up additional underlying Cellular networks.
+     *
+     * <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
+     * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
+     */
     private NetworkRequest getCellNetworkRequestForSubId(int subId) {
         return getBaseNetworkRequestBuilder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -164,20 +200,13 @@
 
     /**
      * Builds and returns a NetworkRequest builder common to all Underlying Network requests
-     *
-     * <p>This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue
-     * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier
-     * owned networks may be selected, as the request specifies only subIds in the VCN's
-     * subscription group, while the VCN networks are excluded by virtue of not having subIds set on
-     * the VCN-exposed networks.
      */
     private NetworkRequest.Builder getBaseNetworkRequestBuilder() {
         return new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
-                .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup));
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
     }
 
     /**
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 89ed956..546893588 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -17,6 +17,9 @@
 package com.android.server.vcn;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
 import static com.android.server.VcnManagementService.VDBG;
 
@@ -44,7 +47,6 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Represents an single instance of a VCN.
@@ -137,17 +139,14 @@
     @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
 
     /**
-     * Whether this Vcn instance is active and running.
+     * The current status of this Vcn instance
      *
-     * <p>The value will be {@code true} while running. It will be {@code false} if the VCN has been
-     * shut down or has entered safe mode.
-     *
-     * <p>This AtomicBoolean is required in order to ensure consistency and correctness across
-     * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads
-     * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN
-     * Looper.
+     * <p>The value will be {@link VCN_STATUS_CODE_ACTIVE} while all VcnGatewayConnections are in
+     * good standing, {@link VCN_STATUS_CODE_SAFE_MODE} if any VcnGatewayConnections are in safe
+     * mode, and {@link VCN_STATUS_CODE_INACTIVE} once a teardown has been commanded.
      */
-    private final AtomicBoolean mIsActive = new AtomicBoolean(true);
+    // Accessed from different threads, but always under lock in VcnManagementService
+    private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
 
     public Vcn(
             @NonNull VcnContext vcnContext,
@@ -199,9 +198,15 @@
         sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN));
     }
 
-    /** Synchronously checks whether this Vcn is active. */
-    public boolean isActive() {
-        return mIsActive.get();
+    /** Synchronously retrieves the current status code. */
+    public int getStatus() {
+        return mCurrentStatus;
+    }
+
+    /** Sets the status of this VCN */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public void setStatus(int status) {
+        mCurrentStatus = status;
     }
 
     /** Get current Gateways for testing purposes */
@@ -217,12 +222,6 @@
         return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections));
     }
 
-    /** Set whether this Vcn is active for testing purposes */
-    @VisibleForTesting(visibility = Visibility.PRIVATE)
-    public void setIsActive(boolean isActive) {
-        mIsActive.set(isActive);
-    }
-
     private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
         @Override
         public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -264,7 +263,8 @@
 
         mConfig = config;
 
-        if (mIsActive.getAndSet(true)) {
+        // TODO(b/183174340): Remove this once opportunistic safe mode is supported.
+        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
             // VCN is already active - teardown any GatewayConnections whose configs have been
             // removed and get all current requests
             for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
@@ -288,11 +288,15 @@
             // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
             // satisfied start a new GatewayConnection)
             mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
-        } else {
+        } else if (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) {
             // If this VCN was not previously active, it is exiting Safe Mode. Re-register the
             // request listener to get NetworkRequests again (and all cached requests).
             mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
+        } else {
+            // Ignored; VCN was not active; config updates ignored.
+            return;
         }
+        mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
     }
 
     private void handleTeardown() {
@@ -302,18 +306,20 @@
             gatewayConnection.teardownAsynchronously();
         }
 
-        mIsActive.set(false);
+        mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
     }
 
     private void handleEnterSafeMode() {
+        // TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
         handleTeardown();
 
+        mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE;
         mVcnCallback.onEnteredSafeMode();
     }
 
     private void handleNetworkRequested(
             @NonNull NetworkRequest request, int score, int providerId) {
-        if (!isActive()) {
+        if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) {
             Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
             return;
         }
@@ -370,8 +376,8 @@
         mVcnGatewayConnections.remove(config);
 
         // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
-        // start a new GatewayConnection), but only if the Vcn is still active
-        if (isActive()) {
+        // start a new GatewayConnection), but only if the Vcn is still alive
+        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
             mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
         }
     }
@@ -379,7 +385,7 @@
     private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
         mLastSnapshot = snapshot;
 
-        if (isActive()) {
+        if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
             for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
                 gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
             }
@@ -417,7 +423,7 @@
 
         /** Callback by a VcnGatewayConnection to indicate that an error occurred. */
         void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
@@ -445,12 +451,12 @@
 
         @Override
         public void onGatewayConnectionError(
-                @NonNull int[] networkCapabilities,
+                @NonNull String gatewayConnectionName,
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage) {
             mVcnCallback.onGatewayConnectionError(
-                    networkCapabilities, errorCode, exceptionClass, exceptionMessage);
+                    gatewayConnectionName, errorCode, exceptionClass, exceptionMessage);
         }
     }
 
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9589505..2ba8edd 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -980,7 +980,7 @@
         // IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed()
         if (exception != null) {
             mGatewayStatusCallback.onGatewayConnectionError(
-                    mConnectionConfig.getExposedCapabilities(),
+                    mConnectionConfig.getGatewayConnectionName(),
                     VCN_ERROR_CODE_INTERNAL_ERROR,
                     RuntimeException.class.getName(),
                     "Received "
@@ -1017,7 +1017,7 @@
         }
 
         mGatewayStatusCallback.onGatewayConnectionError(
-                mConnectionConfig.getExposedCapabilities(),
+                mConnectionConfig.getGatewayConnectionName(),
                 errorCode,
                 exceptionClass,
                 exceptionMessage);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a9d33dc..c9af62b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3750,6 +3750,10 @@
     @VisibleForTesting
     void setImeInputTarget(WindowState target) {
         mImeInputTarget = target;
+        boolean canScreenshot = mImeInputTarget == null || !mImeInputTarget.isSecureLocked();
+        if (mImeWindowsContainer.setCanScreenshot(canScreenshot)) {
+            mWmService.requestTraversal();
+        }
     }
 
     @VisibleForTesting
@@ -3867,7 +3871,7 @@
     void updateImeInputAndControlTarget(WindowState target) {
         if (mImeInputTarget != target) {
             ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
-            mImeInputTarget = target;
+            setImeInputTarget(target);
             updateImeControlTarget();
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a5843d4..070a725 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3321,4 +3321,12 @@
     @WindowManager.LayoutParams.WindowType int getWindowType() {
         return INVALID_WINDOW_TYPE;
     }
+
+    boolean setCanScreenshot(boolean canScreenshot) {
+        if (mSurfaceControl == null) {
+            return false;
+        }
+        getPendingTransaction().setSecure(mSurfaceControl, !canScreenshot);
+        return true;
+    }
 }
diff --git a/services/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp
index 9456946..646aabd 100644
--- a/services/core/jni/gnss/GnssMeasurementCallback.cpp
+++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp
@@ -302,6 +302,10 @@
 
     SET(Cn0DbHz, measurement.antennaCN0DbHz);
     SET(ConstellationType, static_cast<int32_t>(measurement.signalType.constellation));
+    // Half cycle state is reported in the AIDL version of GnssMeasurement
+    SET(AccumulatedDeltaRangeState,
+        (static_cast<int32_t>(measurement.accumulatedDeltaRangeState) |
+         ADR_STATE_HALF_CYCLE_REPORTED));
 
     if (measurement.flags & static_cast<uint32_t>(GnssMeasurement::HAS_CARRIER_FREQUENCY)) {
         SET(CarrierFrequencyHz, static_cast<float>(measurement.signalType.carrierFrequencyHz));
@@ -481,7 +485,7 @@
         JavaObject& object) {
     translateSingleGnssMeasurement(measurement_V1_1.v1_0, object);
 
-    // Set the V1_1 flag, and mark that new field has valid information for Java Layer
+    // Half cycle state is reported in HIDL v1.1 or newer.
     SET(AccumulatedDeltaRangeState,
         (static_cast<int32_t>(measurement_V1_1.accumulatedDeltaRangeState) |
          ADR_STATE_HALF_CYCLE_REPORTED));
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 7c30b45..d1cd7cd 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -92,6 +92,8 @@
     <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
     <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
     <uses-permission android:name="android.permission.KILL_UID"/>
+    <uses-permission
+        android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 94cc666..35c37ef 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.hardware.biometrics.common.CommonProps;
 import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.SensorLocation;
 import android.hardware.biometrics.fingerprint.SensorProps;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
@@ -33,7 +34,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.HalClientMonitor;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -77,9 +77,11 @@
         final SensorProps sensor1 = new SensorProps();
         sensor1.commonProps = new CommonProps();
         sensor1.commonProps.sensorId = 0;
+        sensor1.sensorLocations = new SensorLocation[] {new SensorLocation()};
         final SensorProps sensor2 = new SensorProps();
         sensor2.commonProps = new CommonProps();
         sensor2.commonProps.sensorId = 1;
+        sensor2.sensorLocations = new SensorLocation[] {new SensorLocation()};
 
         mSensorProps = new SensorProps[] {sensor1, sensor2};
 
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
index c1ef350..7ac51b7 100644
--- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -79,6 +79,18 @@
     }
 
     @Test
+    public void testBuilderRequiresUniqueGatewayConnectionNames() {
+        final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.buildTestConfig();
+        try {
+            new VcnConfig.Builder(mContext)
+                    .addGatewayConnectionConfig(config)
+                    .addGatewayConnectionConfig(config);
+            fail("Expected exception due to duplicate gateway connection name");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
     public void testBuilderAndGetters() {
         final VcnConfig config = buildTestConfig(mContext);
 
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 8a0c923..4ee4d61 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.net.NetworkCapabilities;
@@ -61,13 +62,20 @@
     public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG =
             VcnControlPlaneIkeConfigTest.buildTestConfig();
 
+    public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
+    private static int sGatewayConnectionConfigCount = 0;
+
     // Public for use in VcnGatewayConnectionTest
     public static VcnGatewayConnectionConfig buildTestConfig() {
         return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
     }
 
     private static VcnGatewayConnectionConfig.Builder newBuilder() {
-        return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG);
+        // Append a unique identifier to the name prefix to guarantee that all created
+        // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
+        return new VcnGatewayConnectionConfig.Builder(
+                GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
+                CONTROL_PLANE_CONFIG);
     }
 
     // Public for use in VcnGatewayConnectionTest
@@ -87,9 +95,23 @@
     }
 
     @Test
+    public void testBuilderRequiresNonNullGatewayConnectionName() {
+        try {
+            new VcnGatewayConnectionConfig.Builder(
+                            null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG)
+                    .build();
+
+            fail("Expected exception due to invalid gateway connection name");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    @Test
     public void testBuilderRequiresNonNullControlPlaneConfig() {
         try {
-            new VcnGatewayConnectionConfig.Builder(null).build();
+            new VcnGatewayConnectionConfig.Builder(
+                            GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */)
+                    .build();
 
             fail("Expected exception due to invalid control plane config");
         } catch (NullPointerException e) {
@@ -139,6 +161,8 @@
     public void testBuilderAndGetters() {
         final VcnGatewayConnectionConfig config = buildTestConfig();
 
+        assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
+
         int[] exposedCaps = config.getExposedCapabilities();
         Arrays.sort(exposedCaps);
         assertArrayEquals(EXPOSED_CAPS, exposedCaps);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 516c206..8461de6 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -50,9 +50,7 @@
 
 public class VcnManagerTest {
     private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
-    private static final int[] UNDERLYING_NETWORK_CAPABILITIES = {
-        NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET
-    };
+    private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName";
     private static final Executor INLINE_EXECUTOR = Runnable::run;
 
     private IVcnManagementService mMockVcnManagementService;
@@ -207,13 +205,13 @@
         verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
 
         cbBinder.onGatewayConnectionError(
-                UNDERLYING_NETWORK_CAPABILITIES,
+                GATEWAY_CONNECTION_NAME,
                 VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
                 UnknownHostException.class.getName(),
                 "exception_message");
         verify(mMockStatusCallback)
                 .onGatewayConnectionError(
-                        eq(UNDERLYING_NETWORK_CAPABILITIES),
+                        eq(GATEWAY_CONNECTION_NAME),
                         eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
                         any(UnknownHostException.class));
     }
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index c88b0c1..4ad7136 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -19,6 +19,8 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
 
@@ -695,7 +697,9 @@
                 hasCarrierPrivileges);
 
         final Vcn vcn = startAndGetVcnInstance(subGrp);
-        doReturn(isVcnActive).when(vcn).isActive();
+        doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
+                .when(vcn)
+                .getStatus();
 
         doReturn(true)
                 .when(mLocationPermissionChecker)
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index ed2e4d9..b592000 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -158,7 +158,7 @@
         for (final int subId : expectedSubIds) {
             verify(mConnectivityManager)
                     .requestBackgroundNetwork(
-                            eq(getCellRequestForSubId(subId, expectedSubIds)),
+                            eq(getCellRequestForSubId(subId)),
                             any(),
                             any(NetworkBringupCallback.class));
         }
@@ -189,30 +189,30 @@
     }
 
     private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
-        return getExpectedRequestBase(netCapsSubIds)
+        return getExpectedRequestBase()
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                .setSubIds(netCapsSubIds)
                 .build();
     }
 
-    private NetworkRequest getCellRequestForSubId(int subId, Set<Integer> netCapsSubIds) {
-        return getExpectedRequestBase(netCapsSubIds)
+    private NetworkRequest getCellRequestForSubId(int subId) {
+        return getExpectedRequestBase()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
                 .build();
     }
 
     private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
-        return getExpectedRequestBase(netCapsSubIds).build();
+        return getExpectedRequestBase().setSubIds(netCapsSubIds).build();
     }
 
-    private NetworkRequest.Builder getExpectedRequestBase(Set<Integer> subIds) {
+    private NetworkRequest.Builder getExpectedRequestBase() {
         final NetworkRequest.Builder builder =
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
-                        .setSubIds(subIds);
+                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
 
         return builder;
     }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index ca6448c..2fadd44 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -241,7 +241,7 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getExposedCapabilities()),
+                        eq(mConfig.getGatewayConnectionName()),
                         eq(VCN_ERROR_CODE_INTERNAL_ERROR),
                         any(),
                         any());
@@ -275,7 +275,10 @@
 
         verify(mGatewayStatusCallback)
                 .onGatewayConnectionError(
-                        eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any());
+                        eq(mConfig.getGatewayConnectionName()),
+                        eq(expectedErrorType),
+                        any(),
+                        any());
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index c853fc5..540be38 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -19,10 +19,12 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
@@ -51,7 +53,9 @@
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
@@ -140,7 +144,7 @@
         mTestLooper.dispatchAll();
     }
 
-    private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) {
+    private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
 
@@ -150,25 +154,25 @@
         final TelephonySubscriptionSnapshot updatedSnapshot =
                 mock(TelephonySubscriptionSnapshot.class);
 
-        mVcn.setIsActive(isActive);
+        mVcn.setStatus(status);
 
         mVcn.updateSubscriptionSnapshot(updatedSnapshot);
         mTestLooper.dispatchAll();
 
         for (final VcnGatewayConnection gateway : gatewayConnections) {
-            verify(gateway, isActive ? times(1) : never())
+            verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never())
                     .updateSubscriptionSnapshot(eq(updatedSnapshot));
         }
     }
 
     @Test
     public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
-        verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */);
+        verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
     }
 
     @Test
-    public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() {
-        verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */);
+    public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() {
+        verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE);
     }
 
     private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
@@ -199,7 +203,7 @@
     private void verifySafeMode(
             NetworkRequestListener requestListener,
             Set<VcnGatewayConnection> expectedGatewaysTornDown) {
-        assertFalse(mVcn.isActive());
+        assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus());
         for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
             verify(gatewayConnection).teardownAsynchronously();
         }
@@ -274,11 +278,12 @@
         assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
 
         // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
-        // down
-        final VcnGatewayConnectionConfig activeConfig =
-                VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]);
-        final VcnGatewayConnectionConfig removedConfig =
-                VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]);
+        // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
+        // matches.
+        final List<VcnGatewayConnectionConfig> currentConfigs =
+                new ArrayList<>(mVcn.getVcnGatewayConnectionConfigMap().keySet());
+        final VcnGatewayConnectionConfig activeConfig = currentConfigs.get(0);
+        final VcnGatewayConnectionConfig removedConfig = currentConfigs.get(1);
         final VcnConfig updatedConfig =
                 new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
 
@@ -316,7 +321,7 @@
 
         // Registered on start, then re-registered with new configs
         verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
-        assertTrue(mVcn.isActive());
+        assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus());
         for (final int[] caps : TEST_CAPS) {
             // Expect each gateway connection created only on initial startup
             verify(mDeps)
@@ -331,7 +336,7 @@
 
     @Test
     public void testIgnoreNetworkRequestWhileInactive() {
-        mVcn.setIsActive(false /* isActive */);
+        mVcn.setStatus(VCN_STATUS_CODE_INACTIVE);
 
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
         triggerVcnRequestListeners(requestListener);
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index dfdac6b..d1e6d39 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -466,11 +466,19 @@
   const std::string android_r_java = android_java + "/android/R.java";
   std::string android_r_contents;
   ASSERT_TRUE(android::base::ReadFileToString(android_r_java, &android_r_contents));
-  EXPECT_THAT(android_r_contents, HasSubstr(" public static final int finalized_res=0x01010001;"));
-  EXPECT_THAT(android_r_contents, HasSubstr(" public static int staged_s_res=0x01010050;"));
-  EXPECT_THAT(android_r_contents, HasSubstr(" public static int staged_s2_res=0x01ff0049;"));
-  EXPECT_THAT(android_r_contents, HasSubstr(" public static int staged_t_res=0x01fe0063;"));
-  EXPECT_THAT(android_r_contents, HasSubstr(" public static int staged_t_string=0x01fd0072;"));
+  EXPECT_THAT(android_r_contents, HasSubstr("public static final int finalized_res=0x01010001;"));
+  EXPECT_THAT(
+      android_r_contents,
+      HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01010050; }"));
+  EXPECT_THAT(
+      android_r_contents,
+      HasSubstr("public static final int staged_s2_res; static { staged_s2_res=0x01ff0049; }"));
+  EXPECT_THAT(
+      android_r_contents,
+      HasSubstr("public static final int staged_t_res; static { staged_t_res=0x01fe0063; }"));
+  EXPECT_THAT(
+      android_r_contents,
+      HasSubstr("public static final int staged_t_string; static { staged_t_string=0x01fd0072; }"));
 
   // Build an app that uses the framework attribute in a declare-styleable
   const std::string client_res = GetTestPath("app-res");
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index bfb8d58..f1b350f 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -393,8 +393,15 @@
         .SetAllowMangled(true);
 
     if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
-      res_builder.SetVisibility(Visibility{Visibility::Level::kPublic});
+      Visibility visibility{Visibility::Level::kPublic};
 
+      auto spec_flags = entry_type_spec_flags_.find(res_id);
+      if (spec_flags != entry_type_spec_flags_.end() &&
+          spec_flags->second & ResTable_typeSpec::SPEC_STAGED_API) {
+        visibility.staged_api = true;
+      }
+
+      res_builder.SetVisibility(visibility);
       // Erase the ID from the map once processed, so that we don't mark the same symbol more than
       // once.
       entry_type_spec_flags_.erase(res_id);
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index d3648c8..2acdadb 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -78,10 +78,18 @@
     ClassMember::Print(final, printer, strip_api_annotations);
 
     printer->Print("public static ");
-    if (final && !staged_api_) {
+    if (final) {
       printer->Print("final ");
     }
-    printer->Print("int ").Print(name_).Print("=").Print(to_string(val_)).Print(";");
+    printer->Print("int ").Print(name_);
+    if (staged_api_) {
+      // Prevent references to staged apis from being inline by setting their value out-of-line.
+      printer->Print("; static { ").Print(name_);
+    }
+    printer->Print("=").Print(to_string(val_)).Print(";");
+    if (staged_api_) {
+      printer->Print(" }");
+    }
   }
 
  private: