Merge "Add debug logs for TransferOwnershipMetadataManagerTest cases." into pi-dev
diff --git a/Android.bp b/Android.bp
index 037c29c..be83210 100644
--- a/Android.bp
+++ b/Android.bp
@@ -169,8 +169,6 @@
         "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl",
         "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl",
         "core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl",
-        "core/java/android/hardware/location/IFusedLocationHardware.aidl",
-        "core/java/android/hardware/location/IFusedLocationHardwareSink.aidl",
         "core/java/android/hardware/location/IGeofenceHardware.aidl",
         "core/java/android/hardware/location/IGeofenceHardwareCallback.aidl",
         "core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl",
@@ -409,7 +407,6 @@
         "location/java/android/location/IBatchedLocationCallback.aidl",
         "location/java/android/location/ICountryDetector.aidl",
         "location/java/android/location/ICountryListener.aidl",
-        "location/java/android/location/IFusedProvider.aidl",
         "location/java/android/location/IGeocodeProvider.aidl",
         "location/java/android/location/IGeofenceProvider.aidl",
         "location/java/android/location/IGnssStatusListener.aidl",
diff --git a/Android.mk b/Android.mk
index ee8fbe0..e2f88e8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -861,42 +861,39 @@
 
 # ==== hiddenapi lists =======================================
 
-# Copy light and dark greylist over into the build folder.
+# Copy blacklist and light greylist over into the build folder.
 # This is for ART buildbots which need to mock these lists and have alternative
 # rules for building them. Other rules in the build system should depend on the
 # files in the build folder.
 
+$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\
+                            $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)))
+
 # Temporarily merge light greylist from two files. Vendor list will become dark
 # grey once we remove the UI toast.
 $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): frameworks/base/config/hiddenapi-light-greylist.txt \
                                                frameworks/base/config/hiddenapi-vendor-list.txt
 	sort $^ > $@
 
-$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-dark-greylist.txt,\
-                            $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)))
-
 # Generate dark greylist as private API minus (blacklist plus light greylist).
 
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): DARK_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
-                                          $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
-                                          $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
-	if [ ! -z "`comm -12 <(sort $(LIGHT_GREYLIST)) <(sort $(DARK_GREYLIST))`" ]; then \
-		echo "There should be no overlap between $(LIGHT_GREYLIST) and $(DARK_GREYLIST)" 1>&2; \
-		comm -12 <(sort $(LIGHT_GREYLIST)) <(sort $(DARK_GREYLIST)) 1>&2; \
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): BLACKLIST := $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+                                              $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST) \
+                                              $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
+	if [ ! -z "`comm -12 <(sort $(BLACKLIST)) <(sort $(LIGHT_GREYLIST))`" ]; then \
+		echo "There should be no overlap between $(BLACKLIST) and $(LIGHT_GREYLIST)" 1>&2; \
 		exit 1; \
+	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST))`" ]; then \
+		echo "$(BLACKLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
+		exit 2; \
 	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST))`" ]; then \
 		echo "$(LIGHT_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
-		comm -13 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST)) 1>&2; \
-		exit 2; \
-	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(DARK_GREYLIST))`" ]; then \
-		echo "$(DARK_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
-		comm -13 <(sort $(PRIVATE_API)) <(sort $(DARK_GREYLIST)) 1>&2; \
 		exit 3; \
 	fi
-	comm -23 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST) $(DARK_GREYLIST)) > $@
+	comm -23 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST) $(LIGHT_GREYLIST)) > $@
 
 # Include subdirectory makefiles
 # ============================================================
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
new file mode 100644
index 0000000..28d4096
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.os;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BinderCallsStats;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertNull;
+
+
+/**
+ * Performance tests for {@link BinderCallsStats}
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BinderCallsStatsPerfTest {
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    private BinderCallsStats mBinderCallsStats;
+
+    @Before
+    public void setUp() {
+        mBinderCallsStats = new BinderCallsStats(true);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void timeCallSession() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Binder b = new Binder();
+        int i = 0;
+        while (state.keepRunning()) {
+            BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, i % 100);
+            mBinderCallsStats.callEnded(s);
+            i++;
+        }
+    }
+
+    @Test
+    public void timeCallSessionTrackingDisabled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        Binder b = new Binder();
+        mBinderCallsStats = new BinderCallsStats(false);
+        assertNull(mBinderCallsStats.callStarted(b, 0));
+        while (state.keepRunning()) {
+            BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, 0);
+            mBinderCallsStats.callEnded(s);
+        }
+    }
+
+}
diff --git a/api/current.txt b/api/current.txt
index a0b887a..7b627a8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1378,7 +1378,7 @@
     field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e
     field public static final int textEditSuggestionItemLayout = 16843636; // 0x1010374
     field public static final int textFilterEnabled = 16843007; // 0x10100ff
-    field public static final int textFontWeight = 16844166; // 0x1010586
+    field public static final int textFontWeight = 16844165; // 0x1010585
     field public static final int textIsSelectable = 16843542; // 0x1010316
     field public static final int textOff = 16843045; // 0x1010125
     field public static final int textOn = 16843044; // 0x1010124
@@ -1469,7 +1469,6 @@
     field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
     field public static final int unselectedAlpha = 16843278; // 0x101020e
     field public static final int updatePeriodMillis = 16843344; // 0x1010250
-    field public static final int urlBarResourceId = 16844164; // 0x1010584
     field public static final int use32bitAbi = 16844053; // 0x1010515
     field public static final int useDefaultMargins = 16843641; // 0x1010379
     field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
@@ -1549,7 +1548,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 windowLayoutInDisplayCutoutMode = 16844167; // 0x1010587
+    field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586
     field public static final int windowLightNavigationBar = 16844140; // 0x101056c
     field public static final int windowLightStatusBar = 16844000; // 0x10104e0
     field public static final int windowMinWidthMajor = 16843606; // 0x1010356
@@ -6559,7 +6558,7 @@
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
     method public void setLogoutEnabled(android.content.ComponentName, boolean);
     method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
-    method public void setMandatoryBackupTransport(android.content.ComponentName, android.content.ComponentName);
+    method public boolean setMandatoryBackupTransport(android.content.ComponentName, android.content.ComponentName);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -7193,6 +7192,7 @@
     field public static final deprecated java.lang.String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
     field public static final java.lang.String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
     field public static final java.lang.String HINT_ACTIONS = "actions";
+    field public static final java.lang.String HINT_ERROR = "error";
     field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
     field public static final java.lang.String HINT_KEY_WORDS = "key_words";
     field public static final java.lang.String HINT_LARGE = "large";
@@ -7218,29 +7218,22 @@
   }
 
   public static class Slice.Builder {
-    ctor public Slice.Builder(android.net.Uri);
+    ctor public deprecated Slice.Builder(android.net.Uri);
+    ctor public Slice.Builder(android.net.Uri, android.app.slice.SliceSpec);
     ctor public Slice.Builder(android.app.slice.Slice.Builder);
-    method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
     method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice, java.lang.String);
-    method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.lang.String...);
     method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addHints(java.lang.String...);
     method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.lang.String...);
     method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addInt(int, java.lang.String, java.lang.String...);
     method public android.app.slice.Slice.Builder addInt(int, java.lang.String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addLong(long, java.lang.String, java.util.List<java.lang.String>);
     method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String, java.lang.String...);
-    method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
     method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice, java.lang.String);
-    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String, java.lang.String...);
     method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.lang.String...);
-    method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.util.List<java.lang.String>);
+    method public deprecated android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.util.List<java.lang.String>);
     method public android.app.slice.Slice build();
     method public android.app.slice.Slice.Builder setCallerNeeded(boolean);
-    method public android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
+    method public deprecated android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
   }
 
   public final class SliceItem implements android.os.Parcelable {
@@ -7263,10 +7256,11 @@
     field public static final java.lang.String FORMAT_BUNDLE = "bundle";
     field public static final java.lang.String FORMAT_IMAGE = "image";
     field public static final java.lang.String FORMAT_INT = "int";
+    field public static final java.lang.String FORMAT_LONG = "long";
     field public static final java.lang.String FORMAT_REMOTE_INPUT = "input";
     field public static final java.lang.String FORMAT_SLICE = "slice";
     field public static final java.lang.String FORMAT_TEXT = "text";
-    field public static final java.lang.String FORMAT_TIMESTAMP = "timestamp";
+    field public static final deprecated java.lang.String FORMAT_TIMESTAMP = "long";
   }
 
   public class SliceManager {
@@ -11172,6 +11166,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
+    method public android.os.PersistableBundle getSuspendedPackageAppExtras();
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -11185,6 +11180,7 @@
     method public abstract boolean hasSystemFeature(java.lang.String, int);
     method public abstract boolean isInstantApp();
     method public abstract boolean isInstantApp(java.lang.String);
+    method public boolean isPackageSuspended();
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -13650,12 +13646,14 @@
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
     field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
     field public static final int ALLOCATOR_SOFTWARE = 1; // 0x1
-    field public static final int ERROR_SOURCE_ERROR = 3; // 0x3
-    field public static final int ERROR_SOURCE_EXCEPTION = 1; // 0x1
-    field public static final int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
   }
 
-  public static abstract class ImageDecoder.Error implements java.lang.annotation.Annotation {
+  public static final class ImageDecoder.DecodeException extends java.io.IOException {
+    method public int getError();
+    method public android.graphics.ImageDecoder.Source getSource();
+    field public static final int SOURCE_EXCEPTION = 1; // 0x1
+    field public static final int SOURCE_INCOMPLETE = 2; // 0x2
+    field public static final int SOURCE_MALFORMED_DATA = 3; // 0x3
   }
 
   public static class ImageDecoder.ImageInfo {
@@ -13664,16 +13662,12 @@
     method public boolean isAnimated();
   }
 
-  public static class ImageDecoder.IncompleteException extends java.io.IOException {
-    ctor public ImageDecoder.IncompleteException();
-  }
-
   public static abstract interface ImageDecoder.OnHeaderDecodedListener {
     method public abstract void onHeaderDecoded(android.graphics.ImageDecoder, android.graphics.ImageDecoder.ImageInfo, android.graphics.ImageDecoder.Source);
   }
 
   public static abstract interface ImageDecoder.OnPartialImageListener {
-    method public abstract boolean onPartialImage(int, android.graphics.ImageDecoder.Source);
+    method public abstract boolean onPartialImage(android.graphics.ImageDecoder.DecodeException);
   }
 
   public static abstract class ImageDecoder.Source {
@@ -21551,10 +21545,10 @@
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public double getAutomaticGainControlLevelDb();
-    method public long getCarrierCycles();
+    method public deprecated long getCarrierCycles();
     method public float getCarrierFrequencyHz();
-    method public double getCarrierPhase();
-    method public double getCarrierPhaseUncertainty();
+    method public deprecated double getCarrierPhase();
+    method public deprecated double getCarrierPhaseUncertainty();
     method public double getCn0DbHz();
     method public int getConstellationType();
     method public int getMultipathIndicator();
@@ -21567,13 +21561,15 @@
     method public int getSvid();
     method public double getTimeOffsetNanos();
     method public boolean hasAutomaticGainControlLevelDb();
-    method public boolean hasCarrierCycles();
+    method public deprecated boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
-    method public boolean hasCarrierPhase();
-    method public boolean hasCarrierPhaseUncertainty();
+    method public deprecated boolean hasCarrierPhase();
+    method public deprecated boolean hasCarrierPhaseUncertainty();
     method public boolean hasSnrInDb();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_HALF_CYCLE_REPORTED = 16; // 0x10
+    field public static final int ADR_STATE_HALF_CYCLE_RESOLVED = 8; // 0x8
     field public static final int ADR_STATE_RESET = 2; // 0x2
     field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
     field public static final int ADR_STATE_VALID = 1; // 0x1
@@ -21823,7 +21819,6 @@
     method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback);
-    field public static final java.lang.String GNSS_HARDWARE_MODEL_NAME_UNKNOWN = "Model Name Unknown";
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -22096,7 +22091,6 @@
     method public boolean isBluetoothScoOn();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
-    method public boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
@@ -22422,7 +22416,6 @@
     method public int reloadStaticData();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
-    method public void removeStreamEventCallback();
     method public int setAuxEffectSendLevel(float);
     method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
@@ -22437,7 +22430,6 @@
     method public int setPresentation(android.media.AudioPresentation);
     method protected deprecated void setState(int);
     method public deprecated int setStereoVolume(float, float);
-    method public void setStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
@@ -22473,7 +22465,6 @@
     method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
     method public android.media.AudioTrack.Builder setPerformanceMode(int);
     method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
@@ -22497,12 +22488,6 @@
     method public default void onRoutingChanged(android.media.AudioRouting);
   }
 
-  public static abstract class AudioTrack.StreamEventCallback {
-    method public void onStreamDataRequest(android.media.AudioTrack);
-    method public void onStreamPresentationEnd(android.media.AudioTrack);
-    method public void onTearDown(android.media.AudioTrack);
-  }
-
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -22555,40 +22540,6 @@
     field public static final int QUALITY_MEDIUM = 1; // 0x1
   }
 
-  public final class DataSourceDesc {
-    method public long getEndPosition();
-    method public java.io.FileDescriptor getFileDescriptor();
-    method public long getFileDescriptorLength();
-    method public long getFileDescriptorOffset();
-    method public android.media.Media2DataSource getMedia2DataSource();
-    method public java.lang.String getMediaId();
-    method public long getStartPosition();
-    method public int getType();
-    method public android.net.Uri getUri();
-    method public android.content.Context getUriContext();
-    method public java.util.List<java.net.HttpCookie> getUriCookies();
-    method public java.util.Map<java.lang.String, java.lang.String> getUriHeaders();
-    field public static final long LONG_MAX = 576460752303423487L; // 0x7ffffffffffffffL
-    field public static final int TYPE_CALLBACK = 1; // 0x1
-    field public static final int TYPE_FD = 2; // 0x2
-    field public static final int TYPE_NONE = 0; // 0x0
-    field public static final int TYPE_URI = 3; // 0x3
-  }
-
-  public static class DataSourceDesc.Builder {
-    ctor public DataSourceDesc.Builder();
-    ctor public DataSourceDesc.Builder(android.media.DataSourceDesc);
-    method public android.media.DataSourceDesc build();
-    method public android.media.DataSourceDesc.Builder setDataSource(android.media.Media2DataSource);
-    method public android.media.DataSourceDesc.Builder setDataSource(java.io.FileDescriptor);
-    method public android.media.DataSourceDesc.Builder setDataSource(java.io.FileDescriptor, long, long);
-    method public android.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri);
-    method public android.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>);
-    method public android.media.DataSourceDesc.Builder setEndPosition(long);
-    method public android.media.DataSourceDesc.Builder setMediaId(java.lang.String);
-    method public android.media.DataSourceDesc.Builder setStartPosition(long);
-  }
-
   public final class DeniedByServerException extends android.media.MediaDrmException {
     ctor public DeniedByServerException(java.lang.String);
   }
@@ -22866,12 +22817,6 @@
     method public abstract void onJetUserIdUpdate(android.media.JetPlayer, int, int);
   }
 
-  public abstract class Media2DataSource implements java.io.Closeable {
-    ctor public Media2DataSource();
-    method public abstract long getSize() throws java.io.IOException;
-    method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
-  }
-
   public class MediaActionSound {
     ctor public MediaActionSound();
     method public void load(int);
@@ -22883,27 +22828,6 @@
     field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
   }
 
-  public class MediaBrowser2 extends android.media.MediaController2 {
-    ctor public MediaBrowser2(android.content.Context, android.media.SessionToken2, java.util.concurrent.Executor, android.media.MediaBrowser2.BrowserCallback);
-    method public void getChildren(java.lang.String, int, int, android.os.Bundle);
-    method public void getItem(java.lang.String);
-    method public void getLibraryRoot(android.os.Bundle);
-    method public void getSearchResult(java.lang.String, int, int, android.os.Bundle);
-    method public void search(java.lang.String, android.os.Bundle);
-    method public void subscribe(java.lang.String, android.os.Bundle);
-    method public void unsubscribe(java.lang.String);
-  }
-
-  public static class MediaBrowser2.BrowserCallback extends android.media.MediaController2.ControllerCallback {
-    ctor public MediaBrowser2.BrowserCallback();
-    method public void onChildrenChanged(android.media.MediaBrowser2, java.lang.String, int, android.os.Bundle);
-    method public void onGetChildrenDone(android.media.MediaBrowser2, java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
-    method public void onGetItemDone(android.media.MediaBrowser2, java.lang.String, android.media.MediaItem2);
-    method public void onGetLibraryRootDone(android.media.MediaBrowser2, android.os.Bundle, java.lang.String, android.os.Bundle);
-    method public void onGetSearchResultDone(android.media.MediaBrowser2, java.lang.String, int, int, java.util.List<android.media.MediaItem2>, android.os.Bundle);
-    method public void onSearchResultChanged(android.media.MediaBrowser2, java.lang.String, int, android.os.Bundle);
-  }
-
   public final class MediaCas implements java.lang.AutoCloseable {
     ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
     method public void close();
@@ -23381,82 +23305,6 @@
     field public static final int REGULAR_CODECS = 0; // 0x0
   }
 
-  public class MediaController2 implements java.lang.AutoCloseable {
-    ctor public MediaController2(android.content.Context, android.media.SessionToken2, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback);
-    method public void addPlaylistItem(int, android.media.MediaItem2);
-    method public void adjustVolume(int, int);
-    method public void close();
-    method public void fastForward();
-    method public long getBufferedPosition();
-    method public android.media.MediaItem2 getCurrentMediaItem();
-    method public android.media.MediaController2.PlaybackInfo getPlaybackInfo();
-    method public float getPlaybackSpeed();
-    method public int getPlayerState();
-    method public java.util.List<android.media.MediaItem2> getPlaylist();
-    method public android.media.MediaMetadata2 getPlaylistMetadata();
-    method public long getPosition();
-    method public int getRepeatMode();
-    method public android.app.PendingIntent getSessionActivity();
-    method public android.media.SessionToken2 getSessionToken();
-    method public int getShuffleMode();
-    method public boolean isConnected();
-    method public void pause();
-    method public void play();
-    method public void playFromMediaId(java.lang.String, android.os.Bundle);
-    method public void playFromSearch(java.lang.String, android.os.Bundle);
-    method public void playFromUri(android.net.Uri, android.os.Bundle);
-    method public void prepare();
-    method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
-    method public void prepareFromSearch(java.lang.String, android.os.Bundle);
-    method public void prepareFromUri(android.net.Uri, android.os.Bundle);
-    method public void removePlaylistItem(android.media.MediaItem2);
-    method public void replacePlaylistItem(int, android.media.MediaItem2);
-    method public void rewind();
-    method public void seekTo(long);
-    method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
-    method public void setPlaybackSpeed(float);
-    method public void setPlaylist(java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void setRating(java.lang.String, android.media.Rating2);
-    method public void setRepeatMode(int);
-    method public void setShuffleMode(int);
-    method public void setVolumeTo(int, int);
-    method public void skipToNextItem();
-    method public void skipToPlaylistItem(android.media.MediaItem2);
-    method public void skipToPreviousItem();
-    method public void stop();
-    method public void updatePlaylistMetadata(android.media.MediaMetadata2);
-  }
-
-  public static abstract class MediaController2.ControllerCallback {
-    ctor public MediaController2.ControllerCallback();
-    method public void onAllowedCommandsChanged(android.media.MediaController2, android.media.MediaSession2.CommandGroup);
-    method public void onBufferedPositionChanged(android.media.MediaController2, long);
-    method public void onConnected(android.media.MediaController2, android.media.MediaSession2.CommandGroup);
-    method public void onCurrentMediaItemChanged(android.media.MediaController2, android.media.MediaItem2);
-    method public void onCustomCommand(android.media.MediaController2, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
-    method public void onCustomLayoutChanged(android.media.MediaController2, java.util.List<android.media.MediaSession2.CommandButton>);
-    method public void onDisconnected(android.media.MediaController2);
-    method public void onError(android.media.MediaController2, int, android.os.Bundle);
-    method public void onPlaybackInfoChanged(android.media.MediaController2, android.media.MediaController2.PlaybackInfo);
-    method public void onPlaybackSpeedChanged(android.media.MediaController2, float);
-    method public void onPlayerStateChanged(android.media.MediaController2, int);
-    method public void onPlaylistChanged(android.media.MediaController2, android.media.MediaPlaylistAgent, java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void onPlaylistMetadataChanged(android.media.MediaController2, android.media.MediaPlaylistAgent, android.media.MediaMetadata2);
-    method public void onPositionChanged(android.media.MediaController2, long, long);
-    method public void onRepeatModeChanged(android.media.MediaController2, android.media.MediaPlaylistAgent, int);
-    method public void onShuffleModeChanged(android.media.MediaController2, android.media.MediaPlaylistAgent, int);
-  }
-
-  public static final class MediaController2.PlaybackInfo {
-    method public android.media.AudioAttributes getAudioAttributes();
-    method public int getControlType();
-    method public int getCurrentVolume();
-    method public int getMaxVolume();
-    method public int getPlaybackType();
-    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
-    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
-  }
-
   public final class MediaCrypto {
     ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
     method protected void finalize();
@@ -23857,71 +23705,6 @@
     field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
   }
 
-  public class MediaItem2 {
-    method public static android.media.MediaItem2 fromBundle(android.content.Context, android.os.Bundle);
-    method public android.media.DataSourceDesc getDataSourceDesc();
-    method public int getFlags();
-    method public java.lang.String getMediaId();
-    method public android.media.MediaMetadata2 getMetadata();
-    method public boolean isBrowsable();
-    method public boolean isPlayable();
-    method public void setMetadata(android.media.MediaMetadata2);
-    method public android.os.Bundle toBundle();
-    field public static final int FLAG_BROWSABLE = 1; // 0x1
-    field public static final int FLAG_PLAYABLE = 2; // 0x2
-  }
-
-  public static final class MediaItem2.Builder {
-    ctor public MediaItem2.Builder(android.content.Context, int);
-    method public android.media.MediaItem2 build();
-    method public android.media.MediaItem2.Builder setDataSourceDesc(android.media.DataSourceDesc);
-    method public android.media.MediaItem2.Builder setMediaId(java.lang.String);
-    method public android.media.MediaItem2.Builder setMetadata(android.media.MediaMetadata2);
-  }
-
-  public abstract class MediaLibraryService2 extends android.media.MediaSessionService2 {
-    ctor public MediaLibraryService2();
-    method public abstract android.media.MediaLibraryService2.MediaLibrarySession onCreateSession(java.lang.String);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
-  }
-
-  public static final class MediaLibraryService2.LibraryRoot {
-    ctor public MediaLibraryService2.LibraryRoot(android.content.Context, java.lang.String, android.os.Bundle);
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getRootId();
-    field public static final java.lang.String EXTRA_OFFLINE = "android.media.extra.OFFLINE";
-    field public static final java.lang.String EXTRA_RECENT = "android.media.extra.RECENT";
-    field public static final java.lang.String EXTRA_SUGGESTED = "android.media.extra.SUGGESTED";
-  }
-
-  public static final class MediaLibraryService2.MediaLibrarySession extends android.media.MediaSession2 {
-    method public void notifyChildrenChanged(android.media.MediaSession2.ControllerInfo, java.lang.String, int, android.os.Bundle);
-    method public void notifyChildrenChanged(java.lang.String, int, android.os.Bundle);
-    method public void notifySearchResultChanged(android.media.MediaSession2.ControllerInfo, java.lang.String, int, android.os.Bundle);
-  }
-
-  public static final class MediaLibraryService2.MediaLibrarySession.Builder {
-    ctor public MediaLibraryService2.MediaLibrarySession.Builder(android.media.MediaLibraryService2, java.util.concurrent.Executor, android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback);
-    method public android.media.MediaLibraryService2.MediaLibrarySession build();
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setId(java.lang.String);
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setPlayer(android.media.MediaPlayerBase);
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setPlaylistAgent(android.media.MediaPlaylistAgent);
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setSessionActivity(android.app.PendingIntent);
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback);
-    method public android.media.MediaLibraryService2.MediaLibrarySession.Builder setVolumeProvider(android.media.VolumeProvider2);
-  }
-
-  public static class MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback extends android.media.MediaSession2.SessionCallback {
-    ctor public MediaLibraryService2.MediaLibrarySession.MediaLibrarySessionCallback(android.content.Context);
-    method public java.util.List<android.media.MediaItem2> onGetChildren(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
-    method public android.media.MediaItem2 onGetItem(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String);
-    method public android.media.MediaLibraryService2.LibraryRoot onGetLibraryRoot(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, android.os.Bundle);
-    method public java.util.List<android.media.MediaItem2> onGetSearchResult(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, int, int, android.os.Bundle);
-    method public void onSearch(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onSubscribe(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onUnsubscribe(android.media.MediaLibraryService2.MediaLibrarySession, android.media.MediaSession2.ControllerInfo, java.lang.String);
-  }
-
   public final class MediaMetadata implements android.os.Parcelable {
     method public boolean containsKey(java.lang.String);
     method public int describeContents();
@@ -23977,79 +23760,6 @@
     method public android.media.MediaMetadata.Builder putText(java.lang.String, java.lang.CharSequence);
   }
 
-  public final class MediaMetadata2 {
-    method public boolean containsKey(java.lang.String);
-    method public static android.media.MediaMetadata2 fromBundle(android.content.Context, android.os.Bundle);
-    method public android.graphics.Bitmap getBitmap(java.lang.String);
-    method public android.os.Bundle getExtras();
-    method public float getFloat(java.lang.String);
-    method public long getLong(java.lang.String);
-    method public java.lang.String getMediaId();
-    method public android.media.Rating2 getRating(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.CharSequence getText(java.lang.String);
-    method public java.util.Set<java.lang.String> keySet();
-    method public int size();
-    method public android.os.Bundle toBundle();
-    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
-    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
-    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
-    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
-    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
-    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
-    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
-    field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
-    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
-    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
-    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
-    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-    field public static final java.lang.String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
-    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-    field public static final java.lang.String METADATA_KEY_EXTRAS = "android.media.metadata.EXTRAS";
-    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-    field public static final java.lang.String METADATA_KEY_RADIO_CALLSIGN = "android.media.metadata.RADIO_CALLSIGN";
-    field public static final java.lang.String METADATA_KEY_RADIO_FREQUENCY = "android.media.metadata.RADIO_FREQUENCY";
-    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
-    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
-    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
-    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
-  }
-
-  public static final class MediaMetadata2.Builder {
-    ctor public MediaMetadata2.Builder(android.content.Context);
-    ctor public MediaMetadata2.Builder(android.content.Context, android.media.MediaMetadata2);
-    method public android.media.MediaMetadata2 build();
-    method public android.media.MediaMetadata2.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
-    method public android.media.MediaMetadata2.Builder putFloat(java.lang.String, float);
-    method public android.media.MediaMetadata2.Builder putLong(java.lang.String, long);
-    method public android.media.MediaMetadata2.Builder putRating(java.lang.String, android.media.Rating2);
-    method public android.media.MediaMetadata2.Builder putString(java.lang.String, java.lang.String);
-    method public android.media.MediaMetadata2.Builder putText(java.lang.String, java.lang.CharSequence);
-    method public android.media.MediaMetadata2.Builder setExtras(android.os.Bundle);
-  }
-
   public abstract deprecated class MediaMetadataEditor {
     method public synchronized void addEditableKey(int);
     method public abstract void apply();
@@ -24368,263 +24078,6 @@
     field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
   }
 
-  public abstract class MediaPlayer2 extends android.media.MediaPlayerBase implements android.media.AudioRouting {
-    method public abstract void attachAuxEffect(int);
-    method public abstract void clearDrmEventCallback();
-    method public abstract void clearMediaPlayer2EventCallback();
-    method public abstract void clearPendingCommands();
-    method public abstract void close();
-    method public static final android.media.MediaPlayer2 create();
-    method public abstract void deselectTrack(int);
-    method public abstract int getAudioSessionId();
-    method public abstract long getBufferedPosition();
-    method public abstract long getCurrentPosition();
-    method public abstract android.media.MediaPlayer2.DrmInfo getDrmInfo();
-    method public abstract android.media.MediaDrm.KeyRequest getDrmKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
-    method public abstract java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
-    method public abstract long getDuration();
-    method public abstract android.os.PersistableBundle getMetrics();
-    method public abstract android.media.PlaybackParams getPlaybackParams();
-    method public abstract int getSelectedTrack(int);
-    method public abstract android.media.SyncParams getSyncParams();
-    method public abstract android.media.MediaTimestamp getTimestamp();
-    method public abstract java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo();
-    method public abstract int getVideoHeight();
-    method public abstract int getVideoWidth();
-    method public void notifyWhenCommandLabelReached(java.lang.Object);
-    method public abstract void prepareDrm(java.util.UUID) throws android.media.MediaPlayer2.ProvisioningNetworkErrorException, android.media.MediaPlayer2.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
-    method public abstract byte[] provideDrmKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException;
-    method public abstract void releaseDrm() throws android.media.MediaPlayer2.NoDrmSchemeException;
-    method public abstract void restoreDrmKeys(byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException;
-    method public void seekTo(long);
-    method public abstract void seekTo(long, int);
-    method public abstract void selectTrack(int);
-    method public abstract void setAudioSessionId(int);
-    method public abstract void setAuxEffectSendLevel(float);
-    method public abstract void setDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
-    method public abstract void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer2.NoDrmSchemeException;
-    method public abstract void setMediaPlayer2EventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.MediaPlayer2EventCallback);
-    method public abstract void setOnDrmConfigHelper(android.media.MediaPlayer2.OnDrmConfigHelper);
-    method public abstract void setPlaybackParams(android.media.PlaybackParams);
-    method public abstract void setSurface(android.view.Surface);
-    method public abstract void setSyncParams(android.media.SyncParams);
-    field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1
-    field public static final int CALL_COMPLETED_DESELECT_TRACK = 2; // 0x2
-    field public static final int CALL_COMPLETED_LOOP_CURRENT = 3; // 0x3
-    field public static final int CALL_COMPLETED_PAUSE = 4; // 0x4
-    field public static final int CALL_COMPLETED_PLAY = 5; // 0x5
-    field public static final int CALL_COMPLETED_PREPARE = 6; // 0x6
-    field public static final int CALL_COMPLETED_RELEASE_DRM = 12; // 0xc
-    field public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13; // 0xd
-    field public static final int CALL_COMPLETED_SEEK_TO = 14; // 0xe
-    field public static final int CALL_COMPLETED_SELECT_TRACK = 15; // 0xf
-    field public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16; // 0x10
-    field public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17; // 0x11
-    field public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
-    field public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19; // 0x13
-    field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22; // 0x16
-    field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23; // 0x17
-    field public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; // 0x18
-    field public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25; // 0x19
-    field public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26; // 0x1a
-    field public static final int CALL_COMPLETED_SET_SURFACE = 27; // 0x1b
-    field public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28; // 0x1c
-    field public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; // 0x1d
-    field public static final int CALL_STATUS_BAD_VALUE = 2; // 0x2
-    field public static final int CALL_STATUS_ERROR_IO = 4; // 0x4
-    field public static final int CALL_STATUS_ERROR_UNKNOWN = -2147483648; // 0x80000000
-    field public static final int CALL_STATUS_INVALID_OPERATION = 1; // 0x1
-    field public static final int CALL_STATUS_NO_DRM_SCHEME = 5; // 0x5
-    field public static final int CALL_STATUS_NO_ERROR = 0; // 0x0
-    field public static final int CALL_STATUS_PERMISSION_DENIED = 3; // 0x3
-    field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14
-    field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11
-    field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8
-    field public static final int MEDIA_ERROR_TIMED_OUT = -110; // 0xffffff92
-    field public static final int MEDIA_ERROR_UNKNOWN = 1; // 0x1
-    field public static final int MEDIA_ERROR_UNSUPPORTED = -1010; // 0xfffffc0e
-    field public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804; // 0x324
-    field public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4; // 0x4
-    field public static final int MEDIA_INFO_BAD_INTERLEAVING = 800; // 0x320
-    field public static final int MEDIA_INFO_BUFFERING_END = 702; // 0x2be
-    field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
-    field public static final int MEDIA_INFO_BUFFERING_UPDATE = 704; // 0x2c0
-    field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322
-    field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321
-    field public static final int MEDIA_INFO_PLAYBACK_COMPLETE = 5; // 0x5
-    field public static final int MEDIA_INFO_PLAYLIST_END = 6; // 0x6
-    field public static final int MEDIA_INFO_PREPARED = 100; // 0x64
-    field public static final int MEDIA_INFO_STARTED_AS_NEXT = 2; // 0x2
-    field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386
-    field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1
-    field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385
-    field public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805; // 0x325
-    field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
-    field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
-    field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
-    field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
-    field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
-    field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0
-    field public static final int SEEK_CLOSEST = 3; // 0x3
-    field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
-    field public static final int SEEK_NEXT_SYNC = 1; // 0x1
-    field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
-    field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
-  }
-
-  public static abstract class MediaPlayer2.DrmEventCallback {
-    ctor public MediaPlayer2.DrmEventCallback();
-    method public void onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
-    method public void onDrmPrepared(android.media.MediaPlayer2, android.media.DataSourceDesc, int);
-  }
-
-  public static abstract class MediaPlayer2.DrmInfo {
-    ctor public MediaPlayer2.DrmInfo();
-    method public abstract java.util.Map<java.util.UUID, byte[]> getPssh();
-    method public abstract java.util.List<java.util.UUID> getSupportedSchemes();
-  }
-
-  public static abstract class MediaPlayer2.MediaPlayer2EventCallback {
-    ctor public MediaPlayer2.MediaPlayer2EventCallback();
-    method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object);
-    method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onMediaTimeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaTimestamp);
-    method public void onTimedMetaDataAvailable(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.TimedMetaData);
-    method public void onVideoSizeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-  }
-
-  public static final class MediaPlayer2.MetricsConstants {
-    field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
-    field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
-    field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs";
-    field public static final java.lang.String ERRORS = "android.media.mediaplayer.err";
-    field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode";
-    field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames";
-    field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
-    field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height";
-    field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
-    field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
-    field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs";
-    field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
-  }
-
-  public static abstract class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
-    ctor protected MediaPlayer2.NoDrmSchemeException(java.lang.String);
-  }
-
-  public static abstract interface MediaPlayer2.OnDrmConfigHelper {
-    method public abstract void onDrmConfig(android.media.MediaPlayer2, android.media.DataSourceDesc);
-  }
-
-  public static abstract class MediaPlayer2.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
-    ctor protected MediaPlayer2.ProvisioningNetworkErrorException(java.lang.String);
-  }
-
-  public static abstract class MediaPlayer2.ProvisioningServerErrorException extends android.media.MediaDrmException {
-    ctor protected MediaPlayer2.ProvisioningServerErrorException(java.lang.String);
-  }
-
-  public static abstract class MediaPlayer2.TrackInfo {
-    ctor public MediaPlayer2.TrackInfo();
-    method public abstract android.media.MediaFormat getFormat();
-    method public abstract java.lang.String getLanguage();
-    method public abstract int getTrackType();
-    method public abstract java.lang.String toString();
-    field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
-    field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5
-    field public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4; // 0x4
-    field public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0; // 0x0
-    field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
-  }
-
-  public abstract class MediaPlayerBase implements java.lang.AutoCloseable {
-    ctor public MediaPlayerBase();
-    method public abstract android.media.AudioAttributes getAudioAttributes();
-    method public long getBufferedPosition();
-    method public abstract int getBufferingState();
-    method public abstract android.media.DataSourceDesc getCurrentDataSource();
-    method public long getCurrentPosition();
-    method public long getDuration();
-    method public float getMaxPlayerVolume();
-    method public float getPlaybackSpeed();
-    method public abstract int getPlayerState();
-    method public abstract float getPlayerVolume();
-    method public boolean isReversePlaybackSupported();
-    method public abstract void loopCurrent(boolean);
-    method public abstract void pause();
-    method public abstract void play();
-    method public abstract void prepare();
-    method public abstract void registerPlayerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayerBase.PlayerEventCallback);
-    method public abstract void reset();
-    method public abstract void seekTo(long);
-    method public abstract void setAudioAttributes(android.media.AudioAttributes);
-    method public abstract void setDataSource(android.media.DataSourceDesc);
-    method public abstract void setNextDataSource(android.media.DataSourceDesc);
-    method public abstract void setNextDataSources(java.util.List<android.media.DataSourceDesc>);
-    method public abstract void setPlaybackSpeed(float);
-    method public abstract void setPlayerVolume(float);
-    method public abstract void skipToNext();
-    method public abstract void unregisterPlayerEventCallback(android.media.MediaPlayerBase.PlayerEventCallback);
-    field public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1; // 0x1
-    field public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2; // 0x2
-    field public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3; // 0x3
-    field public static final int BUFFERING_STATE_UNKNOWN = 0; // 0x0
-    field public static final int PLAYER_STATE_ERROR = 3; // 0x3
-    field public static final int PLAYER_STATE_IDLE = 0; // 0x0
-    field public static final int PLAYER_STATE_PAUSED = 1; // 0x1
-    field public static final int PLAYER_STATE_PLAYING = 2; // 0x2
-    field public static final long UNKNOWN_TIME = -1L; // 0xffffffffffffffffL
-  }
-
-  public static abstract class MediaPlayerBase.PlayerEventCallback {
-    ctor public MediaPlayerBase.PlayerEventCallback();
-    method public void onBufferingStateChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc, int);
-    method public void onCurrentDataSourceChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc);
-    method public void onMediaPrepared(android.media.MediaPlayerBase, android.media.DataSourceDesc);
-    method public void onPlayerStateChanged(android.media.MediaPlayerBase, int);
-  }
-
-  public abstract class MediaPlaylistAgent {
-    ctor public MediaPlaylistAgent(android.content.Context);
-    method public void addPlaylistItem(int, android.media.MediaItem2);
-    method public java.util.List<android.media.MediaItem2> getPlaylist();
-    method public android.media.MediaMetadata2 getPlaylistMetadata();
-    method public int getRepeatMode();
-    method public int getShuffleMode();
-    method public final void notifyPlaylistChanged();
-    method public final void notifyPlaylistMetadataChanged();
-    method public final void notifyRepeatModeChanged();
-    method public final void notifyShuffleModeChanged();
-    method public final void registerPlaylistEventCallback(java.util.concurrent.Executor, android.media.MediaPlaylistAgent.PlaylistEventCallback);
-    method public void removePlaylistItem(android.media.MediaItem2);
-    method public void replacePlaylistItem(int, android.media.MediaItem2);
-    method public void setPlaylist(java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void setRepeatMode(int);
-    method public void setShuffleMode(int);
-    method public void skipToNextItem();
-    method public void skipToPlaylistItem(android.media.MediaItem2);
-    method public void skipToPreviousItem();
-    method public final void unregisterPlaylistEventCallback(android.media.MediaPlaylistAgent.PlaylistEventCallback);
-    method public void updatePlaylistMetadata(android.media.MediaMetadata2);
-    field public static final int REPEAT_MODE_ALL = 2; // 0x2
-    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
-    field public static final int REPEAT_MODE_NONE = 0; // 0x0
-    field public static final int REPEAT_MODE_ONE = 1; // 0x1
-    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
-    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
-    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
-  }
-
-  public static abstract class MediaPlaylistAgent.PlaylistEventCallback {
-    ctor public MediaPlaylistAgent.PlaylistEventCallback();
-    method public void onPlaylistChanged(android.media.MediaPlaylistAgent, java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void onPlaylistMetadataChanged(android.media.MediaPlaylistAgent, android.media.MediaMetadata2);
-    method public void onRepeatModeChanged(android.media.MediaPlaylistAgent, int);
-    method public void onShuffleModeChanged(android.media.MediaPlaylistAgent, int);
-  }
-
   public class MediaRecorder implements android.media.AudioRouting {
     ctor public MediaRecorder();
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -24901,187 +24354,6 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
-  public class MediaSession2 implements java.lang.AutoCloseable {
-    method public void addPlaylistItem(int, android.media.MediaItem2);
-    method public void clearOnDataSourceMissingHelper();
-    method public void close();
-    method public void fastForward();
-    method public java.util.List<android.media.MediaSession2.ControllerInfo> getConnectedControllers();
-    method public android.media.MediaItem2 getCurrentMediaItem();
-    method public float getPlaybackSpeed();
-    method public android.media.MediaPlayerBase getPlayer();
-    method public java.util.List<android.media.MediaItem2> getPlaylist();
-    method public android.media.MediaPlaylistAgent getPlaylistAgent();
-    method public android.media.MediaMetadata2 getPlaylistMetadata();
-    method public int getRepeatMode();
-    method public int getShuffleMode();
-    method public android.media.SessionToken2 getToken();
-    method public android.media.VolumeProvider2 getVolumeProvider();
-    method public void notifyError(int, android.os.Bundle);
-    method public void pause();
-    method public void play();
-    method public void prepare();
-    method public void removePlaylistItem(android.media.MediaItem2);
-    method public void replacePlaylistItem(int, android.media.MediaItem2);
-    method public void rewind();
-    method public void seekTo(long);
-    method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle);
-    method public void sendCustomCommand(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
-    method public void setAllowedCommands(android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.CommandGroup);
-    method public void setAudioFocusRequest(android.media.AudioFocusRequest);
-    method public void setCustomLayout(android.media.MediaSession2.ControllerInfo, java.util.List<android.media.MediaSession2.CommandButton>);
-    method public void setOnDataSourceMissingHelper(android.media.MediaSession2.OnDataSourceMissingHelper);
-    method public void setPlaybackSpeed(float);
-    method public void setPlaylist(java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void setRepeatMode(int);
-    method public void setShuffleMode(int);
-    method public void skipToNextItem();
-    method public void skipToPlaylistItem(android.media.MediaItem2);
-    method public void skipToPreviousItem();
-    method public void stop();
-    method public void updatePlayer(android.media.MediaPlayerBase, android.media.MediaPlaylistAgent, android.media.VolumeProvider2);
-    method public void updatePlaylistMetadata(android.media.MediaMetadata2);
-    field public static final int COMMAND_CODE_BROWSER = 28; // 0x1c
-    field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
-    field public static final int COMMAND_CODE_PLAYBACK_ADJUST_VOLUME = 11; // 0xb
-    field public static final int COMMAND_CODE_PLAYBACK_FAST_FORWARD = 7; // 0x7
-    field public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2; // 0x2
-    field public static final int COMMAND_CODE_PLAYBACK_PLAY = 1; // 0x1
-    field public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6; // 0x6
-    field public static final int COMMAND_CODE_PLAYBACK_REWIND = 8; // 0x8
-    field public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9; // 0x9
-    field public static final int COMMAND_CODE_PLAYBACK_SET_VOLUME = 10; // 0xa
-    field public static final int COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM = 4; // 0x4
-    field public static final int COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM = 5; // 0x5
-    field public static final int COMMAND_CODE_PLAYBACK_STOP = 3; // 0x3
-    field public static final int COMMAND_CODE_PLAYLIST_ADD_ITEM = 15; // 0xf
-    field public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18; // 0x12
-    field public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20; // 0x14
-    field public static final int COMMAND_CODE_PLAYLIST_REMOVE_ITEM = 16; // 0x10
-    field public static final int COMMAND_CODE_PLAYLIST_REPLACE_ITEM = 17; // 0x11
-    field public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19; // 0x13
-    field public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21; // 0x15
-    field public static final int COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE = 14; // 0xe
-    field public static final int COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE = 13; // 0xd
-    field public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM = 12; // 0xc
-    field public static final int COMMAND_CODE_PLAY_FROM_MEDIA_ID = 22; // 0x16
-    field public static final int COMMAND_CODE_PLAY_FROM_SEARCH = 24; // 0x18
-    field public static final int COMMAND_CODE_PLAY_FROM_URI = 23; // 0x17
-    field public static final int COMMAND_CODE_PREPARE_FROM_MEDIA_ID = 25; // 0x19
-    field public static final int COMMAND_CODE_PREPARE_FROM_SEARCH = 27; // 0x1b
-    field public static final int COMMAND_CODE_PREPARE_FROM_URI = 26; // 0x1a
-    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
-    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
-    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
-    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
-    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
-    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
-    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
-    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
-    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
-    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
-    field public static final int ERROR_CODE_SETUP_REQUIRED = 12; // 0xc
-    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
-    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
-  }
-
-  public static final class MediaSession2.Builder {
-    ctor public MediaSession2.Builder(android.content.Context);
-    method public android.media.MediaSession2 build();
-    method public android.media.MediaSession2.Builder setId(java.lang.String);
-    method public android.media.MediaSession2.Builder setPlayer(android.media.MediaPlayerBase);
-    method public android.media.MediaSession2.Builder setPlaylistAgent(android.media.MediaPlaylistAgent);
-    method public android.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent);
-    method public android.media.MediaSession2.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaSession2.SessionCallback);
-    method public android.media.MediaSession2.Builder setVolumeProvider(android.media.VolumeProvider2);
-  }
-
-  public static final class MediaSession2.Command {
-    ctor public MediaSession2.Command(android.content.Context, int);
-    ctor public MediaSession2.Command(android.content.Context, java.lang.String, android.os.Bundle);
-    method public int getCommandCode();
-    method public java.lang.String getCustomCommand();
-    method public android.os.Bundle getExtras();
-  }
-
-  public static final class MediaSession2.CommandButton {
-    method public android.media.MediaSession2.Command getCommand();
-    method public java.lang.String getDisplayName();
-    method public android.os.Bundle getExtras();
-    method public int getIconResId();
-    method public boolean isEnabled();
-  }
-
-  public static final class MediaSession2.CommandButton.Builder {
-    ctor public MediaSession2.CommandButton.Builder(android.content.Context);
-    method public android.media.MediaSession2.CommandButton build();
-    method public android.media.MediaSession2.CommandButton.Builder setCommand(android.media.MediaSession2.Command);
-    method public android.media.MediaSession2.CommandButton.Builder setDisplayName(java.lang.String);
-    method public android.media.MediaSession2.CommandButton.Builder setEnabled(boolean);
-    method public android.media.MediaSession2.CommandButton.Builder setExtras(android.os.Bundle);
-    method public android.media.MediaSession2.CommandButton.Builder setIconResId(int);
-  }
-
-  public static final class MediaSession2.CommandGroup {
-    ctor public MediaSession2.CommandGroup(android.content.Context);
-    ctor public MediaSession2.CommandGroup(android.content.Context, android.media.MediaSession2.CommandGroup);
-    method public void addAllPredefinedCommands();
-    method public void addCommand(android.media.MediaSession2.Command);
-    method public java.util.List<android.media.MediaSession2.Command> getCommands();
-    method public boolean hasCommand(android.media.MediaSession2.Command);
-    method public boolean hasCommand(int);
-    method public void removeCommand(android.media.MediaSession2.Command);
-  }
-
-  public static final class MediaSession2.ControllerInfo {
-    method public java.lang.String getPackageName();
-    method public int getUid();
-    method public boolean isTrusted();
-  }
-
-  public static abstract interface MediaSession2.OnDataSourceMissingHelper {
-    method public abstract android.media.DataSourceDesc onDataSourceMissing(android.media.MediaSession2, android.media.MediaItem2);
-  }
-
-  public static abstract class MediaSession2.SessionCallback {
-    ctor public MediaSession2.SessionCallback(android.content.Context);
-    method public void onBufferingStateChanged(android.media.MediaSession2, android.media.MediaPlayerBase, android.media.MediaItem2, int);
-    method public boolean onCommandRequest(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command);
-    method public android.media.MediaSession2.CommandGroup onConnect(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
-    method public void onCurrentMediaItemChanged(android.media.MediaSession2, android.media.MediaPlayerBase, android.media.MediaItem2);
-    method public void onCustomCommand(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver);
-    method public void onDisconnected(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
-    method public void onMediaPrepared(android.media.MediaSession2, android.media.MediaPlayerBase, android.media.MediaItem2);
-    method public void onPlayFromMediaId(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onPlayFromSearch(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onPlayFromUri(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
-    method public void onPlayerStateChanged(android.media.MediaSession2, android.media.MediaPlayerBase, int);
-    method public void onPlaylistChanged(android.media.MediaSession2, android.media.MediaPlaylistAgent, java.util.List<android.media.MediaItem2>, android.media.MediaMetadata2);
-    method public void onPlaylistMetadataChanged(android.media.MediaSession2, android.media.MediaPlaylistAgent, android.media.MediaMetadata2);
-    method public void onPrepareFromMediaId(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onPrepareFromSearch(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
-    method public void onPrepareFromUri(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
-    method public void onRepeatModeChanged(android.media.MediaSession2, android.media.MediaPlaylistAgent, int);
-    method public void onSetRating(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.String, android.media.Rating2);
-    method public void onShuffleModeChanged(android.media.MediaSession2, android.media.MediaPlaylistAgent, int);
-  }
-
-  public abstract class MediaSessionService2 extends android.app.Service {
-    ctor public MediaSessionService2();
-    method public final android.media.MediaSession2 getSession();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.media.MediaSession2 onCreateSession(java.lang.String);
-    method public android.media.MediaSessionService2.MediaNotification onUpdateNotification();
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.MediaSessionService2";
-    field public static final java.lang.String SERVICE_META_DATA = "android.media.session";
-  }
-
-  public static class MediaSessionService2.MediaNotification {
-    ctor public MediaSessionService2.MediaNotification(android.content.Context, int, android.app.Notification);
-    method public android.app.Notification getNotification();
-    method public int getNotificationId();
-  }
-
   public final class MediaSync {
     ctor public MediaSync();
     method public android.view.Surface createInputSurface();
@@ -25374,22 +24646,6 @@
     field public static final int URI_COLUMN_INDEX = 2; // 0x2
   }
 
-  public final class SessionToken2 {
-    ctor public SessionToken2(android.content.Context, java.lang.String, java.lang.String);
-    method public static android.media.SessionToken2 fromBundle(android.content.Context, android.os.Bundle);
-    method public java.lang.String getId();
-    method public java.lang.String getPackageName();
-    method public int getType();
-    method public int getUid();
-    method public android.os.Bundle toBundle();
-    field public static final int TYPE_LIBRARY_SERVICE = 2; // 0x2
-    field public static final int TYPE_SESSION = 0; // 0x0
-    field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
-  }
-
-  public static abstract class SessionToken2.TokenType implements java.lang.annotation.Annotation {
-  }
-
   public class SoundPool {
     ctor public deprecated SoundPool(int, int, int);
     method public final void autoPause();
@@ -25593,19 +24849,6 @@
     field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
   }
 
-  public abstract class VolumeProvider2 {
-    ctor public VolumeProvider2(android.content.Context, int, int, int);
-    method public final int getControlType();
-    method public final int getCurrentVolume();
-    method public final int getMaxVolume();
-    method public void onAdjustVolume(int);
-    method public void onSetVolumeTo(int);
-    method public final void setCurrentVolume(int);
-    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
-    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
-    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
-  }
-
   public final class VolumeShaper implements java.lang.AutoCloseable {
     method public void apply(android.media.VolumeShaper.Operation);
     method public void close();
@@ -26548,23 +25791,14 @@
   public final class MediaSessionManager {
     method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
     method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler);
-    method public void addOnSessionTokensChangedListener(java.util.concurrent.Executor, android.media.session.MediaSessionManager.OnSessionTokensChangedListener);
-    method public java.util.List<android.media.SessionToken2> getActiveSessionTokens();
     method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
-    method public java.util.List<android.media.SessionToken2> getAllSessionTokens();
-    method public java.util.List<android.media.SessionToken2> getSessionServiceTokens();
     method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
-    method public void removeOnSessionTokensChangedListener(android.media.session.MediaSessionManager.OnSessionTokensChangedListener);
   }
 
   public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
     method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
   }
 
-  public static abstract interface MediaSessionManager.OnSessionTokensChangedListener {
-    method public abstract void onSessionTokensChanged(java.util.List<android.media.SessionToken2>);
-  }
-
   public final class PlaybackState implements android.os.Parcelable {
     method public int describeContents();
     method public long getActions();
@@ -41427,7 +40661,7 @@
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
     field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
     field public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2; // 0x2
-    field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4; // 0x4
+    field public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4; // 0x4
     field public static final int HANDOVER_FAILURE_UNKNOWN = 5; // 0x5
     field public static final int HANDOVER_FAILURE_USER_REJECTED = 3; // 0x3
   }
@@ -44063,7 +43297,7 @@
     method public abstract int getSpanTypeId();
   }
 
-  public class PrecomputedText implements android.text.Spanned {
+  public class PrecomputedText implements android.text.Spannable {
     method public char charAt(int);
     method public static android.text.PrecomputedText create(java.lang.CharSequence, android.text.PrecomputedText.Params);
     method public int getParagraphCount();
@@ -44077,6 +43311,8 @@
     method public java.lang.CharSequence getText();
     method public int length();
     method public int nextSpanTransition(int, int, java.lang.Class);
+    method public void removeSpan(java.lang.Object);
+    method public void setSpan(java.lang.Object, int, int, int);
     method public java.lang.CharSequence subSequence(int, int);
   }
 
@@ -51597,7 +50833,6 @@
     field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
     field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
     field public static final int RECORD_UNTIL_FULL = 0; // 0x0
-    field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
   }
 
   public static class TracingConfig.Builder {
@@ -53440,20 +52675,6 @@
     method public void update();
   }
 
-  public class MediaControlView2 extends android.view.ViewGroup {
-    ctor public MediaControlView2(android.content.Context);
-    ctor public MediaControlView2(android.content.Context, android.util.AttributeSet);
-    ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int);
-    ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int, int);
-    method public void requestPlayButtonFocus();
-    method public void setMediaSessionToken(android.media.SessionToken2);
-    method public void setOnFullScreenListener(android.widget.MediaControlView2.OnFullScreenListener);
-  }
-
-  public static abstract interface MediaControlView2.OnFullScreenListener {
-    method public abstract void onFullScreen(android.view.View, boolean);
-  }
-
   public class MediaController extends android.widget.FrameLayout {
     ctor public MediaController(android.content.Context, android.util.AttributeSet);
     ctor public MediaController(android.content.Context, boolean);
@@ -54844,27 +54065,6 @@
     method public void suspend();
   }
 
-  public class VideoView2 extends android.view.ViewGroup {
-    ctor public VideoView2(android.content.Context);
-    ctor public VideoView2(android.content.Context, android.util.AttributeSet);
-    ctor public VideoView2(android.content.Context, android.util.AttributeSet, int);
-    ctor public VideoView2(android.content.Context, android.util.AttributeSet, int, int);
-    method public android.widget.MediaControlView2 getMediaControlView2();
-    method public android.media.SessionToken2 getMediaSessionToken();
-    method public int getViewType();
-    method public boolean isSubtitleEnabled();
-    method public void setAudioAttributes(android.media.AudioAttributes);
-    method public void setAudioFocusRequest(int);
-    method public void setDataSource(android.media.DataSourceDesc);
-    method public void setMediaControlView2(android.widget.MediaControlView2, long);
-    method public void setMediaItem(android.media.MediaItem2);
-    method public void setSpeed(float);
-    method public void setSubtitleEnabled(boolean);
-    method public void setViewType(int);
-    field public static final int VIEW_TYPE_SURFACEVIEW = 1; // 0x1
-    field public static final int VIEW_TYPE_TEXTUREVIEW = 2; // 0x2
-  }
-
   public class ViewAnimator extends android.widget.FrameLayout {
     ctor public ViewAnimator(android.content.Context);
     ctor public ViewAnimator(android.content.Context, android.util.AttributeSet);
diff --git a/api/removed.txt b/api/removed.txt
index a5370f4..1228fd1 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -155,6 +155,13 @@
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public deprecated boolean getAsAlphaMask();
     method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
+    field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1
+    field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
+  }
+
+  public static deprecated class ImageDecoder.IncompleteException extends java.io.IOException {
+    ctor public ImageDecoder.IncompleteException();
   }
 
   public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
diff --git a/api/system-current.txt b/api/system-current.txt
index 1e2fe3d..fa32383 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -100,6 +100,7 @@
     field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+    field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
     field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
     field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
@@ -181,6 +182,7 @@
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
+    field public static final java.lang.String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -207,7 +209,7 @@
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
-    field public static final int userRestriction = 16844165; // 0x1010585
+    field public static final int userRestriction = 16844164; // 0x1010584
   }
 
   public static final class R.raw {
@@ -283,6 +285,7 @@
     field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final java.lang.String OPSTR_GPS = "android:gps";
     field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
     field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
@@ -1016,15 +1019,19 @@
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
     method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public android.os.PersistableBundle getSuspendedPackageAppExtras(java.lang.String);
     method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isPackageSuspended(java.lang.String);
     method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
     method public abstract void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
     method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
     method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
+    method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
+    method public void setSuspendedPackageAppExtras(java.lang.String, android.os.PersistableBundle);
     method public abstract void setUpdateAvailable(java.lang.String, boolean);
     method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
     method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
@@ -3067,8 +3074,10 @@
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+    method public void addAddress(android.net.LinkAddress) throws java.io.IOException;
     method public void close();
     method public java.lang.String getInterfaceName();
+    method public void removeAddress(android.net.LinkAddress) throws java.io.IOException;
   }
 
   public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -4234,7 +4243,7 @@
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
     method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
-    field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
+    field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
     field public static final java.lang.String CARRIER_APP_NAMES = "carrier_app_names";
     field public static final java.lang.String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
     field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
@@ -4309,7 +4318,6 @@
     method public int getUserSecretType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainProtectionParams> CREATOR;
-    field public static final int TYPE_CUSTOM_PASSWORD = 101; // 0x65
     field public static final int TYPE_LOCKSCREEN = 100; // 0x64
     field public static final int UI_FORMAT_PASSWORD = 2; // 0x2
     field public static final int UI_FORMAT_PATTERN = 3; // 0x3
@@ -4364,15 +4372,14 @@
     method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
     method public java.security.Key getKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
     method public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public java.util.Map<java.lang.String, java.security.cert.X509Certificate> getRootCertificates();
     method public java.security.Key importKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
     method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
@@ -4386,9 +4393,11 @@
 
   public class RecoverySession implements java.lang.AutoCloseable {
     method public void close();
-    method public java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method public java.util.Map<java.lang.String, java.security.Key> recoverKeyChainSnapshot(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method public deprecated java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
     method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public deprecated byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public byte[] start(java.lang.String, java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
   }
 
   public class SessionExpiredException extends java.security.GeneralSecurityException {
diff --git a/api/test-current.txt b/api/test-current.txt
index 70e3cf3..dd16771 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -79,6 +79,7 @@
     field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final java.lang.String OPSTR_GPS = "android:gps";
     field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
     field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
@@ -294,6 +295,14 @@
 
 }
 
+package android.graphics {
+
+  public final class ImageDecoder implements java.lang.AutoCloseable {
+    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+  }
+
+}
+
 package android.graphics.drawable {
 
   public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -407,20 +416,20 @@
     ctor public GnssMeasurement();
     method public void reset();
     method public void resetAutomaticGainControlLevel();
-    method public void resetCarrierCycles();
+    method public deprecated void resetCarrierCycles();
     method public void resetCarrierFrequencyHz();
-    method public void resetCarrierPhase();
-    method public void resetCarrierPhaseUncertainty();
+    method public deprecated void resetCarrierPhase();
+    method public deprecated void resetCarrierPhaseUncertainty();
     method public void resetSnrInDb();
     method public void set(android.location.GnssMeasurement);
     method public void setAccumulatedDeltaRangeMeters(double);
     method public void setAccumulatedDeltaRangeState(int);
     method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setAutomaticGainControlLevelInDb(double);
-    method public void setCarrierCycles(long);
+    method public deprecated void setCarrierCycles(long);
     method public void setCarrierFrequencyHz(float);
-    method public void setCarrierPhase(double);
-    method public void setCarrierPhaseUncertainty(double);
+    method public deprecated void setCarrierPhase(double);
+    method public deprecated void setCarrierPhaseUncertainty(double);
     method public void setCn0DbHz(double);
     method public void setConstellationType(int);
     method public void setMultipathIndicator(int);
@@ -432,6 +441,7 @@
     method public void setState(int);
     method public void setSvid(int);
     method public void setTimeOffsetNanos(double);
+    field public static final int ADR_STATE_ALL = 31; // 0x1f
   }
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -570,7 +580,7 @@
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
-    field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
+    field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
     field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
     field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final java.lang.String LOW_POWER_MODE = "low_power";
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index ca0611b..79c0d71 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -135,6 +135,12 @@
 
 LOCAL_MODULE_CLASS := EXECUTABLES
 
+# Enable sanitizer on eng builds
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+    LOCAL_CLANG := true
+    LOCAL_SANITIZE := address
+endif
+
 LOCAL_INIT_RC := statsd.rc
 
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index d85157c..79067eb 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -68,10 +68,10 @@
     if (itr->second != nullptr && timestampNs >= NS_PER_SEC * itr->second->timestampSec) {
         declareAnomaly(timestampNs, dimensionKey);
     }
-    mAlarms.erase(dimensionKey);
     if (mAlarmMonitor != nullptr) {
         mAlarmMonitor->remove(itr->second);
     }
+    mAlarms.erase(dimensionKey);
 }
 
 void DurationAnomalyTracker::cancelAllAlarms() {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 40eff4c..99611f4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -23,6 +23,7 @@
 
 import "frameworks/base/cmds/statsd/src/atom_field_options.proto";
 import "frameworks/base/core/proto/android/app/enums.proto";
+import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
@@ -362,7 +363,10 @@
     }
     optional State state = 3;
 
-    // TODO: Consider adding the stopReason (int)
+    // The reason a job has stopped.
+    // This is only applicable when the state is FINISHED.
+    // The default value is CANCELED.
+    optional android.app.job.StopReasonEnum stop_reason = 4;
 }
 
 /**
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 335ec4c..c9547cf 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -205,11 +205,12 @@
     bool hasPendingEvent =
             false;  // has either a kStarted or kPaused event across bucket boundaries
     // meaning we need to carry them over to the new bucket.
-    for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
+    for (auto it = mInfos.begin(); it != mInfos.end();) {
         if (it->second.state == DurationState::kStopped) {
             // No need to keep buckets for events that were stopped before.
-            mInfos.erase(it);
+            it = mInfos.erase(it);
         } else {
+            ++it;
             hasPendingEvent = true;
         }
     }
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 3ba4b7a..1cb20bc 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -365,7 +365,8 @@
             count++;
             proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
                          (long long)record.timestampNs);
-            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
+            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data(),
+                         record.bytes.size());
             proto->end(snapshotsToken);
         }
     }
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 3d8aa47..643d2bf 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -167,8 +167,7 @@
         return;
     }
 
-    const char* suffix =
-            StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()).c_str();
+    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
 
     dirent* de;
     while ((de = readdir(dir.get()))) {
@@ -176,9 +175,9 @@
         if (name[0] == '.') continue;
 
         size_t nameLen = strlen(name);
-        size_t suffixLen = strlen(suffix);
+        size_t suffixLen = suffix.length();
         if (suffixLen <= nameLen &&
-                strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
+            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
             int64_t result[3];
             parseFileName(name, result);
             if (result[0] == -1) continue;
@@ -262,8 +261,7 @@
         return false;
     }
 
-    const char* suffix =
-            StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()).c_str();
+    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
 
     dirent* de;
     while ((de = readdir(dir.get()))) {
@@ -272,10 +270,10 @@
             continue;
         }
         size_t nameLen = strlen(name);
-        size_t suffixLen = strlen(suffix);
+        size_t suffixLen = suffix.length();
         // There can be at most one file that matches this suffix (config key).
         if (suffixLen <= nameLen &&
-                strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
+            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
             int fd = open(StringPrintf("%s/%s", STATS_SERVICE_DIR, name).c_str(),
                                   O_RDONLY | O_CLOEXEC);
             if (fd != -1) {
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 40b266f..87fb998 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -3375,8 +3375,6 @@
 HPLandroid/location/ICountryListener$Stub;->asBinder()Landroid/os/IBinder;
 HPLandroid/location/ICountryListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryListener;
 HPLandroid/location/ICountryListener;->onCountryDetected(Landroid/location/Country;)V
-HPLandroid/location/IFusedProvider$Stub;-><init>()V
-HPLandroid/location/IFusedProvider;->onFusedLocationHardwareChange(Landroid/hardware/location/IFusedLocationHardware;)V
 HPLandroid/location/IGeocodeProvider$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 HPLandroid/location/IGeocodeProvider$Stub$Proxy;->getFromLocation(DDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
 HPLandroid/location/IGeocodeProvider$Stub;-><init>()V
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index e238f06..f897b13 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -669,7 +669,6 @@
 Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
 Landroid/graphics/GraphicBuffer;->mNativeObject:J
 Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
-Landroid/graphics/ImageDecoder;->onPartialImage(I)Z
 Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
 Landroid/graphics/LinearGradient;->mColors:[I
 Landroid/graphics/Matrix;->native_instance:J
@@ -823,7 +822,6 @@
 Landroid/location/Country;->getSource()I
 Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
 Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
-Landroid/location/IFusedProvider$Stub;-><init>()V
 Landroid/location/IGeocodeProvider$Stub;-><init>()V
 Landroid/location/IGeofenceProvider$Stub;-><init>()V
 Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
@@ -978,6 +976,7 @@
 Landroid/media/soundtrigger/SoundTriggerDetector$EventPayload;->getData()[B
 Landroid/media/soundtrigger/SoundTriggerManager;->loadSoundModel(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/app/PendingIntent;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
+Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UUID;Landroid/os/Bundle;Landroid/content/ComponentName;Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->stopRecognition(Ljava/util/UUID;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->unloadSoundModel(Ljava/util/UUID;)I
 Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler;
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index fe9a5db..0230ad9 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -113,7 +113,6 @@
 Landroid/hardware/display/DisplayManagerGlobal;->getRealDisplay(I)Landroid/view/Display;
 Landroid/hardware/location/GeofenceHardware;-><init>(Landroid/hardware/location/IGeofenceHardware;)V
 Landroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V
-Landroid/location/IFusedProvider;->onFusedLocationHardwareChange(Landroid/hardware/location/IFusedLocationHardware;)V
 Landroid/location/IGeocodeProvider;->getFromLocation(DDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
 Landroid/location/IGeocodeProvider;->getFromLocationName(Ljava/lang/String;DDDDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
 Landroid/location/IGeofenceProvider;->setGeofenceHardware(Landroid/hardware/location/IGeofenceHardware;)V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1d069bc..baf2d60 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -147,7 +147,7 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 import com.android.org.conscrypt.TrustedCertificateStore;
-import com.android.server.am.proto.MemInfoDumpProto;
+import com.android.server.am.MemInfoDumpProto;
 
 import dalvik.system.BaseDexClassLoader;
 import dalvik.system.CloseGuard;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4690211..ea8c71c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -270,8 +270,10 @@
     public static final int OP_BIND_ACCESSIBILITY_SERVICE = 73;
     /** @hide Continue handover of a call from another app */
     public static final int OP_ACCEPT_HANDOVER = 74;
+    /** @hide Create and Manage IPsec Tunnels */
+    public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
     /** @hide */
-    public static final int _NUM_OP = 75;
+    public static final int _NUM_OP = 76;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -507,6 +509,9 @@
     @SystemApi @TestApi
     public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE =
             "android:bind_accessibility_service";
+    /** @hide */
+    @SystemApi @TestApi
+    public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -641,6 +646,7 @@
             OP_REQUEST_DELETE_PACKAGES,
             OP_BIND_ACCESSIBILITY_SERVICE,
             OP_ACCEPT_HANDOVER,
+            OP_MANAGE_IPSEC_TUNNELS,
     };
 
     /**
@@ -722,6 +728,7 @@
             OPSTR_REQUEST_DELETE_PACKAGES,
             OPSTR_BIND_ACCESSIBILITY_SERVICE,
             OPSTR_ACCEPT_HANDOVER,
+            OPSTR_MANAGE_IPSEC_TUNNELS,
     };
 
     /**
@@ -804,6 +811,7 @@
             "REQUEST_DELETE_PACKAGES",
             "BIND_ACCESSIBILITY_SERVICE",
             "ACCEPT_HANDOVER",
+            "MANAGE_IPSEC_TUNNELS",
     };
 
     /**
@@ -886,6 +894,7 @@
             Manifest.permission.REQUEST_DELETE_PACKAGES,
             Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
             Manifest.permission.ACCEPT_HANDOVER,
+            null, // no permission for OP_MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -969,6 +978,7 @@
             null, // REQUEST_DELETE_PACKAGES
             null, // OP_BIND_ACCESSIBILITY_SERVICE
             null, // ACCEPT_HANDOVER
+            null, // MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -1051,6 +1061,7 @@
             false, // OP_REQUEST_DELETE_PACKAGES
             false, // OP_BIND_ACCESSIBILITY_SERVICE
             false, // ACCEPT_HANDOVER
+            false, // MANAGE_IPSEC_HANDOVERS
     };
 
     /**
@@ -1132,6 +1143,7 @@
             AppOpsManager.MODE_ALLOWED,  // REQUEST_DELETE_PACKAGES
             AppOpsManager.MODE_ALLOWED,  // OP_BIND_ACCESSIBILITY_SERVICE
             AppOpsManager.MODE_ALLOWED,  // ACCEPT_HANDOVER
+            AppOpsManager.MODE_ERRORED,  // MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -1217,6 +1229,7 @@
             false, // OP_REQUEST_DELETE_PACKAGES
             false, // OP_BIND_ACCESSIBILITY_SERVICE
             false, // ACCEPT_HANDOVER
+            false, // MANAGE_IPSEC_TUNNELS
     };
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b8c4ef7..fb8ded1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -70,6 +70,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -2151,16 +2152,42 @@
     }
 
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-            int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras,
+            String dialogMessage) {
+        // TODO (b/75332201): Pass in the dialogMessage and use it in the interceptor dialog
         try {
-            return mPM.setPackagesSuspendedAsUser(packageNames, suspended, userId);
+            return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
+                    launcherExtras, mContext.getOpPackageName(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+        try {
+            return mPM.getPackageSuspendedAppExtras(packageName, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public PersistableBundle getSuspendedPackageAppExtras() {
+        return getSuspendedPackageAppExtras(mContext.getOpPackageName());
+    }
+
+    @Override
+    public void setSuspendedPackageAppExtras(String packageName, PersistableBundle appExtras) {
+        try {
+            mPM.setSuspendedPackageAppExtras(packageName, appExtras, mContext.getUserId());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
         try {
             return mPM.isPackageSuspendedForUser(packageName, userId);
@@ -2171,6 +2198,17 @@
 
     /** @hide */
     @Override
+    public boolean isPackageSuspended(String packageName) {
+        return isPackageSuspendedForUser(packageName, mContext.getUserId());
+    }
+
+    @Override
+    public boolean isPackageSuspended() {
+        return isPackageSuspendedForUser(mContext.getOpPackageName(), mContext.getUserId());
+    }
+
+    /** @hide */
+    @Override
     public void setApplicationCategoryHint(String packageName, int categoryHint) {
         try {
             mPM.setApplicationCategoryHint(packageName, categoryHint,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c6568e1..d3c1e99 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2631,8 +2631,8 @@
                     if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) {
                         return true;
                     }
-                    CharSequence[] firstCs = firstRs[i].getChoices();
-                    CharSequence[] secondCs = secondRs[i].getChoices();
+                    CharSequence[] firstCs = firstRs[j].getChoices();
+                    CharSequence[] secondCs = secondRs[j].getChoices();
                     if (firstCs == null) {
                         firstCs = new CharSequence[0];
                     }
@@ -3118,7 +3118,6 @@
         private int mActionBarColor = COLOR_INVALID;
         private int mBackgroundColor = COLOR_INVALID;
         private int mForegroundColor = COLOR_INVALID;
-        private int mBackgroundColorHint = COLOR_INVALID;
         /**
          * A temporary location where actions are stored. If != null the view originally has action
          * but doesn't have any for this inflation.
@@ -4387,8 +4386,7 @@
                             backgroundColor);
                     mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(mContext,
                             backgroundColor);
-                    if (backgroundColor != COLOR_DEFAULT
-                            && (mBackgroundColorHint != COLOR_INVALID || isColorized())) {
+                    if (backgroundColor != COLOR_DEFAULT && isColorized()) {
                         mPrimaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
                                 mPrimaryTextColor, backgroundColor, 4.5);
                         mSecondaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
@@ -4595,21 +4593,13 @@
         }
 
         private void bindExpandButton(RemoteViews contentView) {
-            int color = getPrimaryHighlightColor();
+            int color = isColorized() ? getPrimaryTextColor() : getSecondaryTextColor();
             contentView.setDrawableTint(R.id.expand_button, false, color,
                     PorterDuff.Mode.SRC_ATOP);
             contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
                     color);
         }
 
-        /**
-         * @return the color that is used as the first primary highlight color. This is applied
-         * in several places like the action buttons or the app name in the header.
-         */
-        private int getPrimaryHighlightColor() {
-            return isColorized() ? getPrimaryTextColor() : resolveContrastColor();
-        }
-
         private void bindHeaderChronometerAndTime(RemoteViews contentView) {
             if (showsTimeOrChronometer()) {
                 contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
@@ -4706,7 +4696,7 @@
                 setTextViewColorPrimary(contentView, R.id.app_name_text);
             } else {
                 contentView.setTextColor(R.id.app_name_text,
-                        ambient ? resolveAmbientColor() : resolveContrastColor());
+                        ambient ? resolveAmbientColor() : getSecondaryTextColor());
             }
         }
 
@@ -5234,7 +5224,14 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
                 boolean ambient) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
-            int color = ambient ? resolveAmbientColor() : getPrimaryHighlightColor();
+            int color;
+            if (ambient) {
+                color = resolveAmbientColor();
+            } else if (isColorized()) {
+                color = getPrimaryTextColor();
+            } else {
+                color = resolveContrastColor();
+            }
             if (colorable) {
                 contentView.setDrawableTint(R.id.icon, false, color,
                         PorterDuff.Mode.SRC_ATOP);
@@ -5270,14 +5267,11 @@
             }
 
             int color;
-            int background = mBackgroundColorHint;
-            if (mBackgroundColorHint == COLOR_INVALID) {
-                background = mContext.getColor(
-                        com.android.internal.R.color.notification_material_background_color);
-            }
+            int background = mContext.getColor(
+                    com.android.internal.R.color.notification_material_background_color);
             if (mN.color == COLOR_DEFAULT) {
                 ensureColors();
-                color = mSecondaryTextColor;
+                color = NotificationColorUtil.resolveDefaultColor(mContext, background);
             } else {
                 color = NotificationColorUtil.resolveContrastColor(mContext, mN.color,
                         background, mInNightMode);
@@ -5517,8 +5511,7 @@
             if (isColorized()) {
                 return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : mN.color;
             } else {
-                return mBackgroundColorHint != COLOR_INVALID ? mBackgroundColorHint
-                        : COLOR_DEFAULT;
+                return COLOR_DEFAULT;
             }
         }
 
@@ -5555,18 +5548,6 @@
         }
 
         /**
-         * Sets the background color for this notification to be a different one then the default.
-         * This is mainly used to calculate contrast and won't necessarily be applied to the
-         * background.
-         *
-         * @hide
-         */
-        public void setBackgroundColorHint(int backgroundColor) {
-            mBackgroundColorHint = backgroundColor;
-        }
-
-
-        /**
          * Forces all styled remoteViews to be built from scratch and not use any cached
          * RemoteViews.
          * This is needed for legacy apps that are baking in their remoteviews into the
@@ -5972,7 +5953,7 @@
          * @hide
          */
         public abstract boolean areNotificationsVisiblyDifferent(Style other);
-        
+
         /**
          * @return the the text that should be displayed in the statusBar when heads-upped.
          * If {@code null} is returned, the default implementation will be used.
@@ -7498,8 +7479,7 @@
                     }
 
                     final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
-                    final RemoteViews button = generateMediaActionButton(action,
-                            getPrimaryHighlightColor());
+                    final RemoteViews button = generateMediaActionButton(action, getActionColor());
                     view.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -7513,8 +7493,9 @@
             return view;
         }
 
-        private int getPrimaryHighlightColor() {
-            return mBuilder.getPrimaryHighlightColor();
+        private int getActionColor() {
+            return mBuilder.isColorized() ? mBuilder.getPrimaryTextColor()
+                    : mBuilder.resolveContrastColor();
         }
 
         private RemoteViews makeMediaBigContentView() {
@@ -7534,7 +7515,7 @@
                 big.removeAllViews(com.android.internal.R.id.media_actions);
                 for (int i = 0; i < actionCount; i++) {
                     final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
-                            getPrimaryHighlightColor());
+                            getActionColor());
                     big.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 02e77df..4cb7f89 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8877,15 +8877,20 @@
      * <p>If backups were disabled and a non-null backup transport {@link ComponentName} is
      * specified, backups will be enabled.
      *
+     * <p>NOTE: The method shouldn't be called on the main thread.
+     *
      * @param admin admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param backupTransportComponent The backup transport layer to be used for mandatory backups.
+     * @return {@code true} if the backup transport was successfully set; {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not a device owner.
      */
-    public void setMandatoryBackupTransport(
-            @NonNull ComponentName admin, @Nullable ComponentName backupTransportComponent) {
+    @WorkerThread
+    public boolean setMandatoryBackupTransport(
+            @NonNull ComponentName admin,
+            @Nullable ComponentName backupTransportComponent) {
         throwIfParentInstance("setMandatoryBackupTransport");
         try {
-            mService.setMandatoryBackupTransport(admin, backupTransportComponent);
+            return mService.setMandatoryBackupTransport(admin, backupTransportComponent);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c29369f..c46402f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -364,7 +364,7 @@
 
     void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
     boolean isBackupServiceEnabled(in ComponentName admin);
-    void setMandatoryBackupTransport(in ComponentName admin, in ComponentName backupTransportComponent);
+    boolean setMandatoryBackupTransport(in ComponentName admin, in ComponentName backupTransportComponent);
     ComponentName getMandatoryBackupTransport();
 
     void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index c71bf2e..d67f11b 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -36,15 +36,16 @@
 public class JobParameters implements Parcelable {
 
     /** @hide */
-    public static final int REASON_CANCELED = 0;
+    public static final int REASON_CANCELED = JobProtoEnums.STOP_REASON_CANCELLED; // 0.
     /** @hide */
-    public static final int REASON_CONSTRAINTS_NOT_SATISFIED = 1;
+    public static final int REASON_CONSTRAINTS_NOT_SATISFIED =
+            JobProtoEnums.STOP_REASON_CONSTRAINTS_NOT_SATISFIED; //1.
     /** @hide */
-    public static final int REASON_PREEMPT = 2;
+    public static final int REASON_PREEMPT = JobProtoEnums.STOP_REASON_PREEMPT; // 2.
     /** @hide */
-    public static final int REASON_TIMEOUT = 3;
+    public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
     /** @hide */
-    public static final int REASON_DEVICE_IDLE = 4;
+    public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
 
     /** @hide */
     public static String getReasonName(int reason) {
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index d6f2352..61679cb 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -66,10 +66,27 @@
             HINT_HORIZONTAL,
             HINT_PARTIAL,
             HINT_SEE_MORE,
-            HINT_KEY_WORDS
+            HINT_KEY_WORDS,
+            HINT_ERROR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SliceHint {}
+    /**
+     * @hide
+     */
+    @StringDef(prefix = { "SUBTYPE_" }, value = {
+            SUBTYPE_COLOR,
+            SUBTYPE_CONTENT_DESCRIPTION,
+            SUBTYPE_MAX,
+            SUBTYPE_MESSAGE,
+            SUBTYPE_PRIORITY,
+            SUBTYPE_RANGE,
+            SUBTYPE_SOURCE,
+            SUBTYPE_TOGGLE,
+            SUBTYPE_VALUE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SliceSubtype {}
 
     /**
      * Hint that this content is a title of other content in the slice. This can also indicate that
@@ -149,9 +166,14 @@
     /**
      * A hint to indicate that the contents of this subslice represent a list of keywords
      * related to the parent slice.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE}.
      */
     public static final String HINT_KEY_WORDS = "key_words";
     /**
+     * A hint to indicate that this slice represents an error.
+     */
+    public static final String HINT_ERROR = "error";
+    /**
      * Key to retrieve an extra added to an intent when a control is changed.
      */
     public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
@@ -168,14 +190,18 @@
     /**
      * Subtype to indicate that this is a message as part of a communication
      * sequence in this slice.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE}.
      */
     public static final String SUBTYPE_MESSAGE = "message";
     /**
      * Subtype to tag the source (i.e. sender) of a {@link #SUBTYPE_MESSAGE}.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_TEXT},
+     * {@link SliceItem#FORMAT_IMAGE} or an {@link SliceItem#FORMAT_SLICE} containing them.
      */
     public static final String SUBTYPE_SOURCE = "source";
     /**
      * Subtype to tag an item as representing a color.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_INT}.
      */
     public static final String SUBTYPE_COLOR = "color";
     /**
@@ -186,14 +212,18 @@
     public static final String SUBTYPE_SLIDER = "slider";
     /**
      * Subtype to tag an item as representing a range.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_SLICE} containing
+     * a {@link #SUBTYPE_VALUE} and possibly a {@link #SUBTYPE_MAX}.
      */
     public static final String SUBTYPE_RANGE = "range";
     /**
      * Subtype to tag an item as representing the max int value for a {@link #SUBTYPE_RANGE}.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_INT}.
      */
     public static final String SUBTYPE_MAX = "max";
     /**
      * Subtype to tag an item as representing the current int value for a {@link #SUBTYPE_RANGE}.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_INT}.
      */
     public static final String SUBTYPE_VALUE = "value";
     /**
@@ -205,10 +235,12 @@
     public static final String SUBTYPE_TOGGLE = "toggle";
     /**
      * Subtype to tag an item representing priority.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_INT}.
      */
     public static final String SUBTYPE_PRIORITY = "priority";
     /**
      * Subtype to tag an item to use as a content description.
+     * Expected to be on an item of format {@link SliceItem#FORMAT_TEXT}.
      */
     public static final String SUBTYPE_CONTENT_DESCRIPTION = "content_description";
 
@@ -305,14 +337,24 @@
         private SliceSpec mSpec;
 
         /**
-         * Create a builder which will construct a {@link Slice} for the Given Uri.
-         * @param uri Uri to tag for this slice.
+         * @deprecated TO BE REMOVED
          */
+        @Deprecated
         public Builder(@NonNull Uri uri) {
             mUri = uri;
         }
 
         /**
+         * Create a builder which will construct a {@link Slice} for the given Uri.
+         * @param uri Uri to tag for this slice.
+         * @param spec the spec for this slice.
+         */
+        public Builder(@NonNull Uri uri, SliceSpec spec) {
+            mUri = uri;
+            mSpec = spec;
+        }
+
+        /**
          * Create a builder for a {@link Slice} that is a sub-slice of the slice
          * being constructed by the provided builder.
          * @param parent The builder constructing the parent slice
@@ -340,20 +382,13 @@
         /**
          * Add hints to the Slice being constructed
          */
-        public Builder addHints(@SliceHint String... hints) {
-            mHints.addAll(Arrays.asList(hints));
+        public Builder addHints(@SliceHint List<String> hints) {
+            mHints.addAll(hints);
             return this;
         }
 
         /**
-         * Add hints to the Slice being constructed
-         */
-        public Builder addHints(@SliceHint List<String> hints) {
-            return addHints(hints.toArray(new String[hints.size()]));
-        }
-
-        /**
-         * Add the spec for this slice.
+         * @deprecated TO BE REMOVED
          */
         public Builder setSpec(SliceSpec spec) {
             mSpec = spec;
@@ -362,17 +397,10 @@
 
         /**
          * Add a sub-slice to the slice being constructed
-         */
-        public Builder addSubSlice(@NonNull Slice slice) {
-            return addSubSlice(slice, null);
-        }
-
-        /**
-         * Add a sub-slice to the slice being constructed
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addSubSlice(@NonNull Slice slice, @Nullable String subType) {
+        public Builder addSubSlice(@NonNull Slice slice, @Nullable @SliceSubtype String subType) {
             mItems.add(new SliceItem(slice, SliceItem.FORMAT_SLICE, subType,
                     slice.getHints().toArray(new String[slice.getHints().size()])));
             return this;
@@ -380,18 +408,11 @@
 
         /**
          * Add an action to the slice being constructed
-         */
-        public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s) {
-            return addAction(action, s, null);
-        }
-
-        /**
-         * Add an action to the slice being constructed
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
         public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s,
-                @Nullable String subType) {
+                @Nullable @SliceSubtype String subType) {
             List<String> hints = s.getHints();
             s.mSpec = null;
             mItems.add(new SliceItem(action, s, SliceItem.FORMAT_ACTION, subType, hints.toArray(
@@ -404,58 +425,31 @@
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addText(CharSequence text, @Nullable String subType,
-                @SliceHint String... hints) {
+        public Builder addText(CharSequence text, @Nullable @SliceSubtype String subType,
+                @SliceHint List<String> hints) {
             mItems.add(new SliceItem(text, SliceItem.FORMAT_TEXT, subType, hints));
             return this;
         }
 
         /**
-         * Add text to the slice being constructed
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
-         */
-        public Builder addText(CharSequence text, @Nullable String subType,
-                @SliceHint List<String> hints) {
-            return addText(text, subType, hints.toArray(new String[hints.size()]));
-        }
-
-        /**
          * Add an image to the slice being constructed
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addIcon(Icon icon, @Nullable String subType, @SliceHint String... hints) {
+        public Builder addIcon(Icon icon, @Nullable @SliceSubtype String subType,
+                @SliceHint List<String> hints) {
             mItems.add(new SliceItem(icon, SliceItem.FORMAT_IMAGE, subType, hints));
             return this;
         }
 
         /**
-         * Add an image to the slice being constructed
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
-         */
-        public Builder addIcon(Icon icon, @Nullable String subType, @SliceHint List<String> hints) {
-            return addIcon(icon, subType, hints.toArray(new String[hints.size()]));
-        }
-
-        /**
          * Add remote input to the slice being constructed
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput,
+                @Nullable @SliceSubtype String subType,
                 @SliceHint List<String> hints) {
-            return addRemoteInput(remoteInput, subType, hints.toArray(new String[hints.size()]));
-        }
-
-        /**
-         * Add remote input to the slice being constructed
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
-         */
-        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
-                @SliceHint String... hints) {
             mItems.add(new SliceItem(remoteInput, SliceItem.FORMAT_REMOTE_INPUT,
                     subType, hints));
             return this;
@@ -466,70 +460,48 @@
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addInt(int value, @Nullable String subType, @SliceHint String... hints) {
+        public Builder addInt(int value, @Nullable @SliceSubtype String subType,
+                @SliceHint List<String> hints) {
             mItems.add(new SliceItem(value, SliceItem.FORMAT_INT, subType, hints));
             return this;
         }
 
         /**
-         * Add an integer to the slice being constructed
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
+         * @deprecated TO BE REMOVED.
          */
-        public Builder addInt(int value, @Nullable String subType,
+        @Deprecated
+        public Slice.Builder addTimestamp(long time, @Nullable @SliceSubtype String subType,
                 @SliceHint List<String> hints) {
-            return addInt(value, subType, hints.toArray(new String[hints.size()]));
+            return addLong(time, subType, hints);
         }
 
         /**
-         * Add a timestamp to the slice being constructed
+         * Add a long to the slice being constructed
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Slice.Builder addTimestamp(long time, @Nullable String subType,
-                @SliceHint String... hints) {
-            mItems.add(new SliceItem(time, SliceItem.FORMAT_TIMESTAMP, subType,
-                    hints));
+        public Slice.Builder addLong(long value, @Nullable @SliceSubtype String subType,
+                @SliceHint List<String> hints) {
+            mItems.add(new SliceItem(value, SliceItem.FORMAT_LONG, subType,
+                    hints.toArray(new String[hints.size()])));
             return this;
         }
 
         /**
-         * Add a timestamp to the slice being constructed
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
-         */
-        public Slice.Builder addTimestamp(long time, @Nullable String subType,
-                @SliceHint List<String> hints) {
-            return addTimestamp(time, subType, hints.toArray(new String[hints.size()]));
-        }
-
-        /**
          * Add a bundle to the slice being constructed.
          * <p>Expected to be used for support library extension, should not be used for general
          * development
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Slice.Builder addBundle(Bundle bundle, @Nullable String subType,
-                @SliceHint String... hints) {
+        public Slice.Builder addBundle(Bundle bundle, @Nullable @SliceSubtype String subType,
+                @SliceHint List<String> hints) {
             mItems.add(new SliceItem(bundle, SliceItem.FORMAT_BUNDLE, subType,
                     hints));
             return this;
         }
 
         /**
-         * Add a bundle to the slice being constructed.
-         * <p>Expected to be used for support library extension, should not be used for general
-         * development
-         * @param subType Optional template-specific type information
-         * @see {@link SliceItem#getSubType()}
-         */
-        public Slice.Builder addBundle(Bundle bundle, @Nullable String subType,
-                @SliceHint List<String> hints) {
-            return addBundle(bundle, subType, hints.toArray(new String[hints.size()]));
-        }
-
-        /**
          * Construct the slice.
          */
         public Slice build() {
diff --git a/core/java/android/app/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
index 9eb2bb8..019ae49 100644
--- a/core/java/android/app/slice/SliceItem.java
+++ b/core/java/android/app/slice/SliceItem.java
@@ -67,7 +67,7 @@
             FORMAT_IMAGE,
             FORMAT_ACTION,
             FORMAT_INT,
-            FORMAT_TIMESTAMP,
+            FORMAT_LONG,
             FORMAT_REMOTE_INPUT,
             FORMAT_BUNDLE,
     })
@@ -98,9 +98,14 @@
      */
     public static final String FORMAT_INT = "int";
     /**
-     * A {@link SliceItem} that contains a timestamp.
+     * A {@link SliceItem} that contains a long.
      */
-    public static final String FORMAT_TIMESTAMP = "timestamp";
+    public static final String FORMAT_LONG = "long";
+    /**
+     * @deprecated TO BE REMOVED
+     */
+    @Deprecated
+    public static final String FORMAT_TIMESTAMP = FORMAT_LONG;
     /**
      * A {@link SliceItem} that contains a {@link RemoteInput}.
      */
@@ -123,6 +128,14 @@
      * @hide
      */
     public SliceItem(Object obj, @SliceType String format, String subType,
+            List<String> hints) {
+        this(obj, format, subType, hints.toArray(new String[hints.size()]));
+    }
+
+    /**
+     * @hide
+     */
+    public SliceItem(Object obj, @SliceType String format, String subType,
             @Slice.SliceHint String[] hints) {
         mHints = hints;
         mFormat = format;
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index aa2cf46..dd89293 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -41,6 +41,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -430,9 +431,11 @@
         return new Slice.Builder(sliceUri)
                 .addAction(createPermissionIntent(context, sliceUri, callingPackage),
                         new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
-                                .addText(getPermissionString(context, callingPackage), null)
-                                .build())
-                .addHints(Slice.HINT_LIST_ITEM)
+                                .addText(getPermissionString(context, callingPackage), null,
+                                        Collections.emptyList())
+                                .build(),
+                        null)
+                .addHints(Arrays.asList(Slice.HINT_LIST_ITEM))
                 .build();
     }
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index ce7d3af..440103a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2464,8 +2464,9 @@
      * @param account the account to specify in the sync
      * @param authority the provider to specify in the sync request
      * @param extras extra parameters to go along with the sync request
-     * @param pollFrequency how frequently the sync should be performed, in seconds. A minimum value
-     *                      of 1 hour is enforced.
+     * @param pollFrequency how frequently the sync should be performed, in seconds.
+     * On Android API level 24 and above, a minmam interval of 15 minutes is enforced.
+     * On previous versions, the minimum interval is 1 hour.
      * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
      * are null.
      */
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 36a74a4..f4352f9 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -50,8 +50,8 @@
 import android.content.pm.dex.IArtManager;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.content.IntentSender;
 
 /**
@@ -272,9 +272,17 @@
 
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
-    String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended, int userId);
+    String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
+            in PersistableBundle launcherExtras, in PersistableBundle appExtras,
+            String callingPackage, int userId);
+
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
+    PersistableBundle getPackageSuspendedAppExtras(String pacakgeName, int userId);
+
+    void setSuspendedPackageAppExtras(String packageName, in PersistableBundle appExtras,
+            int userId);
+
     /**
      * Backup/restore support - only the system uid may use these.
      */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3536eea..4d8773c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -51,6 +51,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -5510,28 +5511,49 @@
     /**
      * Puts the package in a suspended state, where attempts at starting activities are denied.
      *
-     * <p>It doesn't remove the data or the actual package file. The application notifications
-     * will be hidden, the application will not show up in recents, will not be able to show
-     * toasts or dialogs or ring the device.
+     * <p>It doesn't remove the data or the actual package file. The application's notifications
+     * will be hidden, any of the it's started activities will be stopped and it will not be able to
+     * show toasts or dialogs or ring the device. When the user tries to launch a suspended app, a
+     * system dialog with the given {@code dialogMessage} will be shown instead.</p>
      *
      * <p>The package must already be installed. If the package is uninstalled while suspended
-     * the package will no longer be suspended.
+     * the package will no longer be suspended. </p>
+     *
+     * <p>Optionally, the suspending app can provide extra information in the form of
+     * {@link PersistableBundle} objects to be shared with the apps being suspended and the
+     * launcher to support customization that they might need to handle the suspended state. </p>
+     *
+     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} or
+     * {@link Manifest.permission#MANAGE_USERS} to use this api.</p>
      *
      * @param packageNames The names of the packages to set the suspended status.
      * @param suspended If set to {@code true} than the packages will be suspended, if set to
-     * {@code false} the packages will be unsuspended.
-     * @param userId The user id.
+     * {@code false}, the packages will be unsuspended.
+     * @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
+     *                  which will be shared with the apps being suspended. Ignored if
+     *                  {@code suspended} is false.
+     * @param launcherExtras An optional {@link PersistableBundle} that the suspending app can
+     *                       provide which will be shared with the launcher. Ignored if
+     *                       {@code suspended} is false.
+     * @param dialogMessage The message to be displayed to the user, when they try to launch a
+     *                      suspended app.
      *
      * @return an array of package names for which the suspended status is not set as requested in
      * this method.
      *
      * @hide
      */
-    public abstract String[] setPackagesSuspendedAsUser(
-            String[] packageNames, boolean suspended, @UserIdInt int userId);
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.SUSPEND_APPS,
+            Manifest.permission.MANAGE_USERS})
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
+            String dialogMessage) {
+        throw new UnsupportedOperationException("setPackagesSuspended not implemented");
+    }
 
     /**
-     * @see #setPackageSuspendedAsUser(String, boolean, int)
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
      * @param packageName The name of the package to get the suspended status of.
      * @param userId The user id.
      * @return {@code true} if the package is suspended or {@code false} if the package is not
@@ -5541,6 +5563,86 @@
     public abstract boolean isPackageSuspendedForUser(String packageName, int userId);
 
     /**
+     * Query if an app is currently suspended.
+     *
+     * @return {@code true} if the given package is suspended, {@code false} otherwise
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     * @hide
+     */
+    @SystemApi
+    public boolean isPackageSuspended(String packageName) {
+        throw new UnsupportedOperationException("isPackageSuspended not implemented");
+    }
+
+    /**
+     * Apps can query this to know if they have been suspended.
+     *
+     * @return {@code true} if the calling package has been suspended, {@code false} otherwise.
+     *
+     * @see #getSuspendedPackageAppExtras()
+     */
+    public boolean isPackageSuspended() {
+        throw new UnsupportedOperationException("isPackageSuspended not implemented");
+    }
+
+    /**
+     * Retrieve the {@link PersistableBundle} that was passed as {@code appExtras} when the given
+     * package was suspended.
+     *
+     * <p> The caller must hold permission {@link Manifest.permission#SUSPEND_APPS} to use this
+     * api.</p>
+     *
+     * @param packageName The package to retrieve extras for.
+     * @return The {@code appExtras} for the suspended package.
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.SUSPEND_APPS)
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+        throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
+     * Set the app extras for a suspended package. This method can be used to update the appExtras
+     * for a package that was earlier suspended using
+     * {@link #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+     * String)}
+     * Does nothing if the given package is not already in a suspended state.
+     *
+     * @param packageName The package for which the appExtras need to be updated
+     * @param appExtras The new appExtras for the given package
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.SUSPEND_APPS)
+    public void setSuspendedPackageAppExtras(String packageName,
+            @Nullable PersistableBundle appExtras) {
+        throw new UnsupportedOperationException("setSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
+     * Returns any extra information supplied as {@code appExtras} to the system when the calling
+     * app was suspended.
+     *
+     * <p> Note: This just returns whatever {@link PersistableBundle} was passed to the system via
+     * {@code setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+     * String)} when suspending the package, <em> which might be {@code null}. </em></p>
+     *
+     * @return A {@link PersistableBundle} containing the extras for the app, or {@code null} if the
+     * package is not currently suspended.
+     * @see #isPackageSuspended()
+     */
+    public @Nullable PersistableBundle getSuspendedPackageAppExtras() {
+        throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
      * Provide a hint of what the {@link ApplicationInfo#category} value should
      * be for the given package.
      * <p>
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 293beb2..f7b6e09 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -27,6 +27,8 @@
 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.util.ArraySet;
 
 import com.android.internal.util.ArrayUtils;
@@ -44,6 +46,9 @@
     public boolean notLaunched;
     public boolean hidden; // Is the app restricted by owner / admin
     public boolean suspended;
+    public String suspendingPackage;
+    public PersistableBundle suspendedAppExtras;
+    public PersistableBundle suspendedLauncherExtras;
     public boolean instantApp;
     public boolean virtualPreload;
     public int enabled;
@@ -76,6 +81,9 @@
         notLaunched = o.notLaunched;
         hidden = o.hidden;
         suspended = o.suspended;
+        suspendingPackage = o.suspendingPackage;
+        suspendedAppExtras = o.suspendedAppExtras;
+        suspendedLauncherExtras = o.suspendedLauncherExtras;
         instantApp = o.instantApp;
         virtualPreload = o.virtualPreload;
         enabled = o.enabled;
@@ -195,6 +203,20 @@
         if (suspended != oldState.suspended) {
             return false;
         }
+        if (suspended) {
+            if (suspendingPackage == null
+                    || !suspendingPackage.equals(oldState.suspendingPackage)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(suspendedAppExtras,
+                    oldState.suspendedAppExtras)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(suspendedLauncherExtras,
+                    oldState.suspendedLauncherExtras)) {
+                return false;
+            }
+        }
         if (instantApp != oldState.instantApp) {
             return false;
         }
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 2a791ec..316c796 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -293,9 +293,7 @@
                     (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
             // Use compatibility WAL unless an app explicitly set journal/synchronous mode
             // or DISABLE_COMPATIBILITY_WAL flag is set
-            final boolean useCompatibilityWal = mConfiguration.journalMode == null
-                    && mConfiguration.syncMode == null
-                    && (mConfiguration.openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
+            final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
             if (walEnabled || useCompatibilityWal) {
                 setJournalMode("WAL");
                 if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index dadb95b..e519302 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -23,6 +23,7 @@
 import android.os.Message;
 import android.os.OperationCanceledException;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.PrefixPrinter;
 import android.util.Printer;
@@ -1111,6 +1112,11 @@
             printer.println("  Open: " + mIsOpen);
             printer.println("  Max connections: " + mMaxConnectionPoolSize);
             printer.println("  Total execution time: " + mTotalExecutionTimeCounter);
+            printer.println("  Configuration: openFlags=" + mConfiguration.openFlags
+                    + ", useCompatibilityWal=" + mConfiguration.useCompatibilityWal()
+                    + ", journalMode=" + TextUtils.emptyIfNull(mConfiguration.journalMode)
+                    + ", syncMode=" + TextUtils.emptyIfNull(mConfiguration.syncMode));
+
             if (SQLiteCompatibilityWalFlags.areFlagsSet()) {
                 printer.println("  Compatibility WAL settings: compatibility_wal_supported="
                         + SQLiteCompatibilityWalFlags
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 275043f..8b9dfcf 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -194,6 +194,11 @@
         return path.equalsIgnoreCase(MEMORY_DB_PATH);
     }
 
+    boolean useCompatibilityWal() {
+        return journalMode == null && syncMode == null
+                && (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
+    }
+
     private static String stripPathForLogs(String path) {
         if (path.indexOf('@') == -1) {
             return path;
diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl
deleted file mode 100644
index 2ea4d23..0000000
--- a/core/java/android/hardware/location/IFusedLocationHardware.aidl
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/license/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.location;
-
-import android.hardware.location.IFusedLocationHardwareSink;
-import android.location.FusedBatchOptions;
-
-/**
- * Fused Location hardware interface.
- * This interface is the basic set of supported functionality by Fused Hardware
- * modules that offer Location batching capabilities.
- *
- * @hide
- */
-interface IFusedLocationHardware {
-    /**
-     * Registers a sink with the Location Hardware object.
-     *
-     * @param eventSink     The sink to register.
-     */
-    void registerSink(in IFusedLocationHardwareSink eventSink) = 0;
-
-    /**
-     * Unregisters a sink with the Location Hardware object.
-     *
-     * @param eventSink     The sink to unregister.
-     */
-    void unregisterSink(in IFusedLocationHardwareSink eventSink) = 1;
-
-    /**
-     * Provides access to the batch size available in Hardware.
-     *
-     * @return The batch size the hardware supports.
-     */
-    int getSupportedBatchSize() = 2;
-
-    /**
-     * Requests the Hardware to start batching locations.
-     *
-     * @param id            An Id associated with the request.
-     * @param batchOptions  The options required for batching.
-     *
-     * @throws RuntimeException if the request Id exists.
-     */
-    void startBatching(in int id, in FusedBatchOptions batchOptions) = 3;
-
-    /**
-     * Requests the Hardware to stop batching for the given Id.
-     *
-     * @param id    The request that needs to be stopped.
-     * @throws RuntimeException if the request Id is unknown.
-     */
-    void stopBatching(in int id) = 4;
-
-    /**
-     * Updates a batching operation in progress.
-     *
-     * @param id                The Id of the operation to update.
-     * @param batchOptions     The options to apply to the given operation.
-     *
-     * @throws RuntimeException if the Id of the request is unknown.
-     */
-    void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions) = 5;
-
-    /**
-     * Requests the most recent locations available in Hardware.
-     * This operation does not dequeue the locations, so still other batching
-     * events will continue working.
-     *
-     * @param batchSizeRequested    The number of locations requested.
-     */
-    void requestBatchOfLocations(in int batchSizeRequested) = 6;
-
-    /**
-     * Flags if the Hardware supports injection of diagnostic data.
-     *
-     * @return True if data injection is supported, false otherwise.
-     */
-    boolean supportsDiagnosticDataInjection() = 7;
-
-    /**
-     * Injects diagnostic data into the Hardware subsystem.
-     *
-     * @param data  The data to inject.
-     * @throws RuntimeException if injection is not supported.
-     */
-    void injectDiagnosticData(in String data) = 8;
-
-    /**
-     * Flags if the Hardware supports injection of device context information.
-     *
-     * @return True if device context injection is supported, false otherwise.
-     */
-    boolean supportsDeviceContextInjection() = 9;
-
-    /**
-     * Injects device context information into the Hardware subsystem.
-     *
-     * @param deviceEnabledContext  The context to inject.
-     * @throws RuntimeException if injection is not supported.
-     */
-    void injectDeviceContext(in int deviceEnabledContext) = 10;
-
-    /**
-     * Requests all batched locations currently available in Hardware
-     * and clears the buffer.  Any subsequent calls will not return any
-     * of the locations returned in this call.
-     */
-    void flushBatchedLocations() = 11;
-
-    /**
-     * Returns the version of this FLP HAL implementation.
-     */
-    int getVersion() = 12;
-}
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
deleted file mode 100644
index a7dd035..0000000
--- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/license/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.location;
-
-import android.location.Location;
-
-/**
- * Fused Location hardware event sink interface.
- * This interface defines the set of events that the FusedLocationHardware provides.
- *
- * @hide
- */
-oneway interface IFusedLocationHardwareSink {
-    /**
-     * Event generated when a batch of location information is available.
-     *
-     * @param locations     The batch of location information available.
-     */
-    void onLocationAvailable(in Location[] locations) = 0;
-
-    /**
-     * Event generated from FLP HAL to provide diagnostic data to the platform.
-     *
-     * @param data      The diagnostic data provided by FLP HAL.
-     */
-    void onDiagnosticDataAvailable(in String data) = 1;
-
-    /**
-     * Event generated from FLP HAL to provide a mask of supported
-     * capabilities.  Should be called immediatly after init.
-     */
-    void onCapabilities(int capabilities) = 2;
-
-    /**
-     * Event generated from FLP HAL when the status of location batching
-     * changes (location is successful/unsuccessful).
-     */
-    void onStatusChanged(int status) = 3;
-}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 36f359b..93b1b22 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1977,13 +1977,6 @@
      * services.jar, possibly in com.android.server.net. */
 
     /** {@hide} */
-    public static final boolean checkChangePermission(Context context) {
-        int uid = Binder.getCallingUid();
-        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
-                .getPackageNameForUid(context, uid), false /* throwException */);
-    }
-
-    /** {@hide} */
     public static final void enforceChangePermission(Context context) {
         int uid = Binder.getCallingUid();
         Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 3ce0283..3a3ddcc 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.net.LinkAddress;
 import android.net.Network;
 import android.net.IpSecConfig;
 import android.net.IpSecUdpEncapResponse;
@@ -48,11 +49,11 @@
 
     void addAddressToTunnelInterface(
             int tunnelResourceId,
-            String localAddr);
+            in LinkAddress localAddr);
 
     void removeAddressFromTunnelInterface(
             int tunnelResourceId,
-            String localAddr);
+            in LinkAddress localAddr);
 
     void deleteTunnelInterface(int resourceId);
 
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index c69a4d4..57f0588 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -38,6 +38,13 @@
     private static final String TAG = "IpSecAlgorithm";
 
     /**
+     * Null cipher.
+     *
+     * @hide
+     */
+    public static final String CRYPT_NULL = "ecb(cipher_null)";
+
+    /**
      * AES-CBC Encryption/Ciphering Algorithm.
      *
      * <p>Valid lengths for this key are {128, 192, 256}.
@@ -122,7 +129,7 @@
      * @param algorithm name of the algorithm.
      * @param key key padded to a multiple of 8 bits.
      */
-    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
+    public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
         this(algorithm, key, key.length * 8);
     }
 
@@ -137,7 +144,8 @@
      * @param key key padded to a multiple of 8 bits.
      * @param truncLenBits number of bits of output hash to use.
      */
-    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+    public IpSecAlgorithm(
+            @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
         mName = algorithm;
         mKey = key.clone();
         mTruncLenBits = truncLenBits;
@@ -145,11 +153,13 @@
     }
 
     /** Get the algorithm name */
+    @NonNull
     public String getName() {
         return mName;
     }
 
     /** Get the key for this algorithm */
+    @NonNull
     public byte[] getKey() {
         return mKey.clone();
     }
@@ -263,6 +273,7 @@
     }
 
     @Override
+    @NonNull
     public String toString() {
         return new StringBuilder()
                 .append("{mName=")
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index fbf3056..972b9c0 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -253,8 +253,9 @@
      * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
      *     currently allocated for this user
      */
-    public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress)
-            throws ResourceUnavailableException {
+    @NonNull
+    public SecurityParameterIndex allocateSecurityParameterIndex(
+                @NonNull InetAddress destinationAddress) throws ResourceUnavailableException {
         try {
             return new SecurityParameterIndex(
                     mService,
@@ -280,8 +281,9 @@
      * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be
      *     reserved
      */
+    @NonNull
     public SecurityParameterIndex allocateSecurityParameterIndex(
-            InetAddress destinationAddress, int requestedSpi)
+            @NonNull InetAddress destinationAddress, int requestedSpi)
             throws SpiUnavailableException, ResourceUnavailableException {
         if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) {
             throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI");
@@ -318,9 +320,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            Socket socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull Socket socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
     }
 
@@ -353,9 +354,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull DatagramSocket socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
     }
 
@@ -388,9 +388,8 @@
      * @param transform a transport mode {@code IpSecTransform}
      * @throws IOException indicating that the transform could not be applied
      */
-    public void applyTransportModeTransform(
-            FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform)
-            throws IOException {
+    public void applyTransportModeTransform(@NonNull FileDescriptor socket,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor()
         // constructor takes control and closes the user's FD when we exit the method.
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
@@ -413,8 +412,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(Socket socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
         removeTransportModeTransforms(socket.getFileDescriptor$());
     }
 
@@ -431,8 +429,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(DatagramSocket socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException {
         removeTransportModeTransforms(socket.getFileDescriptor$());
     }
 
@@ -449,8 +446,7 @@
      * @param socket a socket that previously had a transform applied to it
      * @throws IOException indicating that the transform could not be removed from the socket
      */
-    public void removeTransportModeTransforms(FileDescriptor socket)
-            throws IOException {
+    public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException {
         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) {
             mService.removeTransportModeTransforms(pfd);
         } catch (RemoteException e) {
@@ -588,6 +584,7 @@
     // safely usable for Encapsulation without allowing a user to possibly unbind from/close
     // the port, which could potentially impact the traffic of the next user who binds to that
     // socket.
+    @NonNull
     public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
             throws IOException, ResourceUnavailableException {
         /*
@@ -617,6 +614,7 @@
     // safely usable for Encapsulation without allowing a user to possibly unbind from/close
     // the port, which could potentially impact the traffic of the next user who binds to that
     // socket.
+    @NonNull
     public UdpEncapsulationSocket openUdpEncapsulationSocket()
             throws IOException, ResourceUnavailableException {
         return new UdpEncapsulationSocket(mService, 0);
@@ -645,6 +643,7 @@
         private int mResourceId = INVALID_RESOURCE_ID;
 
         /** Get the underlying SPI held by this object. */
+        @NonNull
         public String getInterfaceName() {
             return mInterfaceName;
         }
@@ -656,10 +655,16 @@
          * tunneled traffic.
          *
          * @param address the local address for traffic inside the tunnel
-         * @throws IOException if the address could not be added
          * @hide
          */
-        public void addAddress(LinkAddress address) throws IOException {
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+        public void addAddress(@NonNull LinkAddress address) throws IOException {
+            try {
+                mService.addAddressToTunnelInterface(mResourceId, address);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         /**
@@ -668,10 +673,16 @@
          * <p>Remove an address which was previously added to the IpSecTunnelInterface
          *
          * @param address to be removed
-         * @throws IOException if the address could not be removed
          * @hide
          */
-        public void removeAddress(LinkAddress address) throws IOException {
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+        public void removeAddress(@NonNull LinkAddress address) throws IOException {
+            try {
+                mService.removeAddressFromTunnelInterface(mResourceId, address);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         private IpSecTunnelInterface(@NonNull IIpSecService service,
@@ -758,7 +769,8 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
             @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
             throws ResourceUnavailableException, IOException {
@@ -783,9 +795,9 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-    public void applyTunnelModeTransform(IpSecTunnelInterface tunnel,
-            @PolicyDirection int direction, IpSecTransform transform) throws IOException {
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+    public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
+            @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
         try {
             mService.applyTunnelModeTransform(
                     tunnel.getResourceId(), direction, transform.getResourceId());
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 60e96f9..099fe02 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -282,7 +282,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
     })
     public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
@@ -325,7 +325,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
     })
     public void stopNattKeepalive() {
@@ -350,6 +350,7 @@
          *
          * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
             Preconditions.checkNotNull(algo);
@@ -364,6 +365,7 @@
          *
          * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
             // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
             Preconditions.checkNotNull(algo);
@@ -384,6 +386,7 @@
          * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
          *     be applied.
          */
+        @NonNull
         public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
             Preconditions.checkNotNull(algo);
             mConfig.setAuthenticatedEncryption(algo);
@@ -403,6 +406,7 @@
          * @param remotePort the UDP port number of the remote host that will send and receive
          *     encapsulated traffic. In the case of IKEv2, this should be port 4500.
          */
+        @NonNull
         public IpSecTransform.Builder setIpv4Encapsulation(
                 @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
             Preconditions.checkNotNull(localSocket);
@@ -436,6 +440,7 @@
          *     collides with an existing transform
          * @throws IOException indicating other errors
          */
+        @NonNull
         public IpSecTransform buildTransportModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
@@ -472,7 +477,8 @@
          * @hide
          */
         @SystemApi
-        @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+        @NonNull
+        @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public IpSecTransform buildTunnelModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index fdcc304..4f92fa6 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -24,6 +24,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
@@ -205,6 +206,19 @@
         }
 
         /**
+         * Set the watched UIDs for this request. This will be reset and wiped out unless
+         * the calling app holds the CHANGE_NETWORK_STATE permission.
+         *
+         * @param uids The watched UIDs as a set of UidRanges, or null for everything.
+         * @return The builder to facilitate chaining.
+         * @hide
+         */
+        public Builder setUids(Set<UidRange> uids) {
+            mNetworkCapabilities.setUids(uids);
+            return this;
+        }
+
+        /**
          * Add a capability that must not exist in the requested network.
          * <p>
          * If the capability was previously added to the list of required capabilities (for
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 5312dca..f5a7433 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -357,6 +357,23 @@
     }
 
     /**
+     * Does a loose equality check between two given {@link BaseBundle} objects.
+     * Returns {@code true} if both are {@code null}, or if both are equal as per
+     * {@link #kindofEquals(BaseBundle)}
+     *
+     * @param a A {@link BaseBundle} object
+     * @param b Another {@link BaseBundle} to compare with a
+     * @return {@code true} if both are the same, {@code false} otherwise
+     *
+     * @see #kindofEquals(BaseBundle)
+     *
+     * @hide
+     */
+    public static boolean kindofEquals(BaseBundle a, BaseBundle b) {
+        return (a == b) || (a != null && a.kindofEquals(b));
+    }
+
+    /**
      * @hide This kind-of does an equality comparison.  Kind-of.
      */
     public boolean kindofEquals(BaseBundle other) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b16e7d7..f528d63 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -7138,13 +7138,20 @@
 
                 for (int isvc = serviceStats.size() - 1; isvc >= 0; --isvc) {
                     final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+
+                    final long startTimeMs = roundUsToMs(ss.getStartTime(batteryUptimeUs, which));
+                    final int starts = ss.getStarts(which);
+                    final int launches = ss.getLaunches(which);
+                    if (startTimeMs == 0 && starts == 0 && launches == 0) {
+                        continue;
+                    }
+
                     long sToken = proto.start(UidProto.Package.SERVICES);
 
                     proto.write(UidProto.Package.Service.NAME, serviceStats.keyAt(isvc));
-                    proto.write(UidProto.Package.Service.START_DURATION_MS,
-                            roundUsToMs(ss.getStartTime(batteryUptimeUs, which)));
-                    proto.write(UidProto.Package.Service.START_COUNT, ss.getStarts(which));
-                    proto.write(UidProto.Package.Service.LAUNCH_COUNT, ss.getLaunches(which));
+                    proto.write(UidProto.Package.Service.START_DURATION_MS, startTimeMs);
+                    proto.write(UidProto.Package.Service.START_COUNT, starts);
+                    proto.write(UidProto.Package.Service.LAUNCH_COUNT, launches);
 
                     proto.end(sToken);
                 }
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 44bd35a..0ae5394 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -23,6 +23,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 
+import com.android.internal.os.BinderCallsStats;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
@@ -712,6 +713,8 @@
     // Entry point from android_util_Binder.cpp's onTransact
     private boolean execTransact(int code, long dataObj, long replyObj,
             int flags) {
+        BinderCallsStats binderCallsStats = BinderCallsStats.getInstance();
+        BinderCallsStats.CallSession callSession = binderCallsStats.callStarted(this, code);
         Parcel data = Parcel.obtain(dataObj);
         Parcel reply = Parcel.obtain(replyObj);
         // theoretically, we should call transact, which will call onTransact,
@@ -756,6 +759,7 @@
         // to the main transaction loop to wait for another incoming transaction.  Either
         // way, strict mode begone!
         StrictMode.clearGatheredViolations();
+        binderCallsStats.callEnded(callSession);
 
         return res;
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b9aad11..86f02e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7762,6 +7762,37 @@
         public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
 
         /**
+         * What behavior should be invoked when the volume hush gesture is triggered
+         * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE.
+         *
+         * @hide
+         */
+        public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
+
+        /** @hide */ public static final int VOLUME_HUSH_OFF = 0;
+        /** @hide */ public static final int VOLUME_HUSH_VIBRATE = 1;
+        /** @hide */ public static final int VOLUME_HUSH_MUTE = 2;
+
+        private static final Validator VOLUME_HUSH_GESTURE_VALIDATOR =
+                NON_NEGATIVE_INTEGER_VALIDATOR;
+
+        /**
+         * The number of times (integer) the user has manually enabled battery saver.
+         * @hide
+         */
+        public static final String LOW_POWER_MANUAL_ACTIVATION_COUNT =
+                "low_power_manual_activation_count";
+
+        /**
+         * Whether the "first time battery saver warning" dialog needs to be shown (0: default)
+         * or not (1).
+         *
+         * @hide
+         */
+        public static final String LOW_POWER_WARNING_ACKNOWLEDGED =
+                "low_power_warning_acknowledged";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -7859,6 +7890,7 @@
             SCREENSAVER_ACTIVATE_ON_SLEEP,
             LOCKDOWN_IN_POWER_MENU,
             SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+            VOLUME_HUSH_GESTURE
         };
 
         /**
@@ -7995,6 +8027,7 @@
             VALIDATORS.put(LOCKDOWN_IN_POWER_MENU, LOCKDOWN_IN_POWER_MENU_VALIDATOR);
             VALIDATORS.put(SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
                     SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR);
+            VALIDATORS.put(VOLUME_HUSH_GESTURE, VOLUME_HUSH_GESTURE_VALIDATOR);
             VALIDATORS.put(ENABLED_NOTIFICATION_LISTENERS,
                     ENABLED_NOTIFICATION_LISTENERS_VALIDATOR); //legacy restore setting
             VALIDATORS.put(ENABLED_NOTIFICATION_ASSISTANT,
@@ -9634,6 +9667,21 @@
         public static final String WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED =
                 "wifi_connected_mac_randomization_enabled";
 
+        /**
+         * Parameters to adjust the performance of framework wifi scoring methods.
+         * <p>
+         * Encoded as a comma-separated key=value list, for example:
+         *   "rssi5=-80:-77:-70:-57,rssi2=-83:-80:-73:-60,horizon=15"
+         * This is intended for experimenting with new parameter values,
+         * and is normally unset or empty. The example does not include all
+         * parameters that may be honored.
+         * Default values are provided by code or device configurations.
+         * Errors in the parameters will cause the entire setting to be ignored.
+         * @hide
+         */
+        public static final String WIFI_SCORE_PARAMS =
+                "wifi_score_params";
+
        /**
         * The maximum number of times we will retry a connection to an access
         * point for which we have failed in acquiring an IP address from DHCP.
@@ -11594,8 +11642,8 @@
          */
         @SystemApi
         @TestApi
-        public static final String AUTOFILL_COMPAT_ALLOWED_PACKAGES =
-                "autofill_compat_allowed_packages";
+        public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
+                "autofill_compat_mode_allowed_packages";
 
         /**
          * Exemptions to the hidden API blacklist.
diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index 3d3b6d5..d42424e 100644
--- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -52,7 +52,7 @@
 public final class KeyChainProtectionParams implements Parcelable {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN, TYPE_CUSTOM_PASSWORD})
+    @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN})
     public @interface UserSecretType {
     }
 
@@ -61,11 +61,6 @@
      */
     public static final int TYPE_LOCKSCREEN = 100;
 
-    /**
-     * Custom passphrase, unrelated to lock screen, is required to recover KeyStore.
-     */
-    public static final int TYPE_CUSTOM_PASSWORD = 101;
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"UI_FORMAT_"}, value = {UI_FORMAT_PIN, UI_FORMAT_PASSWORD, UI_FORMAT_PATTERN})
@@ -120,7 +115,6 @@
 
     /**
      * @see TYPE_LOCKSCREEN
-     * @see TYPE_CUSTOM_PASSWORD
      */
     public @UserSecretType int getUserSecretType() {
         return mUserSecretType;
@@ -166,7 +160,6 @@
          * Sets user secret type.
          *
          * @see TYPE_LOCKSCREEN
-         * @see TYPE_CUSTOM_PASSWORD
          * @param userSecretType The secret type
          * @return This builder.
          */
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 10c1c9e..6041561 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -35,6 +35,7 @@
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertPath;
 import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -409,8 +410,7 @@
      * Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them
      * is necessary to recover data.
      *
-     * @param secretTypes {@link KeyChainProtectionParams#TYPE_LOCKSCREEN} or {@link
-     *     KeyChainProtectionParams#TYPE_CUSTOM_PASSWORD}
+     * @param secretTypes {@link KeyChainProtectionParams#TYPE_LOCKSCREEN}
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
      */
@@ -449,51 +449,6 @@
     }
 
     /**
-     * Returns a list of recovery secret types, necessary to create a pending recovery snapshot.
-     * When user enters a secret of a pending type {@link #recoverySecretAvailable} should be
-     * called.
-     *
-     * @return list of recovery secret types
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
-     */
-    @NonNull
-    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
-    public @KeyChainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes()
-            throws InternalRecoveryServiceException {
-        try {
-            return mBinder.getPendingRecoverySecretTypes();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw wrapUnexpectedServiceSpecificException(e);
-        }
-    }
-
-    /**
-     * Method notifies KeyStore that a user-generated secret is available. This method generates a
-     * symmetric session key which a trusted remote device can use to return a recovery key. Caller
-     * should use {@link KeyChainProtectionParams#clearSecret} to override the secret value in
-     * memory.
-     *
-     * @param recoverySecret user generated secret together with parameters necessary to regenerate
-     *     it on a new device.
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
-     */
-    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
-    public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
-            throws InternalRecoveryServiceException {
-        try {
-            mBinder.recoverySecretAvailable(recoverySecret);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        } catch (ServiceSpecificException e) {
-            throw wrapUnexpectedServiceSpecificException(e);
-        }
-    }
-
-    /**
      * Deprecated.
      * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
      * key store. Returns the raw material of the key.
@@ -578,7 +533,7 @@
             if (grantAlias == null) {
                 throw new InternalRecoveryServiceException("Null grant alias");
             }
-            return getKeyFromGrant(alias);
+            return getKeyFromGrant(grantAlias);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (UnrecoverableKeyException e) {
@@ -654,6 +609,11 @@
         return RecoverySession.newInstance(this);
     }
 
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public Map<String, X509Certificate> getRootCertificates() {
+        return TrustedRootCertificates.getRootCertificates();
+    }
+
     InternalRecoveryServiceException wrapUnexpectedServiceSpecificException(
             ServiceSpecificException e) {
         if (e.errorCode == ERROR_SERVICE_INTERNAL_ERROR) {
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 744bfa3..208b9b2 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -77,7 +77,7 @@
     }
 
     /**
-     * @deprecated Use {@link #start(CertPath, byte[], byte[], List)} instead.
+     * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -108,25 +108,9 @@
     }
 
     /**
-     * Starts a recovery session and returns a blob with proof of recovery secret possession.
-     * The method generates a symmetric key for a session, which trusted remote device can use to
-     * return recovery key.
-     *
-     * @param verifierCertPath The certificate path used to create the recovery blob on the source
-     *     device. Keystore will verify the certificate path by using the root of trust.
-     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
-     *     Used to limit number of guesses.
-     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
-     *     replay attacks.
-     * @param secrets Secrets provided by user, the method only uses type and secret fields.
-     * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
-     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
-     *     key and parameters necessary to identify the counter with the number of failed recovery
-     *     attempts.
-     * @throws CertificateException if the {@code verifierCertPath} is invalid.
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
+     * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     @NonNull public byte[] start(
             @NonNull CertPath verifierCertPath,
@@ -179,8 +163,6 @@
      * @throws CertificateException if the {@code verifierCertPath} is invalid.
      * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
      *     service.
-     *
-     * @hide
      */
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     @NonNull public byte[] start(
@@ -215,17 +197,9 @@
     }
 
     /**
-     * Imports keys.
-     *
-     * @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
-     * @param applicationKeys Application keys. Key material can be decrypted using recoveryKeyBlob
-     *     and session. KeyStore only uses package names from the application info in {@link
-     *     WrappedApplicationKey}. Caller is responsibility to perform certificates check.
-     * @return Map from alias to raw key material.
-     * @throws SessionExpiredException if {@code session} has since been closed.
-     * @throws DecryptionFailedException if unable to decrypt the snapshot.
-     * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
+     * @deprecated Use {@link #recoverKeyChainSnapshot(byte[], List)} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public Map<String, byte[]> recoverKeys(
             @NonNull byte[] recoveryKeyBlob,
@@ -257,8 +231,6 @@
      * @throws SessionExpiredException if {@code session} has since been closed.
      * @throws DecryptionFailedException if unable to decrypt the snapshot.
      * @throws InternalRecoveryServiceException if an error occurs internal to the recovery service.
-     *
-     * @hide
      */
     @RequiresPermission(Manifest.permission.RECOVER_KEYSTORE)
     public Map<String, Key> recoverKeyChainSnapshot(
diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
index 4bdde8a..a65b40f 100644
--- a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
+++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
@@ -32,7 +32,7 @@
  *
  * @hide
  */
-public class TrustedRootCertificates {
+public final class TrustedRootCertificates {
 
     public static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS =
             "GoogleCloudKeyVaultServiceV1";
@@ -83,7 +83,7 @@
     /**
      * Returns all available root certificates, keyed by alias.
      */
-    public static Map<String, X509Certificate> listRootCertificates() {
+    public static Map<String, X509Certificate> getRootCertificates() {
         return new ArrayMap(ALL_ROOT_CERTIFICATES);
     }
 
@@ -114,4 +114,7 @@
             throw new RuntimeException(e);
         }
     }
+
+    // Statics only
+    private TrustedRootCertificates() {}
 }
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 41e4181..60537a4 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -518,7 +518,7 @@
  *     &lt;intent-filter&gt;
  *         &lt;action android:name="android.service.autofill.AutofillService" /&gt;
  *     &lt;/intent-filter&gt;
- *     &lt;meta-data android:name="android.autofillservice" android:resource="@xml/autofillservice" /&gt;
+ *     &lt;meta-data android:name="android.autofill" android:resource="@xml/autofillservice" /&gt;
  * &lt;/service&gt;</pre>
  *
  * <P>In the XML file you can specify one or more packages for which to enable compatibility
@@ -527,6 +527,9 @@
  * <pre> &lt;autofill-service xmlns:android="http://schemas.android.com/apk/res/android"&gt;
  *     &lt;compatibility-package android:name="foo.bar.baz" android:maxLongVersionCode="1000000000"/&gt;
  * &lt;/autofill-service&gt;</pre>
+ *
+ * <p>When using compatibility mode, the {@link SaveInfo.Builder#setFlags(int) SaveInfo flags}
+ * automatically include {@link SaveInfo#FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE}.
  */
 public abstract class AutofillService extends Service {
     private static final String TAG = "AutofillService";
diff --git a/core/java/android/service/autofill/AutofillServiceHelper.java b/core/java/android/service/autofill/AutofillServiceHelper.java
new file mode 100644
index 0000000..bbaebff
--- /dev/null
+++ b/core/java/android/service/autofill/AutofillServiceHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.Nullable;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.Preconditions;
+
+/** @hide */
+final class AutofillServiceHelper {
+
+    static AutofillId[] assertValid(@Nullable AutofillId[] ids) {
+        Preconditions.checkArgument(ids != null && ids.length > 0, "must have at least one id");
+        return Preconditions.checkArrayElementsNotNull(ids, "ids");
+    }
+
+    private AutofillServiceHelper() {
+        throw new UnsupportedOperationException("contains static members only");
+    }
+}
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index de23455..b7ec281 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -198,14 +198,6 @@
                     } else {
                         maxVersionCode = Long.MAX_VALUE;
                     }
-                    if (true) { // TODO(b/74445943): remove block after P DP2 is branched
-                        final String urlBarResourceId = cpAttributes.getString(
-                                R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
-                        if (urlBarResourceId != null) {
-                            Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'");
-                        }
-                    }
-
                     if (compatibilityPackages == null) {
                         compatibilityPackages = new ArrayMap<>();
                     }
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index f32dee1..ccec483 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -149,24 +149,33 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        final StringBuilder builder = new StringBuilder("Dataset[id=");
+        final StringBuilder builder = new StringBuilder("Dataset[");
         if (mId == null) {
-            builder.append("null");
+            builder.append("noId");
         } else {
             // Cannot disclose id because it could contain PII.
-            builder.append(mId.length()).append("_chars");
+            builder.append("id=").append(mId.length()).append("_chars");
         }
+        if (mFieldIds != null) {
+            builder.append(", fieldIds=").append(mFieldIds);
+        }
+        if (mFieldValues != null) {
+            builder.append(", fieldValues=").append(mFieldValues);
+        }
+        if (mFieldPresentations != null) {
+            builder.append(", fieldPresentations=").append(mFieldPresentations.size());
 
-        return builder
-                .append(", fieldIds=").append(mFieldIds)
-                .append(", fieldValues=").append(mFieldValues)
-                .append(", fieldPresentations=")
-                .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
-                .append(", fieldFilters=")
-                .append(mFieldFilters == null ? 0 : mFieldFilters.size())
-                .append(", hasPresentation=").append(mPresentation != null)
-                .append(", hasAuthentication=").append(mAuthentication != null)
-                .append(']').toString();
+        }
+        if (mFieldFilters != null) {
+            builder.append(", fieldFilters=").append(mFieldFilters.size());
+        }
+        if (mPresentation != null) {
+            builder.append(", hasPresentation");
+        }
+        if (mAuthentication != null) {
+            builder.append(", hasAuthentication");
+        }
+        return builder.append(']').toString();
     }
 
     /**
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 3a4b6bb..2bc4b8f 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -16,6 +16,7 @@
 
 package android.service.autofill;
 
+import static android.service.autofill.AutofillServiceHelper.assertValid;
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
 import static android.view.autofill.Helper.sDebug;
 
@@ -245,10 +246,15 @@
          * @param ids id of Views that when focused will display the authentication UI.
          *
          * @return This builder.
-
-         * @throws IllegalArgumentException if {@code ids} is {@code null} or empty, or if
-         * both {@code authentication} and {@code presentation} are {@code null}, or if
-         * both {@code authentication} and {@code presentation} are non-{@code null}
+         *
+         * @throws IllegalArgumentException if any of the following occurs:
+         * <ul>
+         *   <li>{@code ids} is {@code null}</li>
+         *   <li>{@code ids} is empty</li>
+         *   <li>{@code ids} contains a {@code null} element</li>
+         *   <li>both {@code authentication} and {@code presentation} are {@code null}</li>
+         *   <li>both {@code authentication} and {@code presentation} are non-{@code null}</li>
+         * </ul>
          *
          * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a
          * {@link #setFooter(RemoteViews) footer} are already set for this builder.
@@ -263,16 +269,13 @@
                 throw new IllegalStateException("Already called #setHeader() or #setFooter()");
             }
 
-            if (ids == null || ids.length == 0) {
-                throw new IllegalArgumentException("ids cannot be null or empry");
-            }
             if (authentication == null ^ presentation == null) {
                 throw new IllegalArgumentException("authentication and presentation"
                         + " must be both non-null or null");
             }
             mAuthentication = authentication;
             mPresentation = presentation;
-            mAuthenticationIds = ids;
+            mAuthenticationIds = assertValid(ids);
             return this;
         }
 
@@ -554,23 +557,40 @@
         if (!sDebug) return super.toString();
 
         // TODO: create a dump() method instead
-        return new StringBuilder(
-                "FillResponse : [mRequestId=" + mRequestId)
-                .append(", datasets=").append(mDatasets == null ? "N/A" : mDatasets.getList())
-                .append(", saveInfo=").append(mSaveInfo)
-                .append(", clientState=").append(mClientState != null)
-                .append(", hasPresentation=").append(mPresentation != null)
-                .append(", hasHeader=").append(mHeader != null)
-                .append(", hasFooter=").append(mFooter != null)
-                .append(", hasAuthentication=").append(mAuthentication != null)
-                .append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds))
-                .append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
-                .append(", disableDuration=").append(mDisableDuration)
-                .append(", flags=").append(mFlags)
-                .append(", fieldClassificationIds=")
-                    .append(Arrays.toString(mFieldClassificationIds))
-                .append("]")
-                .toString();
+        final StringBuilder builder = new StringBuilder(
+                "FillResponse : [mRequestId=" + mRequestId);
+        if (mDatasets != null) {
+            builder.append(", datasets=").append(mDatasets.getList());
+        }
+        if (mSaveInfo != null) {
+            builder.append(", saveInfo=").append(mSaveInfo);
+        }
+        if (mClientState != null) {
+            builder.append(", hasClientState");
+        }
+        if (mPresentation != null) {
+            builder.append(", hasPresentation");
+        }
+        if (mHeader != null) {
+            builder.append(", hasHeader");
+        }
+        if (mFooter != null) {
+            builder.append(", hasFooter");
+        }
+        if (mAuthentication != null) {
+            builder.append(", hasAuthentication");
+        }
+        if (mAuthenticationIds != null) {
+            builder.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds));
+        }
+        builder.append(", disableDuration=").append(mDisableDuration);
+        if (mFlags != 0) {
+            builder.append(", flags=").append(mFlags);
+        }
+        if (mFieldClassificationIds != null) {
+            builder.append(Arrays.toString(mFieldClassificationIds));
+        }
+        return builder.append("]").toString();
     }
 
     /////////////////////////////////////
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index a5a6177..4943fc8 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -16,6 +16,7 @@
 
 package android.service.autofill;
 
+import static android.service.autofill.AutofillServiceHelper.assertValid;
 import static android.view.autofill.Helper.sDebug;
 
 import android.annotation.IntDef;
@@ -405,17 +406,6 @@
             mRequiredIds = null;
         }
 
-        private AutofillId[] assertValid(AutofillId[] ids) {
-            Preconditions.checkArgument(ids != null && ids.length > 0,
-                    "must have at least one id: " + Arrays.toString(ids));
-            for (int i = 0; i < ids.length; i++) {
-                final AutofillId id = ids[i];
-                Preconditions.checkArgument(id != null,
-                        "cannot have null id: " + Arrays.toString(ids));
-            }
-            return ids;
-        }
-
         /**
          * Sets flags changing the save behavior.
          *
@@ -699,22 +689,37 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        return new StringBuilder("SaveInfo: [type=")
+        final StringBuilder builder = new StringBuilder("SaveInfo: [type=")
                 .append(DebugUtils.flagsToString(SaveInfo.class, "SAVE_DATA_TYPE_", mType))
                 .append(", requiredIds=").append(Arrays.toString(mRequiredIds))
-                .append(", optionalIds=").append(Arrays.toString(mOptionalIds))
-                .append(", description=").append(mDescription)
-                .append(DebugUtils.flagsToString(SaveInfo.class, "NEGATIVE_BUTTON_STYLE_",
-                        mNegativeButtonStyle))
-                .append(", flags=").append(mFlags)
-                .append(", customDescription=").append(mCustomDescription)
-                .append(", validator=").append(mValidator)
-                .append(", sanitizerKeys=")
-                    .append(mSanitizerKeys == null ? "N/A:" : mSanitizerKeys.length)
-                .append(", sanitizerValues=")
-                    .append(mSanitizerValues == null ? "N/A:" : mSanitizerValues.length)
-                .append(", triggerId=").append(mTriggerId)
-                .append("]").toString();
+                .append(", style=").append(DebugUtils.flagsToString(SaveInfo.class,
+                        "NEGATIVE_BUTTON_STYLE_", mNegativeButtonStyle));
+        if (mOptionalIds != null) {
+            builder.append(", optionalIds=").append(Arrays.toString(mOptionalIds));
+        }
+        if (mDescription != null) {
+            builder.append(", description=").append(mDescription);
+        }
+        if (mFlags != 0) {
+            builder.append(", flags=").append(mFlags);
+        }
+        if (mCustomDescription != null) {
+            builder.append(", customDescription=").append(mCustomDescription);
+        }
+        if (mValidator != null) {
+            builder.append(", validator=").append(mValidator);
+        }
+        if (mSanitizerKeys != null) {
+            builder.append(", sanitizerKeys=").append(mSanitizerKeys.length);
+        }
+        if (mSanitizerValues != null) {
+            builder.append(", sanitizerValues=").append(mSanitizerValues.length);
+        }
+        if (mTriggerId != null) {
+            builder.append(", triggerId=").append(mTriggerId);
+        }
+
+        return builder.append("]").toString();
     }
 
     /////////////////////////////////////
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 18431ca..febca7e 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -704,7 +704,12 @@
         // Spans other than ReplacementSpan can be ignored because line top and bottom are
         // disjunction of all tops and bottoms, although it's not optimal.
         final Paint paint = getPaint();
-        paint.getTextBounds(text, start, end, mTempRect);
+        if (text instanceof PrecomputedText) {
+            PrecomputedText precomputed = (PrecomputedText) text;
+            precomputed.getBounds(start, end, mTempRect);
+        } else {
+            paint.getTextBounds(text, start, end, mTempRect);
+        }
         final Paint.FontMetricsInt fm = paint.getFontMetricsInt();
         return mTempRect.top < fm.top || mTempRect.bottom > fm.bottom;
     }
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 980f4704..a107cab 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Paint;
+import android.graphics.Rect;
 import android.text.AutoGrowArray.ByteArray;
 import android.text.AutoGrowArray.FloatArray;
 import android.text.AutoGrowArray.IntArray;
@@ -297,6 +298,18 @@
     }
 
     /**
+     * Retrieves the bounding rectangle that encloses all of the characters, with an implied origin
+     * at (0, 0).
+     *
+     * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
+     */
+    public void getBounds(@NonNull Paint paint, @IntRange(from = 0) int start,
+            @IntRange(from = 0) int end, @NonNull Rect bounds) {
+        nGetBounds(mNativePtr, mCopiedBuffer, paint.getNativeInstance(), start, end,
+                paint.getBidiFlags(), bounds);
+    }
+
+    /**
      * Generates new MeasuredParagraph for Bidi computation.
      *
      * If recycle is null, this returns new instance. If recycle is not null, this fills computed
@@ -728,4 +741,7 @@
 
     @CriticalNative
     private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr);
+
+    private static native void nGetBounds(long nativePtr, char[] buf, long paintPtr, int start,
+            int end, int bidiFlag, Rect rect);
 }
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 9458184..413df05 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -19,6 +19,8 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.text.style.MetricAffectingSpan;
 
 import com.android.internal.util.Preconditions;
 
@@ -57,10 +59,12 @@
  * </pre>
  *
  * Note that the {@link PrecomputedText} created from different parameters of the target
- * {@link android.widget.TextView} will be rejected internally and compute the text layout again
- * with the current {@link android.widget.TextView} parameters.
+ * {@link android.widget.TextView} will be rejected.
+ *
+ * Note that any {@link android.text.NoCopySpan} attached to the original text won't be passed to
+ * PrecomputedText.
  */
-public class PrecomputedText implements Spanned {
+public class PrecomputedText implements Spannable {
     private static final char LINE_FEED = '\n';
 
     /**
@@ -283,7 +287,7 @@
 
 
     // The original text.
-    private final @NonNull SpannedString mText;
+    private final @NonNull SpannableString mText;
 
     // The inclusive start offset of the measuring target.
     private final @IntRange(from = 0) int mStart;
@@ -304,6 +308,9 @@
      * presented can save work on the UI thread.
      * </p>
      *
+     * Note that any {@link android.text.NoCopySpan} attached to the text won't be passed to the
+     * created PrecomputedText.
+     *
      * @param text the text to be measured
      * @param params parameters that define how text will be precomputed
      * @return A {@link PrecomputedText}
@@ -347,7 +354,7 @@
     private PrecomputedText(@NonNull CharSequence text, @IntRange(from = 0) int start,
             @IntRange(from = 0) int end, @NonNull Params params,
             @NonNull ParagraphInfo[] paraInfo) {
-        mText = new SpannedString(text);
+        mText = new SpannableString(text, true /* ignoreNoCopySpan */);
         mStart = start;
         mEnd = end;
         mParams = params;
@@ -457,6 +464,21 @@
         return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart);
     }
 
+    /** @hide */
+    public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
+            @NonNull Rect bounds) {
+        final int paraIndex = findParaIndex(start);
+        final int paraStart = getParagraphStart(paraIndex);
+        final int paraEnd = getParagraphEnd(paraIndex);
+        if (start < paraStart || paraEnd < end) {
+            throw new RuntimeException("Cannot measured across the paragraph:"
+                + "para: (" + paraStart + ", " + paraEnd + "), "
+                + "request: (" + start + ", " + end + ")");
+        }
+        getMeasuredParagraph(paraIndex).getBounds(mParams.mPaint,
+                start - paraStart, end - paraStart, bounds);
+    }
+
     /**
      * Returns the size of native PrecomputedText memory usage.
      *
@@ -472,6 +494,35 @@
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Spannable overrides
+    //
+    // Do not allow to modify MetricAffectingSpan
+
+    /**
+     * @throws IllegalArgumentException if {@link MetricAffectingSpan} is specified.
+     */
+    @Override
+    public void setSpan(Object what, int start, int end, int flags) {
+        if (what instanceof MetricAffectingSpan) {
+            throw new IllegalArgumentException(
+                    "MetricAffectingSpan can not be set to PrecomputedText.");
+        }
+        mText.setSpan(what, start, end, flags);
+    }
+
+    /**
+     * @throws IllegalArgumentException if {@link MetricAffectingSpan} is specified.
+     */
+    @Override
+    public void removeSpan(Object what) {
+        if (what instanceof MetricAffectingSpan) {
+            throw new IllegalArgumentException(
+                    "MetricAffectingSpan can not be removed from PrecomputedText.");
+        }
+        mText.removeSpan(what);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
     // Spanned overrides
     //
     // Just proxy for underlying mText if appropriate.
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 3a22db2..435e324 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -650,7 +650,8 @@
         final CharSequence truncatedText = text.subSequence(
                 0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength()));
 
-        final Supplier<TextLinks> supplier = () -> classifier.generateLinks(truncatedText, options);
+        final Supplier<TextLinks> supplier = () ->
+                classifier.generateLinks(truncatedText, options.setLegacyFallback(true));
         final Consumer<TextLinks> consumer = links -> {
             if (links.getLinks().isEmpty()) {
                 if (callback != null) {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 38ab6f2..9687009 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,7 +42,7 @@
         DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
         DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
-        DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
+        DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
         DEFAULT_FLAGS.put("settings_audio_switcher", "false");
     }
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7ff4f21..d4610a5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -353,8 +353,8 @@
         private int mFormat = PixelFormat.OPAQUE;
         private String mName;
         private SurfaceControl mParent;
-        private int mWindowType;
-        private int mOwnerUid;
+        private int mWindowType = -1;
+        private int mOwnerUid = -1;
 
         /**
          * Begin building a SurfaceControl with a given {@link SurfaceSession}.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 69938cb..abc19d0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2882,9 +2882,8 @@
         /**
          * @hide
          */
-        public String toString(String prefix) {
-            StringBuilder sb = new StringBuilder(256);
-            sb.append("{(");
+        public void dumpDimensions(StringBuilder sb) {
+            sb.append('(');
             sb.append(x);
             sb.append(',');
             sb.append(y);
@@ -2895,6 +2894,15 @@
             sb.append((height == MATCH_PARENT ? "fill" : (height == WRAP_CONTENT
                     ? "wrap" : String.valueOf(height))));
             sb.append(")");
+        }
+
+        /**
+         * @hide
+         */
+        public String toString(String prefix) {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append('{');
+            dumpDimensions(sb);
             if (horizontalMargin != 0) {
                 sb.append(" hm=");
                 sb.append(horizontalMargin);
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index c783cae..2a24dd7 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -30,6 +30,8 @@
 import android.service.textclassifier.ITextSelectionCallback;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.util.Preconditions;
 
 import java.util.concurrent.CountDownLatch;
@@ -37,8 +39,10 @@
 
 /**
  * Proxy to the system's default TextClassifier.
+ * @hide
  */
-final class SystemTextClassifier implements TextClassifier {
+@VisibleForTesting(visibility = Visibility.PACKAGE)
+public final class SystemTextClassifier implements TextClassifier {
 
     private static final String LOG_TAG = "SystemTextClassifier";
 
@@ -53,13 +57,13 @@
     @GuardedBy("mLoggerLock")
     private Logger mLogger;
 
-    SystemTextClassifier(Context context, TextClassificationConstants settings)
+    public SystemTextClassifier(Context context, TextClassificationConstants settings)
                 throws ServiceManager.ServiceNotFoundException {
         mManagerService = ITextClassifierService.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE));
         mSettings = Preconditions.checkNotNull(settings);
         mFallback = new TextClassifierImpl(context, settings);
-        mPackageName = context.getPackageName();
+        mPackageName = Preconditions.checkNotNull(context.getPackageName());
     }
 
     /**
@@ -124,8 +128,9 @@
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
         Utils.validate(text, false /* allowInMainThread */);
 
-        if (!mSettings.isSmartLinkifyEnabled()) {
-            return TextClassifier.NO_OP.generateLinks(text, options);
+        final boolean legacyFallback = options != null && options.isLegacyFallback();
+        if (!mSettings.isSmartLinkifyEnabled() && legacyFallback) {
+            return Utils.generateLegacyLinks(text, options);
         }
 
         try {
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index c91116a..b5c9de9 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -344,6 +344,25 @@
         }
     }
 
+    /**
+     * Triggers the specified intent.
+     *
+     * @throws IllegalArgumentException if context or intent is null
+     * @hide
+     */
+    public static void fireIntent(@NonNull final Context context, @NonNull final Intent intent) {
+        switch (getIntentType(intent, context)) {
+            case IntentType.ACTIVITY:
+                context.startActivity(intent);
+                return;
+            case IntentType.SERVICE:
+                context.startService(intent);
+                return;
+            default:
+                return;
+        }
+    }
+
     @IntentType
     private static int getIntentType(@NonNull Intent intent, @NonNull Context context) {
         Preconditions.checkArgument(context != null);
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 887bebb..98fa574 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -26,6 +26,12 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.URLSpan;
+import android.text.util.Linkify;
+import android.text.util.Linkify.LinkifyMask;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -37,6 +43,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Interface for providing text classification related features.
@@ -511,6 +518,65 @@
             Preconditions.checkArgumentInRange(text.length(), 0, maxLength, "text.length()");
         }
 
+        /**
+         * Generates links using legacy {@link Linkify}.
+         */
+        public static TextLinks generateLegacyLinks(
+                @NonNull CharSequence text, @NonNull TextLinks.Options options) {
+            final String string = Preconditions.checkNotNull(text).toString();
+            final TextLinks.Builder links = new TextLinks.Builder(string);
+
+            final List<String> entities = Preconditions.checkNotNull(options).getEntityConfig()
+                    .resolveEntityListModifications(Collections.emptyList());
+            if (entities.contains(TextClassifier.TYPE_URL)) {
+                addLinks(links, string, TextClassifier.TYPE_URL);
+            }
+            if (entities.contains(TextClassifier.TYPE_PHONE)) {
+                addLinks(links, string, TextClassifier.TYPE_PHONE);
+            }
+            if (entities.contains(TextClassifier.TYPE_EMAIL)) {
+                addLinks(links, string, TextClassifier.TYPE_EMAIL);
+            }
+            // NOTE: Do not support MAP_ADDRESSES. Legacy version does not work well.
+            return links.build();
+        }
+
+        private static void addLinks(
+                TextLinks.Builder links, String string, @EntityType String entityType) {
+            final Spannable spannable = new SpannableString(string);
+            if (Linkify.addLinks(spannable, linkMask(entityType))) {
+                final URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+                for (URLSpan urlSpan : spans) {
+                    links.addLink(
+                            spannable.getSpanStart(urlSpan),
+                            spannable.getSpanEnd(urlSpan),
+                            entityScores(entityType),
+                            urlSpan);
+                }
+            }
+        }
+
+        @LinkifyMask
+        private static int linkMask(@EntityType String entityType) {
+            switch (entityType) {
+                case TextClassifier.TYPE_URL:
+                    return Linkify.WEB_URLS;
+                case TextClassifier.TYPE_PHONE:
+                    return Linkify.PHONE_NUMBERS;
+                case TextClassifier.TYPE_EMAIL:
+                    return Linkify.EMAIL_ADDRESSES;
+                default:
+                    // NOTE: Do not support MAP_ADDRESSES. Legacy version does not work well.
+                    return 0;
+            }
+        }
+
+        private static Map<String, Float> entityScores(@EntityType String entityType) {
+            final Map<String, Float> scores = new ArrayMap<>();
+            scores.put(entityType, 1f);
+            return scores;
+        }
+
         private static void checkMainThread(boolean allowInMainThread) {
             if (!allowInMainThread && Looper.myLooper() == Looper.getMainLooper()) {
                 Slog.w(DEFAULT_LOG_TAG, "TextClassifier called on main thread");
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index a099820..c2fb032 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -209,13 +209,15 @@
     public TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
         Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
+
+        final boolean legacyFallback = options != null && options.isLegacyFallback();
+        if (!mSettings.isSmartLinkifyEnabled() && legacyFallback) {
+            return Utils.generateLegacyLinks(text, options);
+        }
+
         final String textString = text.toString();
         final TextLinks.Builder builder = new TextLinks.Builder(textString);
 
-        if (!mSettings.isSmartLinkifyEnabled()) {
-            return builder.build();
-        }
-
         try {
             final long startTimeMs = System.currentTimeMillis();
             final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
@@ -355,12 +357,10 @@
         final List<Locale.LanguageRange> languageRangeList = Locale.LanguageRange.parse(languages);
 
         ModelFile bestModel = null;
-        int bestModelVersion = -1;
         for (ModelFile model : listAllModelsLocked()) {
             if (model.isAnyLanguageSupported(languageRangeList)) {
-                if (model.getVersion() >= bestModelVersion) {
+                if (model.isPreferredTo(bestModel)) {
                     bestModel = model;
-                    bestModelVersion = model.getVersion();
                 }
             }
         }
@@ -482,6 +482,7 @@
         private final String mName;
         private final int mVersion;
         private final List<Locale> mSupportedLocales;
+        private final boolean mLanguageIndependent;
 
         /** Returns null if the path did not point to a compatible model. */
         static @Nullable ModelFile fromPath(String path) {
@@ -496,12 +497,14 @@
                     Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
                     return null;
                 }
+                final boolean languageIndependent = supportedLocalesStr.equals("*");
                 final List<Locale> supportedLocales = new ArrayList<>();
                 for (String langTag : supportedLocalesStr.split(",")) {
                     supportedLocales.add(Locale.forLanguageTag(langTag));
                 }
                 closeAndLogError(modelFd);
-                return new ModelFile(path, file.getName(), version, supportedLocales);
+                return new ModelFile(path, file.getName(), version, supportedLocales,
+                                     languageIndependent);
             } catch (FileNotFoundException e) {
                 Log.e(DEFAULT_LOG_TAG, "Failed to peek " + file.getAbsolutePath(), e);
                 return null;
@@ -525,7 +528,7 @@
 
         /** Returns whether the language supports any language in the given ranges. */
         boolean isAnyLanguageSupported(List<Locale.LanguageRange> languageRanges) {
-            return Locale.lookup(languageRanges, mSupportedLocales) != null;
+            return mLanguageIndependent || Locale.lookup(languageRanges, mSupportedLocales) != null;
         }
 
         /** All locales supported by the model. */
@@ -533,6 +536,25 @@
             return Collections.unmodifiableList(mSupportedLocales);
         }
 
+        public boolean isPreferredTo(ModelFile model) {
+            // A model is preferred to no model.
+            if (model == null) {
+                return true;
+            }
+
+            // A language-specific model is preferred to a language independent
+            // model.
+            if (!mLanguageIndependent && model.mLanguageIndependent) {
+                return true;
+            }
+
+            // A higher-version model is preferred.
+            if (getVersion() > model.getVersion()) {
+                return true;
+            }
+            return false;
+        }
+
         @Override
         public boolean equals(Object other) {
             if (this == other) {
@@ -555,11 +577,13 @@
                     mPath, mName, mVersion, localesJoiner.toString());
         }
 
-        private ModelFile(String path, String name, int version, List<Locale> supportedLocales) {
+        private ModelFile(String path, String name, int version, List<Locale> supportedLocales,
+                          boolean languageIndependent) {
             mPath = path;
             mName = name;
             mVersion = version;
             mSupportedLocales = supportedLocales;
+            mLanguageIndependent = languageIndependent;
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index af9fc7d..38a7d9a 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,17 +20,21 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Spannable;
 import android.text.style.ClickableSpan;
+import android.text.style.URLSpan;
 import android.text.util.Linkify;
 import android.text.util.Linkify.LinkifyMask;
 import android.view.View;
 import android.view.textclassifier.TextClassifier.EntityType;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -197,6 +201,7 @@
         private final EntityConfidence mEntityScores;
         private final int mStart;
         private final int mEnd;
+        @Nullable final URLSpan mUrlSpan;
 
         /**
          * Create a new TextLink.
@@ -204,16 +209,19 @@
          * @param start The start index of the identified subsequence
          * @param end The end index of the identified subsequence
          * @param entityScores A mapping of entity type to confidence score
+         * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled
          *
          * @throws IllegalArgumentException if entityScores is null or empty
          */
-        TextLink(int start, int end, Map<String, Float> entityScores) {
+        TextLink(int start, int end, Map<String, Float> entityScores,
+                @Nullable URLSpan urlSpan) {
             Preconditions.checkNotNull(entityScores);
             Preconditions.checkArgument(!entityScores.isEmpty());
             Preconditions.checkArgument(start <= end);
             mStart = start;
             mEnd = end;
             mEntityScores = new EntityConfidence(entityScores);
+            mUrlSpan = urlSpan;
         }
 
         /**
@@ -291,6 +299,7 @@
             mEntityScores = EntityConfidence.CREATOR.createFromParcel(in);
             mStart = in.readInt();
             mEnd = in.readInt();
+            mUrlSpan = null;
         }
     }
 
@@ -301,6 +310,7 @@
 
         private LocaleList mDefaultLocales;
         private TextClassifier.EntityConfig mEntityConfig;
+        private boolean mLegacyFallback;
 
         private @ApplyStrategy int mApplyStrategy;
         private Function<TextLink, TextLinkSpan> mSpanFactory;
@@ -354,6 +364,17 @@
         }
 
         /**
+         * Sets whether the TextClassifier can fallback to legacy links if smart linkify is
+         * disabled.
+         * <strong>Note: </strong>This is not parcelled.
+         * @hide
+         */
+        public Options setLegacyFallback(boolean legacyFallback) {
+            mLegacyFallback = legacyFallback;
+            return this;
+        }
+
+        /**
          * Sets a strategy for resolving conflicts when applying generated links to text that
          * already have links.
          *
@@ -406,6 +427,16 @@
         }
 
         /**
+         * Returns whether the TextClassifier can fallback to legacy links if smart linkify is
+         * disabled.
+         * <strong>Note: </strong>This is not parcelled.
+         * @hide
+         */
+        public boolean isLegacyFallback() {
+            return mLegacyFallback;
+        }
+
+        /**
          * @return the strategy for resolving conflictswhen applying generated links to text that
          * already have links
          *
@@ -497,7 +528,7 @@
 
         private final TextLink mTextLink;
 
-        public TextLinkSpan(@Nullable TextLink textLink) {
+        public TextLinkSpan(@NonNull TextLink textLink) {
             mTextLink = textLink;
         }
 
@@ -505,13 +536,38 @@
         public void onClick(View widget) {
             if (widget instanceof TextView) {
                 final TextView textView = (TextView) widget;
-                textView.requestActionMode(this);
+                final Context context = textView.getContext();
+                if (TextClassificationManager.getSettings(context).isSmartLinkifyEnabled()) {
+                    if (textView.requestFocus()) {
+                        textView.requestActionMode(this);
+                    } else {
+                        // If textView can not take focus, then simply handle the click as it will
+                        // be difficult to get rid of the floating action mode.
+                        textView.handleClick(this);
+                    }
+                } else {
+                    if (mTextLink.mUrlSpan != null) {
+                        mTextLink.mUrlSpan.onClick(textView);
+                    } else {
+                        textView.handleClick(this);
+                    }
+                }
             }
         }
 
         public final TextLink getTextLink() {
             return mTextLink;
         }
+
+        /** @hide */
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        @Nullable
+        public final String getUrl() {
+            if (mTextLink.mUrlSpan != null) {
+                return mTextLink.mUrlSpan.getURL();
+            }
+            return null;
+        }
     }
 
     /**
@@ -534,12 +590,24 @@
         /**
          * Adds a TextLink.
          *
-         * @return this instance
+         * @param start The start index of the identified subsequence
+         * @param end The end index of the identified subsequence
+         * @param entityScores A mapping of entity type to confidence score
          *
          * @throws IllegalArgumentException if entityScores is null or empty.
          */
         public Builder addLink(int start, int end, Map<String, Float> entityScores) {
-            mLinks.add(new TextLink(start, end, entityScores));
+            mLinks.add(new TextLink(start, end, entityScores, null));
+            return this;
+        }
+
+        /**
+         * @see #addLink(int, int, Map)
+         * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled.
+         */
+        Builder addLink(int start, int end, Map<String, Float> entityScores,
+                @Nullable URLSpan urlSpan) {
+            mLinks.add(new TextLink(start, end, entityScores, urlSpan));
             return this;
         }
 
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
index 68badec..d95ca61 100644
--- a/core/java/android/webkit/TracingConfig.java
+++ b/core/java/android/webkit/TracingConfig.java
@@ -35,9 +35,9 @@
     private @TracingMode int mTracingMode;
 
     /** @hide */
-    @IntDef(flag = true, value = {CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER,
-            CATEGORIES_INPUT_LATENCY, CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING,
-            CATEGORIES_FRAME_VIEWER})
+    @IntDef(flag = true, value = {CATEGORIES_NONE, CATEGORIES_ALL, CATEGORIES_ANDROID_WEBVIEW,
+            CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY, CATEGORIES_RENDERING,
+            CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
     @Retention(RetentionPolicy.SOURCE)
     public @interface PredefinedCategories {}
 
@@ -90,34 +90,28 @@
     public static final int CATEGORIES_FRAME_VIEWER = 1 << 6;
 
     /** @hide */
-    @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER})
+    @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY})
     @Retention(RetentionPolicy.SOURCE)
     public @interface TracingMode {}
 
     /**
-     * Record trace events until the internal tracing buffer is full. Default tracing mode.
-     * Typically the buffer memory usage is between {@link #RECORD_CONTINUOUSLY} and the
-     * {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}. Depending on the implementation typically allows
-     * up to 256k events to be stored.
+     * Record trace events until the internal tracing buffer is full.
+     *
+     * Typically the buffer memory usage is larger than {@link #RECORD_CONTINUOUSLY}.
+     * Depending on the implementation typically allows up to 256k events to be stored.
      */
     public static final int RECORD_UNTIL_FULL = 0;
 
     /**
-     * Record trace events continuously using an internal ring buffer. Overwrites
-     * old events if they exceed buffer capacity. Uses less memory than both
-     * {@link #RECORD_UNTIL_FULL} and {@link #RECORD_UNTIL_FULL_LARGE_BUFFER} modes.
-     * Depending on the implementation typically allows up to 64k events to be stored.
+     * Record trace events continuously using an internal ring buffer. Default tracing mode.
+     *
+     * Overwrites old events if they exceed buffer capacity. Uses less memory than the
+     * {@link #RECORD_UNTIL_FULL} mode. Depending on the implementation typically allows
+     * up to 64k events to be stored.
      */
     public static final int RECORD_CONTINUOUSLY = 1;
 
     /**
-     * Record trace events using a larger internal tracing buffer until it is full.
-     * Uses significantly more memory than {@link #RECORD_UNTIL_FULL} and may not be
-     * suitable on devices with smaller RAM.
-     */
-    public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
-
-    /**
      * @hide
      */
     public TracingConfig(@PredefinedCategories int predefinedCategories,
@@ -182,7 +176,7 @@
     public static class Builder {
         private @PredefinedCategories int mPredefinedCategories = CATEGORIES_NONE;
         private final List<String> mCustomIncludedCategories = new ArrayList<String>();
-        private @TracingMode int mTracingMode = RECORD_UNTIL_FULL;
+        private @TracingMode int mTracingMode = RECORD_CONTINUOUSLY;
 
         /**
          * Default constructor for Builder.
@@ -202,7 +196,9 @@
          *
          * @param predefinedCategories list or bitmask of predefined category sets to use:
          *                    {@link #CATEGORIES_NONE}, {@link #CATEGORIES_ALL},
-         *                    {@link #CATEGORIES_WEB_DEVELOPER}, {@link #CATEGORIES_INPUT_LATENCY},
+         *                    {@link #CATEGORIES_ANDROID_WEBVIEW},
+         *                    {@link #CATEGORIES_WEB_DEVELOPER},
+         *                    {@link #CATEGORIES_INPUT_LATENCY},
          *                    {@link #CATEGORIES_RENDERING},
          *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
          *                    {@link #CATEGORIES_FRAME_VIEWER}.
@@ -250,9 +246,8 @@
         /**
          * Sets the tracing mode for this configuration.
          *
-         * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
-         *                    {@link #RECORD_CONTINUOUSLY} or
-         *                    {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}.
+         * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL} or
+         *                    {@link #RECORD_CONTINUOUSLY}.
          * @return The builder to facilitate chaining.
          */
         public Builder setTracingMode(@TracingMode int tracingMode) {
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index 7871021..50068f5 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -60,9 +60,8 @@
      * Starts tracing all webviews. Depending on the trace mode in traceConfig
      * specifies how the trace events are recorded.
      *
-     * For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
-     * {@link TracingConfig#RECORD_CONTINUOUSLY} and
-     * {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
+     * For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL} and
+     * {@link TracingConfig#RECORD_CONTINUOUSLY} the events are recorded
      * using an internal buffer and flushed to the outputStream when
      * {@link #stop(OutputStream, Executor)} is called.
      *
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9a99963..298c61e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -89,7 +89,7 @@
 
 /**
  * Base class that can be used to implement virtualized lists of items. A list does
- * not have a spatial definition here. For instance, subclases of this class can
+ * not have a spatial definition here. For instance, subclasses of this class can
  * display the content of the list in a grid, in a carousel, as stack, etc.
  *
  * @attr ref android.R.styleable#AbsListView_listSelector
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index 3ec8ab9..f52854a 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -33,6 +33,7 @@
 
 // TODO: Use link annotation to refer VideoView2 once VideoView2 became unhidden.
 /**
+ * @hide
  * A View that contains the controls for MediaPlayer2.
  * It provides a wide range of UI including buttons such as "Play/Pause", "Rewind", "Fast Forward",
  * "Subtitle", "Full Screen", and it is also possible to add multiple custom buttons.
@@ -150,7 +151,7 @@
     public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super((instance, superProvider, privateProvider) ->
-                ApiLoader.getProvider(context).createMediaControlView2(
+                ApiLoader.getProvider().createMediaControlView2(
                         (MediaControlView2) instance, superProvider, privateProvider,
                         attrs, defStyleAttr, defStyleRes),
                 context, attrs, defStyleAttr, defStyleRes);
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index be8c34c..6e855ba 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -246,7 +246,7 @@
                 mTextView.invalidate();
             }
             mTextClassification = result.mClassification;
-        } else if (actionMode == Editor.TextActionMode.TEXT_LINK) {
+        } else if (result != null && actionMode == Editor.TextActionMode.TEXT_LINK) {
             mTextClassification = result.mClassification;
         } else {
             mTextClassification = null;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 72c8426..c366a91 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -162,6 +162,7 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
@@ -187,6 +188,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 /**
  * A user interface element that displays text to the user.
@@ -5635,6 +5640,8 @@
             needEditableForNotification = true;
         }
 
+        PrecomputedText precomputed =
+                (text instanceof PrecomputedText) ? (PrecomputedText) text : null;
         if (type == BufferType.EDITABLE || getKeyListener() != null
                 || needEditableForNotification) {
             createEditorIfNeeded();
@@ -5644,10 +5651,7 @@
             setFilters(t, mFilters);
             InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) imm.restartInput(this);
-        } else if (type == BufferType.SPANNABLE || mMovement != null) {
-            text = mSpannableFactory.newSpannable(text);
-        } else if (text instanceof PrecomputedText) {
-            PrecomputedText precomputed = (PrecomputedText) text;
+        } else if (precomputed != null) {
             if (mTextDir == null) {
                 mTextDir = getTextDirectionHeuristic();
             }
@@ -5660,6 +5664,8 @@
                         + "PrecomputedText: " + precomputed.getParams()
                         + "TextView: " + getTextMetricsParams());
             }
+        } else if (type == BufferType.SPANNABLE || mMovement != null) {
+            text = mSpannableFactory.newSpannable(text);
         } else if (!(text instanceof CharWrapper)) {
             text = TextUtils.stringOrSpannedString(text);
         }
@@ -11515,16 +11521,13 @@
     }
 
     /**
-     * Starts an ActionMode for the specified TextLink.
+     * Starts an ActionMode for the specified TextLinkSpan.
      *
      * @return Whether or not we're attempting to start the action mode.
      * @hide
      */
     public boolean requestActionMode(@NonNull TextLinks.TextLinkSpan clickedSpan) {
         Preconditions.checkNotNull(clickedSpan);
-        final TextLinks.TextLink link = clickedSpan.getTextLink();
-        Preconditions.checkNotNull(link);
-        createEditorIfNeeded();
 
         if (!(mText instanceof Spanned)) {
             return false;
@@ -11533,15 +11536,55 @@
         final int start = ((Spanned) mText).getSpanStart(clickedSpan);
         final int end = ((Spanned) mText).getSpanEnd(clickedSpan);
 
-        if (start < 0 || end < 1) {
+        if (start < 0 || end > mText.length() || start >= end) {
             return false;
         }
 
+        createEditorIfNeeded();
         mEditor.startLinkActionModeAsync(start, end);
         return true;
     }
 
     /**
+     * Handles a click on the specified TextLinkSpan.
+     *
+     * @return Whether or not the click is being handled.
+     * @hide
+     */
+    public boolean handleClick(@NonNull TextLinks.TextLinkSpan clickedSpan) {
+        Preconditions.checkNotNull(clickedSpan);
+        if (mText instanceof Spanned) {
+            final Spanned spanned = (Spanned) mText;
+            final int start = spanned.getSpanStart(clickedSpan);
+            final int end = spanned.getSpanEnd(clickedSpan);
+            if (start >= 0 && end <= mText.length() && start < end) {
+                final TextClassification.Options options = new TextClassification.Options()
+                        .setDefaultLocales(getTextLocales());
+                final Supplier<TextClassification> supplier = () ->
+                        getTextClassifier().classifyText(mText, start, end, options);
+                final Consumer<TextClassification> consumer = classification -> {
+                    if (classification != null) {
+                        final Intent intent = classification.getIntent();
+                        if (intent != null) {
+                            TextClassification.fireIntent(mContext, intent);
+                        } else {
+                            Log.d(LOG_TAG, "No link action to perform");
+                        }
+                    } else {
+                        // classification == null
+                        Log.d(LOG_TAG, "Timeout while classifying text");
+                    }
+                };
+                CompletableFuture.supplyAsync(supplier)
+                        .completeOnTimeout(null, 1, TimeUnit.SECONDS)
+                        .thenAccept(consumer);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * @hide
      */
     protected void stopTextActionMode() {
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 6f08dc2..388eae2 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -47,6 +47,7 @@
 
 // TODO: Replace MediaSession wtih MediaSession2 once MediaSession2 is submitted.
 /**
+ * @hide
  * Displays a video file.  VideoView2 class is a View class which is wrapping {@link MediaPlayer2}
  * so that developers can easily implement a video rendering application.
  *
@@ -143,7 +144,7 @@
             @NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super((instance, superProvider, privateProvider) ->
-                ApiLoader.getProvider(context).createVideoView2(
+                ApiLoader.getProvider().createVideoView2(
                         (VideoView2) instance, superProvider, privateProvider,
                         attrs, defStyleAttr, defStyleRes),
                 context, attrs, defStyleAttr, defStyleRes);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index d3b4dbf..9a082ec 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -320,8 +320,8 @@
         return builder;
     }
 
-    public static ArrayList<InputMethodInfo> getDefaultEnabledImes(final Context context,
-            final ArrayList<InputMethodInfo> imis) {
+    public static ArrayList<InputMethodInfo> getDefaultEnabledImes(
+            Context context, ArrayList<InputMethodInfo> imis, boolean onlyMinimum) {
         final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
         // We will primarily rely on the system locale, but also keep relying on the fallback locale
         // as a last resort.
@@ -329,11 +329,19 @@
         // then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
         // subtype)
         final Locale systemLocale = getSystemLocaleFromContext(context);
-        return getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale)
-                .fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
-                        true /* checkCountry */, SUBTYPE_MODE_ANY)
-                .fillAuxiliaryImes(imis, context)
-                .build();
+        final InputMethodListBuilder builder =
+                getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale);
+        if (!onlyMinimum) {
+            builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+                    true /* checkCountry */, SUBTYPE_MODE_ANY)
+                    .fillAuxiliaryImes(imis, context);
+        }
+        return builder.build();
+    }
+
+    public static ArrayList<InputMethodInfo> getDefaultEnabledImes(
+            Context context, ArrayList<InputMethodInfo> imis) {
+        return getDefaultEnabledImes(context, imis, false /* onlyMinimum */);
     }
 
     public static Locale constructLocaleFromString(String localeStr) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 06230c1..3c150c1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.job.JobProtoEnums;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.UidTraffic;
 import android.content.ContentResolver;
@@ -137,7 +138,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 176 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 177 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS;
@@ -1550,27 +1551,31 @@
         }
     }
 
+    @VisibleForTesting
     public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
         final TimeBase mTimeBase;
-        long mCount;
-        long mLoadedCount;
-        long mUnpluggedCount;
+        public long mCount;
+        public long mCurrentCount;
+        public long mLoadedCount;
+        public long mUnpluggedCount;
 
-        LongSamplingCounter(TimeBase timeBase, Parcel in) {
+        public LongSamplingCounter(TimeBase timeBase, Parcel in) {
             mTimeBase = timeBase;
             mCount = in.readLong();
+            mCurrentCount = in.readLong();
             mLoadedCount = in.readLong();
             mUnpluggedCount = in.readLong();
             timeBase.add(this);
         }
 
-        LongSamplingCounter(TimeBase timeBase) {
+        public LongSamplingCounter(TimeBase timeBase) {
             mTimeBase = timeBase;
             timeBase.add(this);
         }
 
         public void writeToParcel(Parcel out) {
             out.writeLong(mCount);
+            out.writeLong(mCurrentCount);
             out.writeLong(mLoadedCount);
             out.writeLong(mUnpluggedCount);
         }
@@ -1597,24 +1602,37 @@
         @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount
+                    + " mCurrentCount=" + mCurrentCount
                     + " mLoadedCount=" + mLoadedCount
                     + " mUnpluggedCount=" + mUnpluggedCount);
         }
 
-        void addCountLocked(long count) {
-            addCountLocked(count, mTimeBase.isRunning());
+        public void addCountLocked(long count) {
+            update(mCurrentCount + count, mTimeBase.isRunning());
         }
 
-        void addCountLocked(long count, boolean isRunning) {
-            if (isRunning) {
-                mCount += count;
+        public void addCountLocked(long count, boolean isRunning) {
+            update(mCurrentCount + count, isRunning);
+        }
+
+        public void update(long count) {
+            update(count, mTimeBase.isRunning());
+        }
+
+        public void update(long count, boolean isRunning) {
+            if (count < mCurrentCount) {
+                mCurrentCount = 0;
             }
+            if (isRunning) {
+                mCount += count - mCurrentCount;
+            }
+            mCurrentCount = count;
         }
 
         /**
          * Clear state of this counter.
          */
-        void reset(boolean detachIfReset) {
+        public void reset(boolean detachIfReset) {
             mCount = 0;
             mLoadedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
@@ -1622,18 +1640,16 @@
             }
         }
 
-        void detach() {
+        public void detach() {
             mTimeBase.remove(this);
         }
 
-        void writeSummaryFromParcelLocked(Parcel out) {
+        public void writeSummaryFromParcelLocked(Parcel out) {
             out.writeLong(mCount);
         }
 
-        void readSummaryFromParcelLocked(Parcel in) {
-            mLoadedCount = in.readLong();
-            mCount = mLoadedCount;
-            mUnpluggedCount = mLoadedCount;
+        public void readSummaryFromParcelLocked(Parcel in) {
+            mCount = mUnpluggedCount= mLoadedCount = in.readLong();
         }
     }
 
@@ -10045,7 +10061,8 @@
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
                 StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, getUid(), null,
-                        name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED);
+                        name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED,
+                        JobProtoEnums.STOP_REASON_CANCELLED);
             }
         }
 
@@ -10055,7 +10072,8 @@
                 t.stopRunningLocked(elapsedRealtimeMs);
                 if (!t.isRunningLocked()) { // only tell statsd if truly stopped
                     StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, getUid(), null,
-                            name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED);
+                            name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
+                            stopReason);
                 }
             }
             if (mBsi.mOnBatteryTimeBase.isRunning()) {
@@ -11600,10 +11618,6 @@
         }
     }
 
-    // Cache last value for comparison.
-    private BluetoothActivityEnergyInfo mLastBluetoothActivityEnergyInfo =
-            new BluetoothActivityEnergyInfo(0, 0, 0, 0, 0, 0);
-
     /**
      * Add modem tx power to history
      * Device is said to be in high cellular transmit power when it has spent most of the transmit
@@ -11642,8 +11656,35 @@
         return;
     }
 
+    private final class BluetoothActivityInfoCache {
+        long idleTimeMs;
+        long rxTimeMs;
+        long txTimeMs;
+        long energy;
+
+        SparseLongArray uidRxBytes = new SparseLongArray();
+        SparseLongArray uidTxBytes = new SparseLongArray();
+
+        void set(BluetoothActivityEnergyInfo info) {
+            idleTimeMs = info.getControllerIdleTimeMillis();
+            rxTimeMs = info.getControllerRxTimeMillis();
+            txTimeMs = info.getControllerTxTimeMillis();
+            energy = info.getControllerEnergyUsed();
+            if (info.getUidTraffic() != null) {
+                for (UidTraffic traffic : info.getUidTraffic()) {
+                    uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
+                    uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
+                }
+            }
+        }
+    }
+
+    private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
+            = new BluetoothActivityInfoCache();
+
     /**
      * Distribute Bluetooth energy info and network traffic to apps.
+     *
      * @param info The energy information from the bluetooth controller.
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
@@ -11658,12 +11699,13 @@
         mHasBluetoothReporting = true;
 
         final long elapsedRealtimeMs = mClocks.elapsedRealtime();
-        final long rxTimeMs = info.getControllerRxTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerRxTimeMillis();
-        final long txTimeMs = info.getControllerTxTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerTxTimeMillis();
-        final long idleTimeMs = info.getControllerIdleTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerIdleTimeMillis();
+        final long rxTimeMs =
+                info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
+        final long txTimeMs =
+                info.getControllerTxTimeMillis() - mLastBluetoothActivityInfo.txTimeMs;
+        final long idleTimeMs =
+                info.getControllerIdleTimeMillis() - mLastBluetoothActivityInfo.idleTimeMs;
+
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "------ BEGIN BLE power blaming ------");
             Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
@@ -11735,8 +11777,8 @@
         }
 
         if (DEBUG_ENERGY) {
-            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
-                    + " TX=" + leftOverTxTimeMs);
+            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs + " TX="
+                    + leftOverTxTimeMs);
         }
 
         //
@@ -11747,70 +11789,56 @@
         long totalRxBytes = 0;
 
         final UidTraffic[] uidTraffic = info.getUidTraffic();
-        final UidTraffic[] lastUidTraffic = mLastBluetoothActivityEnergyInfo.getUidTraffic();
-        final ArrayList<UidTraffic> deltaTraffic = new ArrayList<>();
-        int m = 0, n = 0;
-        for (; m < uidTraffic.length && n < lastUidTraffic.length; m++) {
-            final UidTraffic traffic = uidTraffic[m];
-            final UidTraffic lastTraffic = lastUidTraffic[n];
-            if (traffic.getUid() == lastTraffic.getUid()) {
-                deltaTraffic.add(new UidTraffic(traffic.getUid(),
-                        traffic.getRxBytes() - lastTraffic.getRxBytes(),
-                        traffic.getTxBytes() - lastTraffic.getTxBytes()));
-                n++;
-            }
-        }
-        for (; m < uidTraffic.length; m ++) {
-            deltaTraffic.add(uidTraffic[m]);
-        }
-
-        for (int i = 0, j = 0; i < deltaTraffic.size(); i++) {
-            final UidTraffic traffic = deltaTraffic.get(i);
+        final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+        for (int i = 0; i < numUids; i++) {
+            final UidTraffic traffic = uidTraffic[i];
+            final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(
+                    traffic.getUid());
+            final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(
+                    traffic.getUid());
 
             // Add to the global counters.
-            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
-                    traffic.getRxBytes());
-            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
-                    traffic.getTxBytes());
+            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(rxBytes);
+            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(txBytes);
 
             // Add to the UID counters.
             final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
-            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
-            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
+            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, rxBytes, 0);
+            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, txBytes, 0);
 
             // Calculate the total traffic.
-            totalTxBytes += traffic.getTxBytes();
-            totalRxBytes += traffic.getRxBytes();
+            totalRxBytes += rxBytes;
+            totalTxBytes += txBytes;
         }
 
-        if ((totalTxBytes != 0 || totalRxBytes != 0) &&
-                (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
-            for (int i = 0; i < deltaTraffic.size(); i++) {
-                final UidTraffic traffic = deltaTraffic.get(i);
+        if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0
+                || leftOverTxTimeMs != 0)) {
+            for (int i = 0; i < numUids; i++) {
+                final UidTraffic traffic = uidTraffic[i];
+                final int uid = traffic.getUid();
+                final long rxBytes =
+                        traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid);
+                final long txBytes =
+                        traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(uid);
 
-                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
+                final Uid u = getUidStatsLocked(mapUid(uid));
                 final ControllerActivityCounterImpl counter =
                         u.getOrCreateBluetoothControllerActivityLocked();
 
-                if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
-                    final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
-
+                if (totalRxBytes > 0 && rxBytes > 0) {
+                    final long timeRxMs = (leftOverRxTimeMs * rxBytes) / totalRxBytes;
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
-                                + " rx_time=" + timeRxMs);
+                        Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
                     }
                     counter.getRxTimeCounter().addCountLocked(timeRxMs);
                     leftOverRxTimeMs -= timeRxMs;
                 }
 
-                if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
-                    final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
-
+                if (totalTxBytes > 0 && txBytes > 0) {
+                    final long timeTxMs = (leftOverTxTimeMs * txBytes) / totalTxBytes;
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
-                                + " tx_time=" + timeTxMs);
+                        Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
                     }
-
                     counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
                     leftOverTxTimeMs -= timeTxMs;
                 }
@@ -11827,10 +11855,10 @@
         if (opVolt != 0) {
             // We store the power drain as mAms.
             mBluetoothActivity.getPowerCounter().addCountLocked(
-                    (long) ((info.getControllerEnergyUsed() -
-                            mLastBluetoothActivityEnergyInfo.getControllerEnergyUsed() )/ opVolt));
+                    (long) ((info.getControllerEnergyUsed() - mLastBluetoothActivityInfo.energy)
+                            / opVolt));
         }
-        mLastBluetoothActivityEnergyInfo = info;
+        mLastBluetoothActivityInfo.set(info);
     }
 
     /**
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
new file mode 100644
index 0000000..2c48506
--- /dev/null
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.os;
+
+import android.os.Binder;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Collects statistics about CPU time spent per binder call across multiple dimensions, e.g.
+ * per thread, uid or call description.
+ */
+public class BinderCallsStats {
+    private static final int CALL_SESSIONS_POOL_SIZE = 100;
+    private static final BinderCallsStats sInstance = new BinderCallsStats();
+
+    private volatile boolean mTrackingEnabled = false;
+    private final SparseArray<UidEntry> mUidEntries = new SparseArray<>();
+    private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>();
+
+    private BinderCallsStats() {
+    }
+
+    @VisibleForTesting
+    public BinderCallsStats(boolean trackingEnabled) {
+        mTrackingEnabled = trackingEnabled;
+    }
+
+    public CallSession callStarted(Binder binder, int code) {
+        if (!mTrackingEnabled) {
+            return null;
+        }
+
+        return callStarted(binder.getClass().getName(), code);
+    }
+
+    private CallSession callStarted(String className, int code) {
+        CallSession s = mCallSessionsPool.poll();
+        if (s == null) {
+            s = new CallSession();
+        }
+        s.mCallStat.className = className;
+        s.mCallStat.msg = code;
+
+        s.mStarted = getThreadTimeMicro();
+        return s;
+    }
+
+    public void callEnded(CallSession s) {
+        if (!mTrackingEnabled) {
+            return;
+        }
+        Preconditions.checkNotNull(s);
+        final long cpuTimeNow = getThreadTimeMicro();
+        final long duration = cpuTimeNow - s.mStarted;
+        s.mCallingUId = Binder.getCallingUid();
+
+        synchronized (mUidEntries) {
+            UidEntry uidEntry = mUidEntries.get(s.mCallingUId);
+            if (uidEntry == null) {
+                uidEntry = new UidEntry(s.mCallingUId);
+                mUidEntries.put(s.mCallingUId, uidEntry);
+            }
+
+            // Find CallDesc entry and update its total time
+            CallStat callStat = uidEntry.mCallStats.get(s.mCallStat);
+            // Only create CallStat if it's a new entry, otherwise update existing instance
+            if (callStat == null) {
+                callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg);
+                uidEntry.mCallStats.put(callStat, callStat);
+            }
+            uidEntry.time += duration;
+            uidEntry.callCount++;
+            callStat.callCount++;
+            callStat.time += duration;
+        }
+        if (mCallSessionsPool.size() < CALL_SESSIONS_POOL_SIZE) {
+            mCallSessionsPool.add(s);
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        Map<Integer, Long> uidTimeMap = new HashMap<>();
+        Map<Integer, Long> uidCallCountMap = new HashMap<>();
+        long totalCallsCount = 0;
+        long totalCallsTime = 0;
+        int uidEntriesSize = mUidEntries.size();
+        List<UidEntry> entries = new ArrayList<>();
+        synchronized (mUidEntries) {
+            for (int i = 0; i < uidEntriesSize; i++) {
+                UidEntry e = mUidEntries.valueAt(i);
+                entries.add(e);
+                totalCallsTime += e.time;
+                // Update per-uid totals
+                Long totalTimePerUid = uidTimeMap.get(e.uid);
+                uidTimeMap.put(e.uid,
+                        totalTimePerUid == null ? e.time : totalTimePerUid + e.time);
+                Long totalCallsPerUid = uidCallCountMap.get(e.uid);
+                uidCallCountMap.put(e.uid, totalCallsPerUid == null ? e.callCount
+                        : totalCallsPerUid + e.callCount);
+                totalCallsCount += e.callCount;
+            }
+        }
+        pw.println("Binder call stats:");
+        pw.println("  Raw data (uid,call_desc,time):");
+        entries.sort((o1, o2) -> {
+            if (o1.time < o2.time) {
+                return 1;
+            } else if (o1.time > o2.time) {
+                return -1;
+            }
+            return 0;
+        });
+        StringBuilder sb = new StringBuilder();
+        for (UidEntry uidEntry : entries) {
+            List<CallStat> callStats = new ArrayList<>(uidEntry.mCallStats.keySet());
+            callStats.sort((o1, o2) -> {
+                if (o1.time < o2.time) {
+                    return 1;
+                } else if (o1.time > o2.time) {
+                    return -1;
+                }
+                return 0;
+            });
+            for (CallStat e : callStats) {
+                sb.setLength(0);
+                sb.append("    ")
+                        .append(uidEntry.uid).append(",").append(e).append(',').append(e.time);
+                pw.println(sb);
+            }
+        }
+        pw.println();
+        pw.println("  Per UID Summary(UID: time, total_time_percentage, calls_count):");
+        List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet());
+        uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
+        for (Map.Entry<Integer, Long> uidTotal : uidTotals) {
+            Long callCount = uidCallCountMap.get(uidTotal.getKey());
+            pw.println(String.format("    %5d: %11d %3.0f%% %8d",
+                    uidTotal.getKey(), uidTotal.getValue(),
+                    100d * uidTotal.getValue() / totalCallsTime, callCount));
+        }
+        pw.println();
+        pw.println(String.format("  Summary: total_time=%d, "
+                        + "calls_count=%d, avg_call_time=%.0f",
+                totalCallsTime, totalCallsCount,
+                (double)totalCallsTime / totalCallsCount));
+    }
+
+    private static long getThreadTimeMicro() {
+        return SystemClock.currentThreadTimeMicro();
+    }
+
+    public static BinderCallsStats getInstance() {
+        return sInstance;
+    }
+
+    public void setTrackingEnabled(boolean enabled) {
+        mTrackingEnabled = enabled;
+    }
+
+    public boolean isTrackingEnabled() {
+        return mTrackingEnabled;
+    }
+
+    private static class CallStat {
+        String className;
+        int msg;
+        long time;
+        long callCount;
+
+        CallStat() {
+        }
+
+        CallStat(String className, int msg) {
+            this.className = className;
+            this.msg = msg;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            CallStat callStat = (CallStat) o;
+
+            return msg == callStat.msg && (className == callStat.className);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = className.hashCode();
+            result = 31 * result + msg;
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return className + "/" + msg;
+        }
+    }
+
+    public static class CallSession {
+        int mCallingUId;
+        long mStarted;
+        CallStat mCallStat = new CallStat();
+    }
+
+    private static class UidEntry {
+        int uid;
+        long time;
+        long callCount;
+
+        UidEntry(int uid) {
+            this.uid = uid;
+        }
+
+        // Aggregate time spent per each call name: call_desc -> cpu_time_micros
+        Map<CallStat, CallStat> mCallStats = new ArrayMap<>();
+
+        @Override
+        public String toString() {
+            return "UidEntry{" +
+                    "time=" + time +
+                    ", callCount=" + callCount +
+                    ", mCallStats=" + mCallStats +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            UidEntry uidEntry = (UidEntry) o;
+            return uid == uidEntry.uid;
+        }
+
+        @Override
+        public int hashCode() {
+            return uid;
+        }
+    }
+
+}
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 4901080..f0e7796 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -115,6 +115,14 @@
         command.append(' ');
         command.append(appProcess);
 
+        // Generate bare minimum of debug information to be able to backtrace through JITed code.
+        // We assume that if the invoke wrapper is used, backtraces are desirable:
+        //  * The wrap.sh script can only be used by debuggable apps, which would enable this flag
+        //    without the script anyway (the fork-zygote path).  So this makes the two consistent.
+        //  * The wrap.* property can only be used on userdebug builds and is likely to be used by
+        //    developers (e.g. enable debug-malloc), in which case backtraces are also useful.
+        command.append(" -Xcompiler-option --generate-mini-debug-info");
+
         command.append(" /system/bin --application");
         if (niceName != null) {
             command.append(" '--nice-name=").append(niceName).append("'");
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 933cc7a..577fa17 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -443,7 +443,7 @@
      */
     public static int resolveColor(Context context, int color) {
         if (color == Notification.COLOR_DEFAULT) {
-            return context.getColor(com.android.internal.R.color.notification_icon_default_color);
+            return context.getColor(com.android.internal.R.color.notification_default_color_light);
         }
         return color;
     }
@@ -475,20 +475,15 @@
             int backgroundColor, boolean isDark) {
         final int resolvedColor = resolveColor(context, notificationColor);
 
-        final int actionBg = context.getColor(
-                com.android.internal.R.color.notification_action_list);
-
         int color = resolvedColor;
-        color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg, isDark);
         color = NotificationColorUtil.ensureTextContrast(color, backgroundColor, isDark);
 
         if (color != resolvedColor) {
             if (DEBUG){
                 Log.w(TAG, String.format(
-                        "Enhanced contrast of notification for %s %s (over action)"
+                        "Enhanced contrast of notification for %s"
                                 + " and %s (over background) by changing #%s to %s",
                         context.getPackageName(),
-                        NotificationColorUtil.contrastChange(resolvedColor, color, actionBg),
                         NotificationColorUtil.contrastChange(resolvedColor, color, backgroundColor),
                         Integer.toHexString(resolvedColor), Integer.toHexString(color)));
             }
@@ -552,6 +547,17 @@
         }
     }
 
+    public static int resolveDefaultColor(Context context, int backgroundColor) {
+        boolean useDark = shouldUseDark(backgroundColor);
+        if (useDark) {
+            return context.getColor(
+                    com.android.internal.R.color.notification_default_color_light);
+        } else {
+            return context.getColor(
+                    com.android.internal.R.color.notification_default_color_dark);
+        }
+    }
+
     public static int resolveActionBarColor(Context context, int backgroundColor) {
         if (backgroundColor == Notification.COLOR_DEFAULT) {
             return context.getColor(com.android.internal.R.color.notification_action_list);
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index b962d4f..bf796cd 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -26,7 +26,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 
 import java.util.Objects;
@@ -47,6 +46,18 @@
                 Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING), false, mSmsContentObserver);
     }
 
+    public boolean isImportantMessaging(StatusBarNotification sbn, int importance) {
+        if (importance < NotificationManager.IMPORTANCE_LOW) {
+            return false;
+        }
+
+        return hasMessagingStyle(sbn) || (isCategoryMessage(sbn) && isDefaultMessagingApp(sbn));
+    }
+
+    public boolean isMessaging(StatusBarNotification sbn) {
+        return hasMessagingStyle(sbn) || isDefaultMessagingApp(sbn) || isCategoryMessage(sbn);
+    }
+
     @SuppressWarnings("deprecation")
     private boolean isDefaultMessagingApp(StatusBarNotification sbn) {
         final int userId = sbn.getUserId();
@@ -73,25 +84,12 @@
         }
     };
 
-    public boolean isImportantMessaging(StatusBarNotification sbn, int importance) {
-        if (importance < NotificationManager.IMPORTANCE_LOW) {
-            return false;
-        }
-
-        return isMessaging(sbn);
+    private boolean hasMessagingStyle(StatusBarNotification sbn) {
+        Class<? extends Notification.Style> style = sbn.getNotification().getNotificationStyle();
+        return Notification.MessagingStyle.class.equals(style);
     }
 
-    public boolean isMessaging(StatusBarNotification sbn) {
-        Class<? extends Notification.Style> style = sbn.getNotification().getNotificationStyle();
-        if (Notification.MessagingStyle.class.equals(style)) {
-            return true;
-        }
-
-        if (Notification.CATEGORY_MESSAGE.equals(sbn.getNotification().category)
-                && isDefaultMessagingApp(sbn)) {
-            return true;
-        }
-
-        return false;
+    private boolean isCategoryMessage(StatusBarNotification sbn) {
+        return Notification.CATEGORY_MESSAGE.equals(sbn.getNotification().category);
     }
 }
diff --git a/core/java/com/android/internal/util/ProviderAccessStats.java b/core/java/com/android/internal/util/ProviderAccessStats.java
new file mode 100644
index 0000000..c3ffb02
--- /dev/null
+++ b/core/java/com/android/internal/util/ProviderAccessStats.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.util;
+
+import android.os.SystemClock;
+import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
+
+import java.io.PrintWriter;
+
+public class ProviderAccessStats {
+    private final Object mLock = new Object();
+
+    private final long mStartUptime = SystemClock.uptimeMillis();
+
+    private final SparseBooleanArray mAllCallingUids = new SparseBooleanArray();
+    private final SparseLongArray mQueryStats = new SparseLongArray(16);
+    private final SparseLongArray mBatchStats = new SparseLongArray(0);
+    private final SparseLongArray mInsertStats = new SparseLongArray(0);
+    private final SparseLongArray mUpdateStats = new SparseLongArray(0);
+    private final SparseLongArray mDeleteStats = new SparseLongArray(0);
+    private final SparseLongArray mInsertInBatchStats = new SparseLongArray(0);
+    private final SparseLongArray mUpdateInBatchStats = new SparseLongArray(0);
+    private final SparseLongArray mDeleteInBatchStats = new SparseLongArray(0);
+
+    private final SparseLongArray mOperationDurationMillis = new SparseLongArray(16);
+
+    private static class PerThreadData {
+        public int nestCount;
+        public long startUptimeMillis;
+    }
+
+    private final ThreadLocal<PerThreadData> mThreadLocal =
+            ThreadLocal.withInitial(() -> new PerThreadData());
+
+    private void incrementStats(int callingUid, SparseLongArray stats) {
+        synchronized (mLock) {
+            stats.put(callingUid, stats.get(callingUid) + 1);
+            mAllCallingUids.put(callingUid, true);
+        }
+
+        final PerThreadData data = mThreadLocal.get();
+        data.nestCount++;
+        if (data.nestCount == 1) {
+            data.startUptimeMillis = SystemClock.uptimeMillis();
+        }
+    }
+
+    private void incrementStats(int callingUid, boolean inBatch,
+            SparseLongArray statsNonBatch, SparseLongArray statsInBatch) {
+        incrementStats(callingUid, inBatch ? statsInBatch : statsNonBatch);
+    }
+
+    public final void incrementInsertStats(int callingUid, boolean inBatch) {
+        incrementStats(callingUid, inBatch, mInsertStats, mInsertInBatchStats);
+    }
+
+    public final void incrementUpdateStats(int callingUid, boolean inBatch) {
+        incrementStats(callingUid, inBatch, mUpdateStats, mUpdateInBatchStats);
+    }
+
+    public final void incrementDeleteStats(int callingUid, boolean inBatch) {
+        incrementStats(callingUid, inBatch, mDeleteStats, mDeleteInBatchStats);
+    }
+
+    public final void incrementQueryStats(int callingUid) {
+        incrementStats(callingUid, mQueryStats);
+    }
+
+    public final void incrementBatchStats(int callingUid) {
+        incrementStats(callingUid, mBatchStats);
+    }
+
+    public void finishOperation(int callingUid) {
+        final PerThreadData data = mThreadLocal.get();
+        data.nestCount--;
+        if (data.nestCount == 0) {
+            // Because we only have millisecond granularity, let's always attribute at least 1ms
+            // for each operation.
+            final long duration = Math.max(1, SystemClock.uptimeMillis() - data.startUptimeMillis);
+
+            synchronized (mLock) {
+                mOperationDurationMillis.put(callingUid,
+                        mOperationDurationMillis.get(callingUid) + duration);
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        synchronized (mLock) {
+            pw.print("  Process uptime: ");
+            pw.print((SystemClock.uptimeMillis() - mStartUptime) / (60 * 1000));
+            pw.println(" minutes");
+            pw.println();
+
+            pw.print(prefix);
+            pw.println("Client activities:");
+            pw.print(prefix);
+            pw.println("  UID        Query  Insert Update Delete   Batch Insert Update Delete"
+                    + "          Sec");
+            for (int i = 0; i < mAllCallingUids.size(); i++) {
+                final int uid = mAllCallingUids.keyAt(i);
+                pw.print(prefix);
+                pw.println(String.format(
+                        "  %-9d %6d  %6d %6d %6d  %6d %6d %6d %6d %12.3f",
+                        uid,
+                        mQueryStats.get(uid),
+                        mInsertStats.get(uid),
+                        mUpdateStats.get(uid),
+                        mDeleteStats.get(uid),
+                        mBatchStats.get(uid),
+                        mInsertInBatchStats.get(uid),
+                        mUpdateInBatchStats.get(uid),
+                        mDeleteInBatchStats.get(uid),
+                        (mOperationDurationMillis.get(uid) / 1000.0)
+                ));
+            }
+            pw.println();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index bec70fd..bff34ca 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -74,7 +74,6 @@
     void setRecoverySecretTypes(in int[] secretTypes);
     int[] getRecoverySecretTypes();
     int[] getPendingRecoverySecretTypes();
-    void recoverySecretAvailable(in KeyChainProtectionParams recoverySecret);
     byte[] startRecoverySession(in String sessionId,
             in byte[] verifierPublicKey, in byte[] vaultParams, in byte[] vaultChallenge,
             in List<KeyChainProtectionParams> secrets);
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index d6496cd..7166c75 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -42,7 +42,6 @@
     }
 
     auto* imageDecoder = reinterpret_cast<ImageDecoder*>(nativeImageDecoder);
-    auto info = imageDecoder->mCodec->getInfo();
     const SkISize scaledSize = SkISize::Make(width, height);
     SkIRect subset;
     if (jsubset) {
@@ -51,6 +50,35 @@
         subset = SkIRect::MakeWH(width, height);
     }
 
+    auto info = imageDecoder->mCodec->getInfo();
+    bool hasRestoreFrame = false;
+    if (imageDecoder->mCodec->getEncodedFormat() == SkEncodedImageFormat::kWEBP) {
+        if (width < info.width() && height < info.height()) {
+            // WebP will scale its SkBitmap to the scaled size.
+            // FIXME: b/73529447 GIF should do the same.
+            info = info.makeWH(width, height);
+        }
+    } else {
+        const int frameCount = imageDecoder->mCodec->codec()->getFrameCount();
+        for (int i = 0; i < frameCount; ++i) {
+            SkCodec::FrameInfo frameInfo;
+            if (!imageDecoder->mCodec->codec()->getFrameInfo(i, &frameInfo)) {
+                doThrowIOE(env, "Failed to read frame info!");
+                return 0;
+            }
+            if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
+                hasRestoreFrame = true;
+                break;
+            }
+        }
+    }
+
+    size_t bytesUsed = info.computeMinByteSize();
+    // SkAnimatedImage has one SkBitmap for decoding, plus an extra one if there is a
+    // kRestorePrevious frame. AnimatedImageDrawable has two SkPictures storing the current
+    // frame and the next frame. (The former assumes that the image is animated, and the
+    // latter assumes that it is drawn to a hardware canvas.)
+    bytesUsed *= hasRestoreFrame ? 4 : 3;
     sk_sp<SkPicture> picture;
     if (jpostProcess) {
         SkRect bounds = SkRect::MakeWH(subset.width(), subset.height());
@@ -63,6 +91,7 @@
             return 0;
         }
         picture = recorder.finishRecordingAsPicture();
+        bytesUsed += picture->approximateBytesUsed();
     }
 
 
@@ -74,7 +103,10 @@
         return 0;
     }
 
-    sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(animatedImg));
+    bytesUsed += sizeof(animatedImg.get());
+
+    sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg),
+                                                                    bytesUsed));
     return reinterpret_cast<jlong>(drawable.release());
 }
 
@@ -202,10 +234,9 @@
     }
 }
 
-static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
-    // FIXME: Report the size of the internal SkBitmap etc.
-    return sizeof(drawable);
+    return drawable->byteSize();
 }
 
 static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 4b6578b..3fcedd0 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -30,8 +30,8 @@
 
 class SkColorFilterGlue {
 public:
-    static void SafeUnref(SkShader* shader) {
-        SkSafeUnref(shader);
+    static void SafeUnref(SkColorFilter* filter) {
+        SkSafeUnref(filter);
     }
 
     static jlong GetNativeFinalizer(JNIEnv*, jobject) {
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index e2ce1a4..726c450 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -38,48 +38,81 @@
 
 static jclass    gImageDecoder_class;
 static jclass    gSize_class;
-static jclass    gIncomplete_class;
+static jclass    gDecodeException_class;
 static jclass    gCanvas_class;
 static jmethodID gImageDecoder_constructorMethodID;
 static jmethodID gImageDecoder_postProcessMethodID;
 static jmethodID gSize_constructorMethodID;
-static jmethodID gIncomplete_constructorMethodID;
+static jmethodID gDecodeException_constructorMethodID;
 static jmethodID gCallback_onPartialImageMethodID;
 static jmethodID gCanvas_constructorMethodID;
 static jmethodID gCanvas_releaseMethodID;
 
-static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream) {
+// Clear and return any pending exception for handling other than throwing directly.
+static jthrowable get_and_clear_exception(JNIEnv* env) {
+    jthrowable jexception = env->ExceptionOccurred();
+    if (jexception) {
+        env->ExceptionClear();
+    }
+    return jexception;
+}
+
+// Throw a new ImageDecoder.DecodeException. Returns null for convenience.
+static jobject throw_exception(JNIEnv* env, ImageDecoder::Error error, const char* msg,
+                               jthrowable cause, jobject source) {
+    jstring jstr = nullptr;
+    if (msg) {
+        jstr = env->NewStringUTF(msg);
+        if (!jstr) {
+            // Out of memory.
+            return nullptr;
+        }
+    }
+    jthrowable exception = (jthrowable) env->NewObject(gDecodeException_class,
+            gDecodeException_constructorMethodID, error, jstr, cause, source);
+    // Only throw if not out of memory.
+    if (exception) {
+        env->Throw(exception);
+    }
+    return nullptr;
+}
+
+static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobject source) {
     if (!stream.get()) {
-        doThrowIOE(env, "Failed to create a stream");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+                               nullptr, source);
     }
     std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
     SkCodec::Result result;
     auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get());
+    if (jthrowable jexception = get_and_clear_exception(env)) {
+        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+    }
     if (!codec) {
         switch (result) {
             case SkCodec::kIncompleteInput:
-                env->ThrowNew(gIncomplete_class, "Incomplete input");
-                break;
+                return throw_exception(env, ImageDecoder::kSourceIncomplete, "", nullptr, source);
             default:
                 SkString msg;
                 msg.printf("Failed to create image decoder with message '%s'",
                            SkCodec::ResultToString(result));
-                doThrowIOE(env, msg.c_str());
-                break;
+                return throw_exception(env, ImageDecoder::kSourceMalformedData,  msg.c_str(),
+                                       nullptr, source);
 
         }
-        return nullptr;
     }
 
-    // FIXME: Avoid parsing the whole image?
     const bool animated = codec->getFrameCount() > 1;
+    if (jthrowable jexception = get_and_clear_exception(env)) {
+        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+    }
+
     decoder->mCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
             SkAndroidCodec::ExifOrientationBehavior::kRespect);
     if (!decoder->mCodec.get()) {
-        doThrowIOE(env, "Could not create AndroidCodec");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "", nullptr, source);
     }
+
     const auto& info = decoder->mCodec->getInfo();
     const int width = info.width();
     const int height = info.height();
@@ -89,26 +122,26 @@
 }
 
 static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
-        jobject fileDescriptor) {
+        jobject fileDescriptor, jobject source) {
     int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
-        doThrowIOE(env, "broken file descriptor; fstat returned -1");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData,
+                               "broken file descriptor; fstat returned -1", nullptr, source);
     }
 
     int dupDescriptor = dup(descriptor);
     FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
         close(dupDescriptor);
-        doThrowIOE(env, "Could not open file");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Could not open file",
+                               nullptr, source);
     }
     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
 
     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
-        return native_create(env, std::move(fileStream));
+        return native_create(env, std::move(fileStream), source);
     }
 
     // FIXME: This allows us to pretend the current location is the beginning,
@@ -116,44 +149,46 @@
     // point as the beginning.
     std::unique_ptr<SkStream> stream(SkFrontBufferedStream::Make(std::move(fileStream),
                 SkCodec::MinBufferedBytesNeeded()));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
-        jobject is, jbyteArray storage) {
+        jobject is, jbyteArray storage, jobject source) {
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
 
     if (!stream.get()) {
-        doThrowIOE(env, "Failed to create stream!");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+                               nullptr, source);
     }
+
     std::unique_ptr<SkStream> bufferedStream(
         SkFrontBufferedStream::Make(std::move(stream),
         SkCodec::MinBufferedBytesNeeded()));
-    return native_create(env, std::move(bufferedStream));
+    return native_create(env, std::move(bufferedStream), source);
 }
 
-static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr) {
+static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr,
+                                         jobject source) {
     Asset* asset = reinterpret_cast<Asset*>(assetPtr);
     std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, jobject jbyteBuffer,
-                                              jint initialPosition, jint limit) {
+                                              jint initialPosition, jint limit, jobject source) {
     std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
                                                                      initialPosition, limit);
     if (!stream) {
-        doThrowIOE(env, "Failed to read ByteBuffer");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer",
+                               nullptr, source);
     }
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jbyteArray byteArray,
-                                             jint offset, jint length) {
+                                             jint offset, jint length, jobject source) {
     std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
@@ -170,10 +205,8 @@
     return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID, jcanvas);
 }
 
-// Note: jpostProcess points to an ImageDecoder object if it has a PostProcess object, and nullptr
-// otherwise.
 static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
-                                          jobject jcallback, jobject jpostProcess,
+                                          jobject jdecoder, jboolean jpostProcess,
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
@@ -264,11 +297,8 @@
     SkAndroidCodec::AndroidOptions options;
     options.fSampleSize = sampleSize;
     auto result = codec->getAndroidPixels(decodeInfo, bm.getPixels(), bm.rowBytes(), &options);
-    jthrowable jexception = env->ExceptionOccurred();
-    if (jexception) {
-        env->ExceptionClear();
-    }
-    int onPartialImageError = jexception ? 1  // ImageDecoder.java's ERROR_SOURCE_EXCEPTION
+    jthrowable jexception = get_and_clear_exception(env);
+    int onPartialImageError = jexception ? ImageDecoder::kSourceException
                                          : 0; // No error.
     switch (result) {
         case SkCodec::kSuccess:
@@ -278,12 +308,12 @@
             break;
         case SkCodec::kIncompleteInput:
             if (!jexception) {
-                onPartialImageError = 2; // ImageDecoder.java's ERROR_SOURCE_EXCEPTION
+                onPartialImageError = ImageDecoder::kSourceIncomplete;
             }
             break;
         case SkCodec::kErrorInInput:
             if (!jexception) {
-                onPartialImageError = 3; // ImageDecoder.java's ERROR_SOURCE_ERROR
+                onPartialImageError = ImageDecoder::kSourceMalformedData;
             }
             break;
         default:
@@ -293,24 +323,12 @@
             return nullptr;
     }
 
-    if (jexception || onPartialImageError) {
-        bool throwException = !jcallback ||
-            !env->CallBooleanMethod(jcallback, gCallback_onPartialImageMethodID,
-                                    onPartialImageError);
+    if (onPartialImageError) {
+        env->CallVoidMethod(jdecoder, gCallback_onPartialImageMethodID, onPartialImageError,
+                jexception);
         if (env->ExceptionCheck()) {
             return nullptr;
         }
-
-        if (throwException) {
-            if (jexception) {
-                env->Throw(jexception);
-            } else if (onPartialImageError == 2) {
-                env->ThrowNew(gIncomplete_class, "Incomplete input");
-            } else {
-                doThrowIOE(env, "image has an error!");
-            }
-            return nullptr;
-        }
     }
 
     float scaleX = 1.0f;
@@ -357,11 +375,6 @@
             SkIRect subset;
             GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
 
-            // FIXME: If there is no scale, should this instead call
-            // SkBitmap::extractSubset? If we could upload a subset
-            // (b/70626068), this would save memory and time. Even for a
-            // software Bitmap, the extra speed might be worth the memory
-            // tradeoff if the subset is large?
             translateX    = -subset.fLeft;
             translateY    = -subset.fTop;
             desiredWidth  =  subset.width();
@@ -404,7 +417,7 @@
     if (jpostProcess) {
         std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
 
-        jint pixelFormat = postProcessAndRelease(env, jpostProcess, std::move(canvas));
+        jint pixelFormat = postProcessAndRelease(env, jdecoder, std::move(canvas));
         if (env->ExceptionCheck()) {
             return nullptr;
         }
@@ -495,12 +508,12 @@
 }
 
 static const JNINativeMethod gImageDecoderMethods[] = {
-    { "nCreate",        "(J)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
-    { "nCreate",        "(Ljava/nio/ByteBuffer;II)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
-    { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
-    { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
-    { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;Landroid/graphics/ImageDecoder;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nCreate",        "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
+    { "nCreate",        "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
+    { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
+    { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
+    { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
@@ -516,10 +529,10 @@
     gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
     gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
 
-    gIncomplete_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$IncompleteException"));
-    gIncomplete_constructorMethodID = GetMethodIDOrDie(env, gIncomplete_class, "<init>", "()V");
+    gDecodeException_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$DecodeException"));
+    gDecodeException_constructorMethodID = GetMethodIDOrDie(env, gDecodeException_class, "<init>", "(ILjava/lang/String;Ljava/lang/Throwable;Landroid/graphics/ImageDecoder$Source;)V");
 
-    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(I)Z");
+    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(ILjava/lang/Throwable;)V");
 
     gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
     gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
diff --git a/core/jni/android/graphics/ImageDecoder.h b/core/jni/android/graphics/ImageDecoder.h
index 5d7e676..fd9827b 100644
--- a/core/jni/android/graphics/ImageDecoder.h
+++ b/core/jni/android/graphics/ImageDecoder.h
@@ -33,6 +33,13 @@
         kHardware_Allocator     = 3,
     };
 
+    // These need to stay in sync with ImageDecoder.java's Error constants.
+    enum Error {
+        kSourceException     = 1,
+        kSourceIncomplete    = 2,
+        kSourceMalformedData = 3,
+    };
+
     // These need to stay in sync with PixelFormat.java's Format constants.
     enum PixelFormat {
         kUnknown     =  0,
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 0017f6c..c9bfa13 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -18,6 +18,7 @@
 #include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
 
+#include <android/api-level.h>
 #include <androidfw/ResourceTypes.h>
 #include <hwui/Canvas.h>
 #include <hwui/Paint.h>
@@ -467,6 +468,13 @@
 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
                            jint meshWidth, jint meshHeight, jfloatArray jverts,
                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
+    if (Canvas::GetApiLevel() < __ANDROID_API_P__) {
+        // Before P we forgot to respect these. Now that we do respect them, explicitly
+        // zero them for backward compatibility.
+        vertIndex = 0;
+        colorIndex = 0;
+    }
+
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
@@ -474,7 +482,8 @@
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
-                                             vertA.ptr(), colorA.ptr(), paint);
+                                             vertA.ptr() + vertIndex*2,
+                                             colorA.ptr() + colorIndex, paint);
 }
 
 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
diff --git a/core/jni/android_text_MeasuredParagraph.cpp b/core/jni/android_text_MeasuredParagraph.cpp
index d33337d..9d79417 100644
--- a/core/jni/android_text_MeasuredParagraph.cpp
+++ b/core/jni/android_text_MeasuredParagraph.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "MeasuredParagraph"
 
+#include "GraphicsJNI.h"
 #include "ScopedIcuLocale.h"
 #include "unicode/locid.h"
 #include "unicode/brkiter.h"
@@ -109,6 +110,33 @@
     return r;
 }
 
+// Regular JNI
+static void nGetBounds(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jlong paintPtr,
+                           jint start, jint end, jint bidiFlags, jobject bounds) {
+    ScopedCharArrayRO text(env, javaText);
+    const minikin::U16StringPiece textBuffer(text.get(), text.size());
+
+    minikin::MeasuredText* mt = toMeasuredParagraph(ptr);
+    Paint* paint = toPaint(paintPtr);
+    const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
+    minikin::Layout layout = MinikinUtils::doLayout(paint,
+            static_cast<minikin::Bidi>(bidiFlags), typeface, textBuffer.data(), start, end - start,
+            textBuffer.size(), mt);
+
+    minikin::MinikinRect rect;
+    layout.getBounds(&rect);
+
+    SkRect r;
+    r.fLeft = rect.mLeft;
+    r.fTop = rect.mTop;
+    r.fRight = rect.mRight;
+    r.fBottom = rect.mBottom;
+
+    SkIRect ir;
+    r.roundOut(&ir);
+    GraphicsJNI::irect_to_jrect(ir, env, bounds);
+}
+
 // CriticalNative
 static jlong nGetReleaseFunc() {
     return toJLong(&releaseMeasuredParagraph);
@@ -128,6 +156,7 @@
 
     // MeasuredParagraph native functions.
     {"nGetWidth", "(JII)F", (void*) nGetWidth},  // Critical Natives
+    {"nGetBounds", "(J[CJIIILandroid/graphics/Rect;)V", (void*) nGetBounds},  // Regular JNI
     {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc},  // Critical Natives
     {"nGetMemoryUsage", "(J)I", (void*) nGetMemoryUsage},  // Critical Native
 };
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7c8a52d..b5fd792 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -666,7 +666,9 @@
       }
     }
 
-    if (!is_system_server) {
+    // If this zygote isn't root, it won't be able to create a process group,
+    // since the directory is owned by root.
+    if (!is_system_server && getuid() == 0) {
         int rc = createProcessGroup(uid, getpid());
         if (rc != 0) {
             if (rc == -EROFS) {
diff --git a/core/proto/android/app/jobparameters.proto b/core/proto/android/app/job/enums.proto
similarity index 66%
rename from core/proto/android/app/jobparameters.proto
rename to core/proto/android/app/job/enums.proto
index 4f6a2a2..0f14f20 100644
--- a/core/proto/android/app/jobparameters.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -15,19 +15,18 @@
  */
 
 syntax = "proto2";
+
+package android.app.job;
+
+option java_outer_classname = "JobProtoEnums";
 option java_multiple_files = true;
 
-package android.app;
-
-/**
- * An android.app.JobParameters object.
- */
-message JobParametersProto {
-    enum CancelReason {
-        REASON_CANCELLED = 0;
-        REASON_CONSTRAINTS_NOT_SATISFIED = 1;
-        REASON_PREEMPT = 2;
-        REASON_TIMEOUT = 3;
-        REASON_DEVICE_IDLE = 4;
-    }
+// Reasons a job is stopped.
+// Primarily used in android.app.job.JobParameters.java.
+enum StopReasonEnum {
+  STOP_REASON_CANCELLED = 0;
+  STOP_REASON_CONSTRAINTS_NOT_SATISFIED = 1;
+  STOP_REASON_PREEMPT = 2;
+  STOP_REASON_TIMEOUT = 3;
+  STOP_REASON_DEVICE_IDLE = 4;
 }
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index 345c8ef..8e98ac9 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -19,7 +19,7 @@
 
 package android.os;
 
-import "frameworks/base/core/proto/android/app/jobparameters.proto";
+import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -637,7 +637,7 @@
     message ReasonCount {
       option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-      optional android.app.JobParametersProto.CancelReason name = 1;
+      optional android.app.job.StopReasonEnum name = 1;
       optional int32 count = 2;
     }
     repeated ReasonCount reason_count = 2;
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 6a3aaab..476d5fe 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -231,22 +231,22 @@
         (section).args = "procstats --proto"
     ];
 
-    optional com.android.server.am.proto.ActivityManagerServiceDumpActivitiesProto activities = 3012 [
+    optional com.android.server.am.ActivityManagerServiceDumpActivitiesProto activities = 3012 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "activity --proto activities"
     ];
 
-    optional com.android.server.am.proto.ActivityManagerServiceDumpBroadcastsProto broadcasts = 3013 [
+    optional com.android.server.am.ActivityManagerServiceDumpBroadcastsProto broadcasts = 3013 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "activity --proto broadcasts"
     ];
 
-    optional com.android.server.am.proto.ActivityManagerServiceDumpServicesProto amservices = 3014 [
+    optional com.android.server.am.ActivityManagerServiceDumpServicesProto amservices = 3014 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "activity --proto service"
     ];
 
-    optional com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto amprocesses = 3015 [
+    optional com.android.server.am.ActivityManagerServiceDumpProcessesProto amprocesses = 3015 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "activity --proto processes"
     ];
@@ -256,12 +256,12 @@
         (section).args = "alarm --proto"
     ];
 
-    optional com.android.server.wm.proto.WindowManagerServiceDumpProto window = 3017 [
+    optional com.android.server.wm.WindowManagerServiceDumpProto window = 3017 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "window --proto"
     ];
 
-    optional com.android.server.am.proto.MemInfoDumpProto meminfo = 3018 [
+    optional com.android.server.am.MemInfoDumpProto meminfo = 3018 [
         (section).type = SECTION_DUMPSYS,
         (section).args = "meminfo -a --proto"
     ];
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 4e781d6..89665db 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -228,6 +228,7 @@
     optional SettingProto ble_scan_low_power_interval_ms = 161 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto ble_scan_balanced_interval_ms = 162 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto ble_scan_low_latency_interval_ms = 163 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto ble_scan_background_mode = 389 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_saved_state = 164 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_supplicant_scan_interval_ms = 165 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_enhanced_auto_join = 166 [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -466,7 +467,7 @@
     // skipped.
     optional SettingProto override_settings_provider_restore_any_version = 355 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto chained_battery_attribution_enabled = 356 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto autofill_compat_allowed_packages = 357 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto autofill_compat_mode_allowed_packages = 357 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto hidden_api_blacklist_exemptions = 358 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto sound_trigger_detection_service_op_timeout = 387  [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto max_sound_trigger_detection_service_ops_per_day = 388  [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -507,7 +508,7 @@
     optional SettingsProto backup_agent_timeout_parameters = 386;
     // Please insert fields in the same order as in
     // frameworks/base/core/java/android/provider/Settings.java.
-    // Next tag = 389;
+    // Next tag = 390;
 }
 
 message SecureSettingsProto {
@@ -744,9 +745,10 @@
     optional SettingProto backup_manager_constants = 193;
     optional SettingProto backup_local_transport_parameters = 194;
     optional SettingProto bluetooth_on_while_driving = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingsProto volume_hush_gesture = 196 [ (android.privacy).dest = DEST_AUTOMATIC ];
     // Please insert fields in the same order as in
     // frameworks/base/core/java/android/provider/Settings.java.
-    // Next tag = 196
+    // Next tag = 197
 }
 
 message SystemSettingsProto {
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index fcb9807..0c617ff 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -16,7 +16,7 @@
 
 syntax = "proto2";
 
-package com.android.server.am.proto;
+package com.android.server.am;
 
 import "frameworks/base/core/proto/android/app/activitymanager.proto";
 import "frameworks/base/core/proto/android/app/enums.proto";
@@ -59,11 +59,11 @@
 message ActivityStackSupervisorProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
   repeated ActivityDisplayProto displays = 2;
   optional KeyguardControllerProto keyguard_controller = 3;
   optional int32 focused_stack_id = 4;
-  optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 5;
+  optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
   // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
   // know what activity types to check for when invoking splitscreen multi-window.
   optional bool is_home_recents_component = 6;
@@ -73,7 +73,7 @@
 message ActivityDisplayProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated ActivityStackProto stacks = 3;
 }
@@ -81,10 +81,10 @@
 message ActivityStackProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated TaskRecordProto tasks = 3;
-  optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 4;
+  optional .com.android.server.wm.IdentifierProto resumed_activity = 4;
   optional int32 display_id = 5;
   optional bool fullscreen = 6;
   optional .android.graphics.RectProto bounds = 7;
@@ -93,7 +93,7 @@
 message TaskRecordProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
   optional int32 id = 2;
   repeated ActivityRecordProto activities = 3;
   optional int32 stack_id = 4;
@@ -111,8 +111,8 @@
 message ActivityRecordProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-  optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
-  optional .com.android.server.wm.proto.IdentifierProto identifier = 2;
+  optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
+  optional .com.android.server.wm.IdentifierProto identifier = 2;
   optional string state = 3;
   optional bool visible = 4;
   optional bool front_of_task = 5;
@@ -689,25 +689,14 @@
   }
   optional SleepStatus sleep_status = 27;
 
-  message VoiceProto {
+  message Voice {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional string session = 1;
     optional .android.os.PowerManagerProto.WakeLock wakelock = 2;
   }
-  optional VoiceProto running_voice = 28;
+  optional Voice running_voice = 28;
 
-  message VrControllerProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    enum VrMode {
-      FLAG_NON_VR_MODE = 0;
-      FLAG_VR_MODE = 1;
-      FLAG_PERSISTENT_VR_MODE = 2;
-    }
-    repeated VrMode vr_mode = 1;
-    optional int32 render_thread_id = 2;
-  }
   optional VrControllerProto vr_controller = 29;
 
   message DebugApp {
@@ -854,6 +843,19 @@
   optional string reason = 3;
 }
 
+// proto of class VrController.java
+message VrControllerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  enum VrMode {
+    FLAG_NON_VR_MODE = 0;
+    FLAG_VR_MODE = 1;
+    FLAG_PERSISTENT_VR_MODE = 2;
+  }
+  repeated VrMode vr_mode = 1;
+  optional int32 render_thread_id = 2;
+}
+
 message ProcessOomProto {
   option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
diff --git a/core/proto/android/server/animationadapter.proto b/core/proto/android/server/animationadapter.proto
index c4ffe8c..9bfa794 100644
--- a/core/proto/android/server/animationadapter.proto
+++ b/core/proto/android/server/animationadapter.proto
@@ -20,7 +20,7 @@
 import "frameworks/base/core/proto/android/view/remote_animation_target.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
-package com.android.server.wm.proto;
+package com.android.server.wm;
 option java_multiple_files = true;
 
 message AnimationAdapterProto {
diff --git a/core/proto/android/server/appwindowthumbnail.proto b/core/proto/android/server/appwindowthumbnail.proto
index 8f48d75..54ad193 100644
--- a/core/proto/android/server/appwindowthumbnail.proto
+++ b/core/proto/android/server/appwindowthumbnail.proto
@@ -19,7 +19,7 @@
 import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
-package com.android.server.wm.proto;
+package com.android.server.wm;
 option java_multiple_files = true;
 
 /**
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 9193129..122e5c4 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -20,7 +20,7 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/app/jobparameters.proto";
+import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/content/clipdata.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
@@ -465,7 +465,7 @@
         message StopReasonCount {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-            optional .android.app.JobParametersProto.CancelReason reason = 1;
+            optional .android.app.job.StopReasonEnum reason = 1;
             optional int32 count = 2;
         }
         repeated StopReasonCount stop_reasons = 9;
@@ -516,7 +516,7 @@
         optional int32 job_id = 4;
         optional string tag = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
         // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.
-        optional .android.app.JobParametersProto.CancelReason stop_reason = 6;
+        optional .android.app.job.StopReasonEnum stop_reason = 6;
     }
     repeated HistoryEvent history_event = 1;
 }
diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto
index dcc2b34..84560bc 100644
--- a/core/proto/android/server/surfaceanimator.proto
+++ b/core/proto/android/server/surfaceanimator.proto
@@ -20,7 +20,7 @@
 import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
-package com.android.server.wm.proto;
+package com.android.server.wm;
 option java_multiple_files = true;
 
 /**
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 9598f24..063135d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -28,7 +28,7 @@
 import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
-package com.android.server.wm.proto;
+package com.android.server.wm;
 
 option java_multiple_files = true;
 
diff --git a/core/proto/android/server/windowmanagertrace.proto b/core/proto/android/server/windowmanagertrace.proto
index 96a90bf..f502961 100644
--- a/core/proto/android/server/windowmanagertrace.proto
+++ b/core/proto/android/server/windowmanagertrace.proto
@@ -18,7 +18,7 @@
 
 import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 
-package com.android.server.wm.proto;
+package com.android.server.wm;
 
 option java_multiple_files = true;
 
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index f8050a1..88bb4a6 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -110,6 +110,7 @@
         optional bool is_launched = 6;
         optional EnabledState enabled_state = 7;
         optional string last_disabled_app_caller = 8;
+        optional string suspending_package = 9;
     }
 
     // Name of package. e.g. "com.android.providers.telephony".
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1b4d571..1924bac 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1341,6 +1341,13 @@
         android:label="@string/permlab_changeWifiState"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi @hide Allows apps to create and manage IPsec tunnels.
+         <p>Only granted to applications that are currently bound by the
+         system for creating and managing IPsec-based interfaces.
+    -->
+    <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
+        android:protectionLevel="signature|appop" />
+
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
@@ -1441,6 +1448,13 @@
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
+         from using them until they are unsuspended.
+         @hide
+    -->
+    <permission android:name="android.permission.SUSPEND_APPS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
     -->
@@ -3310,8 +3324,9 @@
     <permission android:name="android.permission.BACKUP"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows application to manage RecoverableKeyStoreLoader.
-    <p>Not for use by third-party applications.
+    <!-- @SystemApi Allows application to manage
+         {@link android.security.keystore.recovery.RecoveryController}.
+         <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.RECOVER_KEYSTORE"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 5c5b985..fa69038 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -35,8 +35,8 @@
         <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
             android:orientation="vertical">
 
             <LinearLayout
@@ -52,7 +52,7 @@
 
                 <TextView
                     android:id="@+id/autofill_save_title"
-                    android:paddingLeft="8dp"
+                    android:paddingStart="8dp"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:text="@string/autofill_save_title"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4a72bf9..3135455 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2151,6 +2151,9 @@
             @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
             -->
             <enum name="shortEdges" value="1" />
+            <!-- Use {@code shortEdges} instead. This is temporarily here to unblock pushing the SDK
+                 until all usages have been migrated to {@code shortEdges} -->
+            <enum name="always" value="1" />
             <!-- The window is never allowed to overlap with the DisplayCutout area.
             <p>
             This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN}
@@ -5965,6 +5968,9 @@
              in the encoded data. Setting this to infinite (-1) will result in the
              animation repeating as long as it is displayed (once start() is called). -->
         <attr name="repeatCount"/>
+        <!-- When true, automatically start animating. The default is false, meaning
+             that the animation will not start until start() is called. -->
+        <attr name="autoStart" />
     </declare-styleable>
 
     <!-- Drawable used to draw bitmaps. -->
@@ -7981,8 +7987,6 @@
              android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
         -->
         <attr name="maxLongVersionCode" format="string" />
-        <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
-        <attr name="urlBarResourceId" format="string" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 722102e..449d3e7 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -130,13 +130,14 @@
     <drawable name="notification_template_divider_media">#29ffffff</drawable>
     <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
     <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
-    <color name="notification_secondary_text_color_light">@color/secondary_text_material_light</color>
-    <color name="notification_secondary_text_color_dark">@color/secondary_text_material_dark</color>
+    <color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color>
+    <color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color>
+    <color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
+    <color name="notification_default_color_light">#a3202124</color>
 
     <color name="notification_material_background_color">#ffffffff</color>
 
     <color name="notification_default_color">#757575</color> <!-- Gray 600 -->
-    <color name="notification_icon_default_color">@color/notification_default_color</color>
 
     <color name="notification_progress_background_color">@color/secondary_text_material_light</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1083630..55c17b9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1996,7 +1996,7 @@
 
     <!-- If true, the doze component is not started until after the screen has been
          turned off and the screen off animation has been performed. -->
-    <bool name="config_dozeAfterScreenOff">false</bool>
+    <bool name="config_dozeAfterScreenOffByDefault">false</bool>
 
     <!-- Doze: should the TYPE_PICK_UP_GESTURE sensor be used as a pulse signal. -->
     <bool name="config_dozePulsePickup">false</bool>
@@ -2911,6 +2911,10 @@
          is non-interactive. -->
     <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
 
+    <!-- Allow the gesture power + volume up to change the ringer mode while the device
+         is interactive. -->
+    <bool name="config_volumeHushGestureEnabled">true</bool>
+
     <!-- Name of the component to handle network policy notifications. If present,
          disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
     <string translatable="false" name="config_networkPolicyNotificationComponent"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2c0deed..0246c80 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,8 +2869,6 @@
       <public name="outlineSpotShadowColor" />
       <public name="outlineAmbientShadowColor" />
       <public name="maxLongVersionCode" />
-      <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
-      <public name="urlBarResourceId" />
       <!-- @hide @SystemApi -->
       <public name="userRestriction" />
       <public name="textFontWeight" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aac4092..7038887 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -159,6 +159,9 @@
     <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. -->
     <string name="RestrictedStateContent">Temporarily turned off by your carrier</string>
 
+    <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control when multiple SIMs are active. -->
+    <string name="RestrictedStateContentMsimTemplate">Temporarily turned off by your carrier for SIM <xliff:g id="simNumber" example="1">%d</xliff:g></string>
+
     <!-- Displayed to tell the user that they should switch their network preference. -->
     <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string>
     <!-- Displayed to tell the user that they should switch their network preference. -->
@@ -227,14 +230,14 @@
     <string name="roamingTextSearching">Searching for Service</string>
 
     <!-- Displayed when WFC registration fails -->
-    <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
+    <string name="wfcRegErrorTitle">Couldn\u2019t set up Wi\u2011Fi calling</string>
     <!-- WFC Operator Error Messages showed as alerts -->
     <string-array name="wfcOperatorErrorAlertMessages">
         <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings. (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
     </string-array>
     <!-- WFC Operator Error Messages showed as notifications -->
     <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item>
+        <item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item>
     </string-array>
     <!-- Template for showing mobile network operator name while WFC is active -->
     <string-array name="wfcSpnFormats">
@@ -3085,13 +3088,13 @@
     <string name="wifi_available_title">Connect to open Wi\u2011Fi network</string>
     <!-- Notification title for a nearby carrier wireless network.-->
     <string name="wifi_available_carrier_network_title">Connect to carrier Wi\u2011Fi network</string>
-    <!-- Notification title when the system is connecting to the specified open network. The network name is specified in the notification content. -->
-    <string name="wifi_available_title_connecting">Connecting to open Wi\u2011Fi network</string>
-    <!-- Notification title when the system has connected to the open network. The network name is specified in the notification content. -->
+    <!-- Notification title when the system is connecting to the specified network. The network name is specified in the notification content. -->
+    <string name="wifi_available_title_connecting">Connecting to Wi\u2011Fi network</string>
+    <!-- Notification title when the system has connected to the network. The network name is specified in the notification content. -->
     <string name="wifi_available_title_connected">Connected to Wi\u2011Fi network</string>
-    <!-- Notification title when the system failed to connect to the specified open network. -->
+    <!-- Notification title when the system failed to connect to the specified network. -->
     <string name="wifi_available_title_failed_to_connect">Could not connect to Wi\u2011Fi network</string>
-    <!-- Notification content when the system failed to connect to the specified open network. This informs the user that tapping on this notification will open the wifi picker. -->
+    <!-- Notification content when the system failed to connect to the specified network. This informs the user that tapping on this notification will open the wifi picker. -->
     <string name="wifi_available_content_failed_to_connect">Tap to see all networks</string>
     <!-- Notification action name for connecting to the network specified in the notification body. -->
     <string name="wifi_available_action_connect">Connect</string>
@@ -4475,7 +4478,7 @@
     <string name="package_deleted_device_owner">Deleted by your admin</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
-    <string name="battery_saver_description">To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string>
+    <string name="battery_saver_description">To extend battery life, Battery Saver reduces your device\'s performance and limits or turns off vibration, location services, and background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string>
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
@@ -4578,14 +4581,14 @@
 
     <!-- Displayed when the USSD/SS request is modified by STK CC to a
     different request. This will be displayed in a toast. -->
-    <string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
-    <string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
-    <string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
-    <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
-    <string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
-    <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
-    <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
-    <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+    <string name="stk_cc_ussd_to_dial">USSD request changed to regular call</string>
+    <string name="stk_cc_ussd_to_ss">USSD request changed to SS request</string>
+    <string name="stk_cc_ussd_to_ussd">Changed to new USSD request</string>
+    <string name="stk_cc_ussd_to_dial_video">USSD request changed to video call</string>
+    <string name="stk_cc_ss_to_dial">SS request changed to regular call</string>
+    <string name="stk_cc_ss_to_dial_video">SS request changed to video call</string>
+    <string name="stk_cc_ss_to_ussd">SS request changed to USSD request</string>
+    <string name="stk_cc_ss_to_ss">Changed to new SS request</string>
 
     <!-- Content description of the work profile icon in the notification. -->
     <string name="notification_work_profile_content_description">Work profile</string>
@@ -4833,6 +4836,12 @@
     <string name="mmcc_illegal_ms">SIM not allowed for voice</string>
     <string name="mmcc_illegal_me">Phone not allowed for voice</string>
 
+    <!-- Title of notification when UE fails to register network with MM reject cause code when multiple SIMs are active. -->
+    <string name="mmcc_authentication_reject_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_imsi_unknown_in_hlr_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not provisioned</string>
+    <string name="mmcc_illegal_ms_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+    <string name="mmcc_illegal_me_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string>
+
     <!-- Popup window default title to be read by a screen reader-->
     <string name="popup_window_default_title">Popup Window</string>
 
@@ -4888,6 +4897,9 @@
     <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
     <string name="screenshot_edit">Edit</string>
 
+    <string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
+    <string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
+
     <!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] -->
     <string name="notification_channel_system_changes">System changes</string>
     <!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index fa3cf2f..b8a046f 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -473,7 +473,7 @@
     <style name="TextAppearance.Material.Notification.Reply" />
 
     <style name="TextAppearance.Material.Notification.Title">
-        <item name="textColor">@color/notification_primary_text_color_light</item>
+        <item name="fontFamily">sans-serif-medium</item>
         <item name="textSize">@dimen/notification_title_text_size</item>
     </style>
 
@@ -482,7 +482,6 @@
     </style>
 
     <style name="TextAppearance.Material.Notification.Info">
-        <item name="textColor">@color/notification_secondary_text_color_light</item>
         <item name="textSize">@dimen/notification_subtext_size</item>
     </style>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac01c4e..3bf97d0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -579,6 +579,7 @@
   <java-symbol type="string" name="RestrictedOnEmergencyTitle" />
   <java-symbol type="string" name="RestrictedOnNormalTitle" />
   <java-symbol type="string" name="RestrictedStateContent" />
+  <java-symbol type="string" name="RestrictedStateContentMsimTemplate" />
   <java-symbol type="string" name="notification_channel_network_alert" />
   <java-symbol type="string" name="notification_channel_call_forward" />
   <java-symbol type="string" name="notification_channel_emergency_callback" />
@@ -1024,6 +1025,8 @@
   <java-symbol type="string" name="volume_icon_description_media" />
   <java-symbol type="string" name="volume_icon_description_notification" />
   <java-symbol type="string" name="volume_icon_description_ringer" />
+  <java-symbol type="string" name="volume_dialog_ringer_guidance_vibrate" />
+  <java-symbol type="string" name="volume_dialog_ringer_guidance_silent" />
   <java-symbol type="string" name="wait" />
   <java-symbol type="string" name="webpage_unresponsive" />
   <java-symbol type="string" name="whichApplication" />
@@ -1817,7 +1820,7 @@
   <java-symbol type="bool" name="config_notificationHeaderClickableForExpand" />
   <java-symbol type="bool" name="config_enableNightMode" />
   <java-symbol type="bool" name="config_tintNotificationActionButtons" />
-  <java-symbol type="bool" name="config_dozeAfterScreenOff" />
+  <java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
   <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
   <java-symbol type="bool" name="config_enableHardwareFlpOverlay" />
@@ -2029,6 +2032,10 @@
   <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr" />
   <java-symbol type="string" name="mmcc_illegal_ms" />
   <java-symbol type="string" name="mmcc_illegal_me" />
+  <java-symbol type="string" name="mmcc_authentication_reject_msim_template" />
+  <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr_msim_template" />
+  <java-symbol type="string" name="mmcc_illegal_ms_msim_template" />
+  <java-symbol type="string" name="mmcc_illegal_me_msim_template" />
   <java-symbol type="string" name="notification_listener_binding_label" />
   <java-symbol type="string" name="vr_listener_binding_label" />
   <java-symbol type="string" name="condition_provider_service_binding_label" />
@@ -2115,7 +2122,6 @@
   <java-symbol type="layout" name="notification_template_material_big_text" />
   <java-symbol type="layout" name="notification_template_header" />
   <java-symbol type="layout" name="notification_material_media_action" />
-  <java-symbol type="color" name="notification_icon_default_color" />
   <java-symbol type="color" name="notification_progress_background_color" />
   <java-symbol type="id" name="media_actions" />
 
@@ -2621,6 +2627,7 @@
   <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
   <java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
   <java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
+  <java-symbol type="bool" name="config_volumeHushGestureEnabled" />
 
   <java-symbol type="drawable" name="platlogo_m" />
 
@@ -2779,7 +2786,6 @@
   <java-symbol type="drawable" name="ic_user_secure" />
 
   <java-symbol type="string" name="android_upgrading_notification_title" />
-  <java-symbol type="string" name="android_upgrading_notification_body" />
 
   <java-symbol type="string" name="usb_mtp_launch_notification_title" />
   <java-symbol type="string" name="usb_mtp_launch_notification_description" />
@@ -2965,6 +2971,8 @@
   <java-symbol type="color" name="notification_primary_text_color_dark" />
   <java-symbol type="color" name="notification_secondary_text_color_light" />
   <java-symbol type="color" name="notification_secondary_text_color_dark" />
+  <java-symbol type="color" name="notification_default_color_light" />
+  <java-symbol type="color" name="notification_default_color_dark" />
 
   <java-symbol type="string" name="app_category_game" />
   <java-symbol type="string" name="app_category_audio" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 2036e2f..87a9bd0e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -117,7 +117,7 @@
                     Settings.Global.APP_STANDBY_ENABLED,
                     Settings.Global.ASSISTED_GPS_ENABLED,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
-                    Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES,
+                    Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
                     Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
                     Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
                     Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
@@ -450,6 +450,7 @@
                     Settings.Global.WIFI_SAVED_STATE,
                     Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
                     Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
+                    Settings.Global.WIFI_SCORE_PARAMS,
                     Settings.Global.WIFI_SLEEP_POLICY,
                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
                     Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
@@ -581,7 +582,9 @@
                  Settings.Secure.KEYGUARD_SLICE_URI,
                  Settings.Secure.PARENTAL_CONTROL_ENABLED,
                  Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL,
-                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING);
+                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
+                 Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
+                 Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
index 3b4ad38..a5a3ca9 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
@@ -16,7 +16,7 @@
 
 package android.security.keystore.recovery;
 
-import static android.security.keystore.recovery.TrustedRootCertificates.listRootCertificates;
+import static android.security.keystore.recovery.TrustedRootCertificates.getRootCertificates;
 
 import static org.junit.Assert.assertTrue;
 
@@ -36,8 +36,8 @@
             "GoogleCloudKeyVaultServiceV1";
 
     @Test
-    public void listRootCertificates_listsGoogleCloudVaultV1Certificate() {
-        Map<String, X509Certificate> certificates = listRootCertificates();
+    public void getRootCertificates_listsGoogleCloudVaultV1Certificate() {
+        Map<String, X509Certificate> certificates = getRootCertificates();
 
         assertTrue(certificates.containsKey(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS));
     }
diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java
index be3a0be..2fe7db4 100644
--- a/core/tests/coretests/src/android/text/util/LinkifyTest.java
+++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java
@@ -31,6 +31,11 @@
 import android.text.method.LinkMovementMethod;
 import android.text.style.URLSpan;
 import android.util.Patterns;
+import android.view.textclassifier.SystemTextClassifier;
+import android.view.textclassifier.TextClassificationConstants;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextClassifierImpl;
+import android.view.textclassifier.TextLinks.TextLinkSpan;
 import android.widget.TextView;
 
 import org.junit.After;
@@ -38,7 +43,11 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 /**
  * LinkifyTest tests {@link Linkify}.
@@ -149,4 +158,55 @@
         assertEquals("android.com should be linkified", 1, spans.length);
         assertEquals("https://android.com", spans[0].getURL());
     }
+
+    @Test
+    public void testAddLinksAsync_useLegacyIfSmartDisabled_localTextClassifier()
+            throws Exception {
+        final TextClassificationConstants settings =
+                TextClassificationConstants.loadFromString("smart_linkify_enabled=false");
+        final TextClassifier classifier = new TextClassifierImpl(mContext, settings);
+        testAddLinksAsync_useLegacyIfSmartDisabled(classifier);
+    }
+
+    @Test
+    public void testAddLinksAsync_useLegacyIfSmartDisabled_systemTextClassifier()
+            throws Exception {
+        final TextClassificationConstants settings =
+                TextClassificationConstants.loadFromString("smart_linkify_enabled=false");
+        final TextClassifier classifier = new SystemTextClassifier(mContext, settings);
+        testAddLinksAsync_useLegacyIfSmartDisabled(classifier);
+    }
+
+    private void testAddLinksAsync_useLegacyIfSmartDisabled(TextClassifier classifier)
+            throws Exception {
+        final int linkMask = Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.WEB_URLS;
+        final String string = "example@android.com\n"
+                + "(415) 555-1212\n"
+                + "http://android.com\n"
+                + "100 Android Rd California";
+        final Spannable expected = new SpannableString(string);
+        final Spannable actual = new SpannableString(string);
+
+        Linkify.addLinks(expected, linkMask);  // legacy.
+        Linkify.addLinksAsync(actual, classifier, linkMask).get();
+
+        final URLSpan[] expectedSpans = expected.getSpans(0, expected.length(), URLSpan.class);
+        final TextLinkSpan[] actualSpans = actual.getSpans(0, actual.length(), TextLinkSpan.class);
+        assertEquals(expectedSpans.length, actualSpans.length);
+        final Set<List> expectedLinkSpec = new HashSet<>();
+        final Set<List> actualLinkSpec = new HashSet<>();
+        for (int i = 0; i < expectedSpans.length; i++) {
+            final URLSpan expectedSpan = expectedSpans[i];
+            final TextLinkSpan actualSpan = actualSpans[i];
+            expectedLinkSpec.add(Arrays.asList(
+                    expected.getSpanStart(expectedSpan),
+                    expected.getSpanEnd(expectedSpan),
+                    expectedSpan.getURL()));
+            actualLinkSpec.add(Arrays.asList(
+                    actual.getSpanStart(actualSpan),
+                    actual.getSpanEnd(actualSpan),
+                    actualSpan.getUrl()));
+        }
+        assertEquals(expectedLinkSpec, actualLinkSpec);
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index e6ac682..1fd24e3 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -99,6 +99,10 @@
         assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
                 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
                 "DummyNonDefaultAutoVoiceIme1");
+        assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US,
+                "DummyDefaultEnKeyboardIme");
+        assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US,
+                "DummyDefaultEnKeyboardIme");
 
         // locale: en_GB
         assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
@@ -106,6 +110,10 @@
         assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
                 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
                 "DummyNonDefaultAutoVoiceIme1");
+        assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB,
+                "DummyDefaultEnKeyboardIme");
+        assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB,
+                "DummyDefaultEnKeyboardIme");
 
         // locale: ja_JP
         assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
@@ -113,6 +121,10 @@
         assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
                 "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0",
                 "DummyNonDefaultAutoVoiceIme1");
+        assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP,
+                "DummyDefaultEnKeyboardIme");
+        assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP,
+                "DummyDefaultEnKeyboardIme");
     }
 
     @Test
@@ -120,34 +132,49 @@
         // locale: en_US
         assertDefaultEnabledImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
                 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rUS"), LOCALE_EN_US,
+                "com.android.apps.inputmethod.latin");
 
         // locale: en_GB
         assertDefaultEnabledImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
                 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rGB"), LOCALE_EN_GB,
+                "com.android.apps.inputmethod.latin");
 
         // locale: en_IN
         assertDefaultEnabledImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
                 "com.android.apps.inputmethod.hindi",
                 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("en-rIN"), LOCALE_EN_IN,
+                "com.android.apps.inputmethod.hindi",
+                "com.android.apps.inputmethod.latin");
 
         // locale: hi
         assertDefaultEnabledImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
                 "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin",
                 "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("hi"), LOCALE_HI,
+                "com.android.apps.inputmethod.hindi", "com.android.apps.inputmethod.latin");
 
         // locale: ja_JP
         assertDefaultEnabledImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
                 "com.android.apps.inputmethod.japanese", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("ja-rJP"), LOCALE_JA_JP,
+                "com.android.apps.inputmethod.japanese");
 
         // locale: zh_CN
         assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
                 "com.android.apps.inputmethod.pinyin", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("zh-rCN"), LOCALE_ZH_CN,
+                "com.android.apps.inputmethod.pinyin");
 
         // locale: zh_TW
         // Note: In this case, no IME is suitable for the system locale. Hence we will pick up a
         // fallback IME regardless of the "default" attribute.
         assertDefaultEnabledImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
                 "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.voice");
+        assertDefaultEnabledMinimumImes(getSamplePreinstalledImes("zh-rTW"), LOCALE_ZH_TW,
+                "com.android.apps.inputmethod.latin");
     }
 
     @Test
@@ -785,6 +812,18 @@
         }
     }
 
+    private void assertDefaultEnabledMinimumImes(final ArrayList<InputMethodInfo> preinstalledImes,
+            final Locale systemLocale, String... expectedImeNames) {
+        final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
+        final String[] actualImeNames = getPackageNames(
+                InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes,
+                        true /* onlyMinimum */));
+        assertEquals(expectedImeNames.length, actualImeNames.length);
+        for (int i = 0; i < expectedImeNames.length; ++i) {
+            assertEquals(expectedImeNames[i], actualImeNames[i]);
+        }
+    }
+
     private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
         Parcel p = null;
         try {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index f5fe80c..94492ba 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -43,6 +43,7 @@
         KernelUidCpuActiveTimeReaderTest.class,
         KernelUidCpuClusterTimeReaderTest.class,
         KernelWakelockReaderTest.class,
+        LongSamplingCounterTest.class,
         LongSamplingCounterArrayTest.class,
         PowerCalculatorTest.class,
         PowerProfileTest.class
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
new file mode 100644
index 0000000..853bf8a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounter;
+import static com.android.internal.os.BatteryStatsImpl.TimeBase;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test class for {@link LongSamplingCounter}.
+ *
+ * To run the tests, use
+ *
+ * bit FrameworksCoreTests:com.android.internal.os.LongSamplingCounterTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSamplingCounterTest {
+
+    private static final long COUNT = 1111;
+    private static final long CURRENT_COUNT = 5555;
+
+    @Mock
+    private TimeBase mTimeBase;
+    private LongSamplingCounter mCounter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mCounter = new LongSamplingCounter(mTimeBase);
+        Mockito.reset(mTimeBase);
+    }
+
+    @Test
+    public void testReadWriteParcel() {
+        final Parcel parcel = Parcel.obtain();
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.writeToParcel(parcel);
+        parcel.setDataPosition(0);
+
+        // Now clear counterArray and verify values are read from parcel correctly.
+        updateCounts(0, 0);
+
+        mCounter = new LongSamplingCounter(mTimeBase, parcel);
+        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testReadWriteSummaryParcel() {
+        final Parcel parcel = Parcel.obtain();
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.writeSummaryFromParcelLocked(parcel);
+        parcel.setDataPosition(0);
+
+        // Now clear counterArray and verify values are read from parcel correctly.
+        updateCounts(0, 0);
+
+        mCounter.readSummaryFromParcelLocked(parcel);
+        assertEquals(COUNT, mCounter.mCount);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testOnTimeStarted() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.onTimeStarted(0, 0, 0);
+        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(COUNT, mCounter.mUnpluggedCount);
+    }
+
+    @Test
+    public void testOnTimeStopped() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.onTimeStopped(0, 0, 0);
+        assertEquals(COUNT, mCounter.mCount);
+    }
+
+    @Test
+    public void testAddCountLocked() {
+        updateCounts(0, 0);
+        assertEquals(0, mCounter.getCountLocked(0));
+        when(mTimeBase.isRunning()).thenReturn(true);
+        mCounter.addCountLocked(111);
+        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(111, mCounter.mCurrentCount);
+        mCounter.addCountLocked(222);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(333, mCounter.mCurrentCount);
+
+        when(mTimeBase.isRunning()).thenReturn(false);
+        mCounter.addCountLocked(456);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(789, mCounter.mCurrentCount);
+
+        mCounter.addCountLocked(444, true);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1233, mCounter.mCurrentCount);
+        mCounter.addCountLocked(567, false);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1800, mCounter.mCurrentCount);
+    }
+
+    @Test
+    public void testUpdate() {
+        updateCounts(0, 0);
+        assertEquals(0, mCounter.getCountLocked(0));
+        when(mTimeBase.isRunning()).thenReturn(true);
+        mCounter.update(111);
+        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(111, mCounter.mCurrentCount);
+        mCounter.update(333);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(333, mCounter.mCurrentCount);
+
+        when(mTimeBase.isRunning()).thenReturn(false);
+        mCounter.update(789);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(789, mCounter.mCurrentCount);
+        mCounter.update(100);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(100, mCounter.mCurrentCount);
+
+        mCounter.update(544, true);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(544, mCounter.mCurrentCount);
+        mCounter.update(1544, false);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1544, mCounter.mCurrentCount);
+    }
+
+    @Test
+    public void testReset() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        // Test with detachIfReset=false
+        mCounter.reset(false /* detachIfReset */);
+        assertEquals(0, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        verifyZeroInteractions(mTimeBase);
+
+        updateCounts(COUNT, CURRENT_COUNT);
+        // Test with detachIfReset=true
+        mCounter.reset(true /* detachIfReset */);
+        assertEquals(0, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        verify(mTimeBase).remove(mCounter);
+        verifyNoMoreInteractions(mTimeBase);
+    }
+
+    @Test
+    public void testDetach() {
+        mCounter.detach();
+        verify(mTimeBase).remove(mCounter);
+        verifyNoMoreInteractions(mTimeBase);
+    }
+
+    private void updateCounts(long total, long current) {
+        mCounter.mCount = total;
+        mCounter.mCurrentCount = current;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index 002df88..518cadd 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.policy;
 
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -27,7 +26,6 @@
 import android.content.Context;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
@@ -44,7 +42,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(detail = "Promote to presubmit once monitored to be stable.")
 @RunWith(AndroidJUnit4.class)
 public final class PhoneWindowTest {
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d925441..b0bc102 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1490,6 +1490,10 @@
      * across the top of the bitmap from left to right. A more general version of this method is
      * drawVertices().
      *
+     * Prior to API level {@value Build.VERSION_CODES#P} vertOffset and colorOffset were ignored,
+     * effectively treating them as zeros. In API level {@value Build.VERSION_CODES#P} and above
+     * these parameters will be respected.
+     *
      * @param bitmap The bitmap to draw using the mesh
      * @param meshWidth The number of columns in the mesh. Nothing is drawn if this is 0
      * @param meshHeight The number of rows in the mesh. Nothing is drawn if this is 0
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 2f09c65..5ca0ad6 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -24,6 +24,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
@@ -102,7 +103,7 @@
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
-            return nCreate(mData, mOffset, mLength);
+            return nCreate(mData, mOffset, mLength, this);
         }
     }
 
@@ -117,9 +118,9 @@
             if (!mBuffer.isDirect() && mBuffer.hasArray()) {
                 int offset = mBuffer.arrayOffset() + mBuffer.position();
                 int length = mBuffer.limit() - mBuffer.position();
-                return nCreate(mBuffer.array(), offset, length);
+                return nCreate(mBuffer.array(), offset, length, this);
             }
-            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit());
+            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit(), this);
         }
     }
 
@@ -156,7 +157,7 @@
                     throw new FileNotFoundException(mUri.toString());
                 }
 
-                return createFromStream(is, true);
+                return createFromStream(is, true, this);
             }
 
             final FileDescriptor fd = assetFd.getFileDescriptor();
@@ -166,9 +167,9 @@
             try {
                 try {
                     Os.lseek(fd, offset, SEEK_SET);
-                    decoder = nCreate(fd);
+                    decoder = nCreate(fd, this);
                 } catch (ErrnoException e) {
-                    decoder = createFromStream(new FileInputStream(fd), true);
+                    decoder = createFromStream(new FileInputStream(fd), true, this);
                 }
             } finally {
                 if (decoder == null) {
@@ -182,18 +183,19 @@
     }
 
     @NonNull
-    private static ImageDecoder createFromFile(@NonNull File file) throws IOException {
+    private static ImageDecoder createFromFile(@NonNull File file,
+            @NonNull Source source) throws IOException {
         FileInputStream stream = new FileInputStream(file);
         FileDescriptor fd = stream.getFD();
         try {
             Os.lseek(fd, 0, SEEK_CUR);
         } catch (ErrnoException e) {
-            return createFromStream(stream, true);
+            return createFromStream(stream, true, source);
         }
 
         ImageDecoder decoder = null;
         try {
-            decoder = nCreate(fd);
+            decoder = nCreate(fd, source);
         } finally {
             if (decoder == null) {
                 IoUtils.closeQuietly(stream);
@@ -207,12 +209,12 @@
 
     @NonNull
     private static ImageDecoder createFromStream(@NonNull InputStream is,
-            boolean closeInputStream) throws IOException {
+            boolean closeInputStream, Source source) throws IOException {
         // Arbitrary size matches BitmapFactory.
         byte[] storage = new byte[16 * 1024];
         ImageDecoder decoder = null;
         try {
-            decoder = nCreate(is, storage);
+            decoder = nCreate(is, storage, source);
         } finally {
             if (decoder == null) {
                 if (closeInputStream) {
@@ -260,7 +262,7 @@
                 }
                 InputStream is = mInputStream;
                 mInputStream = null;
-                return createFromStream(is, false);
+                return createFromStream(is, false, this);
             }
         }
     }
@@ -305,7 +307,7 @@
                 }
                 AssetInputStream ais = mAssetInputStream;
                 mAssetInputStream = null;
-                return createFromAsset(ais);
+                return createFromAsset(ais, this);
             }
         }
     }
@@ -340,18 +342,19 @@
                 mResDensity = value.density;
             }
 
-            return createFromAsset((AssetInputStream) is);
+            return createFromAsset((AssetInputStream) is, this);
         }
     }
 
     /**
      *  ImageDecoder will own the AssetInputStream.
      */
-    private static ImageDecoder createFromAsset(AssetInputStream ais) throws IOException {
+    private static ImageDecoder createFromAsset(AssetInputStream ais,
+            Source source) throws IOException {
         ImageDecoder decoder = null;
         try {
             long asset = ais.getNativeAsset();
-            decoder = nCreate(asset);
+            decoder = nCreate(asset, source);
         } finally {
             if (decoder == null) {
                 IoUtils.closeQuietly(ais);
@@ -375,7 +378,7 @@
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
             InputStream is = mAssets.open(mFileName);
-            return createFromAsset((AssetInputStream) is);
+            return createFromAsset((AssetInputStream) is, this);
         }
     }
 
@@ -388,7 +391,7 @@
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
-            return createFromFile(mFile);
+            return createFromFile(mFile, this);
         }
     }
 
@@ -431,9 +434,10 @@
         }
     };
 
-    /**
-     *  Thrown if the provided data is incomplete.
+    /** @removed
+     * @deprecated Subsumed by {@link #DecodeException}.
      */
+    @java.lang.Deprecated
     public static class IncompleteException extends IOException {};
 
     /**
@@ -453,24 +457,102 @@
 
     };
 
-    /**
-     *  An Exception was thrown reading the {@link Source}.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_EXCEPTION}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_EXCEPTION  = 1;
 
-    /**
-     *  The encoded data was incomplete.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_INCOMPLETE}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_INCOMPLETE = 2;
 
-    /**
-     *  The encoded data contained an error.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_MALFORMED_DATA}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_ERROR      = 3;
 
-    @Retention(SOURCE)
-    @IntDef({ ERROR_SOURCE_EXCEPTION, ERROR_SOURCE_INCOMPLETE, ERROR_SOURCE_ERROR })
-    public @interface Error {};
+    /**
+     *  Information about an interrupted decode.
+     */
+    public static final class DecodeException extends IOException {
+        /**
+         *  An Exception was thrown reading the {@link Source}.
+         */
+        public static final int SOURCE_EXCEPTION  = 1;
+
+        /**
+         *  The encoded data was incomplete.
+         */
+        public static final int SOURCE_INCOMPLETE = 2;
+
+        /**
+         *  The encoded data contained an error.
+         */
+        public static final int SOURCE_MALFORMED_DATA      = 3;
+
+        /** @hide **/
+        @Retention(SOURCE)
+        @IntDef(value = { SOURCE_EXCEPTION, SOURCE_INCOMPLETE, SOURCE_MALFORMED_DATA },
+                prefix = {"SOURCE_"})
+        public @interface Error {};
+
+        @Error final int mError;
+        @NonNull final Source mSource;
+
+        DecodeException(@Error int error, @Nullable Throwable cause, @NonNull Source source) {
+            super(errorMessage(error, cause), cause);
+            mError = error;
+            mSource = source;
+        }
+
+        /**
+         * Private method called by JNI.
+         */
+        @SuppressWarnings("unused")
+        DecodeException(@Error int error, @Nullable String msg, @Nullable Throwable cause,
+                @NonNull Source source) {
+            super(msg + errorMessage(error, cause), cause);
+            mError = error;
+            mSource = source;
+        }
+
+        /**
+         *  Retrieve the reason that decoding was interrupted.
+         *
+         *  <p>If the error is {@link #SOURCE_EXCEPTION}, the underlying
+         *  {@link java.lang.Throwable} can be retrieved with
+         *  {@link java.lang.Throwable#getCause}.</p>
+         */
+        @Error
+        public int getError() {
+            return mError;
+        }
+
+        /**
+         *  Retrieve the {@link Source} that was interrupted.
+         */
+        @NonNull
+        public Source getSource() {
+            return mSource;
+        }
+
+        private static String errorMessage(@Error int error, @Nullable Throwable cause) {
+            switch (error) {
+                case SOURCE_EXCEPTION:
+                    return "Exception in input: " + cause;
+                case SOURCE_INCOMPLETE:
+                    return "Input was incomplete.";
+                case SOURCE_MALFORMED_DATA:
+                    return "Input contained an error.";
+                default:
+                    return "";
+            }
+        }
+    }
 
     /**
      *  Optional listener supplied to the ImageDecoder.
@@ -486,13 +568,12 @@
          *  optionally finish the rest of the decode/creation process to create
          *  a partial {@link Drawable}/{@link Bitmap}.
          *
-         *  @param error indicating what interrupted the decode.
-         *  @param source that had the error.
+         *  @param e containing information about the decode interruption.
          *  @return True to create and return a {@link Drawable}/{@link Bitmap}
          *      with partial data. False (which is the default) to abort the
-         *      decode and throw {@link java.io.IOException}.
+         *      decode and throw {@code e}.
          */
-        public boolean onPartialImage(@Error int error, @NonNull Source source);
+        boolean onPartialImage(@NonNull DecodeException e);
     };
 
     // Fields
@@ -667,6 +748,7 @@
      * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
      * @hide
      */
+    @TestApi
     public static Source createSource(Resources res, InputStream is, int density) {
         return new InputStreamSource(res, is, density);
     }
@@ -1087,14 +1169,8 @@
     @NonNull
     private Bitmap decodeBitmapInternal() throws IOException {
         checkState();
-        // nDecodeBitmap calls onPartialImage only if mOnPartialImageListener
-        // exists
-        ImageDecoder partialImagePtr = mOnPartialImageListener == null ? null : this;
-        // nDecodeBitmap calls postProcessAndRelease only if mPostProcessor
-        // exists.
-        ImageDecoder postProcessPtr = mPostProcessor == null ? null : this;
-        return nDecodeBitmap(mNativePtr, partialImagePtr,
-                postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
+        return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
+                mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mRequireUnpremultiplied,
                 mConserveMemory, mDecodeAsAlphaMask);
     }
@@ -1310,23 +1386,28 @@
      * Private method called by JNI.
      */
     @SuppressWarnings("unused")
-    private boolean onPartialImage(@Error int error) {
-        return mOnPartialImageListener.onPartialImage(error, mSource);
+    private void onPartialImage(@DecodeException.Error int error, @Nullable Throwable cause)
+            throws DecodeException {
+        DecodeException exception = new DecodeException(error, cause, mSource);
+        if (mOnPartialImageListener == null
+                || !mOnPartialImageListener.onPartialImage(exception)) {
+            throw exception;
+        }
     }
 
-    private static native ImageDecoder nCreate(long asset) throws IOException;
-    private static native ImageDecoder nCreate(ByteBuffer buffer,
-                                               int position,
-                                               int limit) throws IOException;
-    private static native ImageDecoder nCreate(byte[] data, int offset,
-                                               int length) throws IOException;
-    private static native ImageDecoder nCreate(InputStream is, byte[] storage);
+    private static native ImageDecoder nCreate(long asset, Source src) throws IOException;
+    private static native ImageDecoder nCreate(ByteBuffer buffer, int position,
+                                               int limit, Source src) throws IOException;
+    private static native ImageDecoder nCreate(byte[] data, int offset, int length,
+                                               Source src) throws IOException;
+    private static native ImageDecoder nCreate(InputStream is, byte[] storage,
+                                               Source src) throws IOException;
     // The fd must be seekable.
-    private static native ImageDecoder nCreate(FileDescriptor fd) throws IOException;
+    private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException;
     @NonNull
     private static native Bitmap nDecodeBitmap(long nativePtr,
-            @Nullable ImageDecoder partialImageListener,
-            @Nullable ImageDecoder postProcessor,
+            @NonNull ImageDecoder decoder,
+            boolean doPostProcess,
             int width, int height,
             @Nullable Rect cropRect, boolean mutable,
             int allocator, boolean requireUnpremul,
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 9ac94d8..d01ff6f 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -209,6 +209,8 @@
         public PictureCanvas(Picture pict, long nativeCanvas) {
             super(nativeCanvas);
             mPicture = pict;
+            // Disable bitmap density scaling. This matches DisplayListCanvas.
+            mDensity = 0;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index c0f4920..457e4aa 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -261,6 +261,12 @@
         if (repeatCount != REPEAT_UNDEFINED) {
             this.setRepeatCount(repeatCount);
         }
+
+        boolean autoStart = a.getBoolean(
+                R.styleable.AnimatedImageDrawable_autoStart, false);
+        if (autoStart && mState.mNativePtr != 0) {
+            this.start();
+        }
     }
 
     /**
@@ -292,8 +298,7 @@
         mState = new State(nCreate(nativeImageDecoder, decoder, width, height, cropRect),
                 inputStream, afd);
 
-        // FIXME: Use the right size for the native allocation.
-        long nativeSize = 200;
+        final long nativeSize = nNativeByteSize(mState.mNativePtr);
         NativeAllocationRegistry registry = new NativeAllocationRegistry(
                 AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
         registry.registerNativeAllocation(mState, mState.mNativePtr);
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 28d0bc4..c529f87 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -26,8 +26,8 @@
 
 namespace android {
 
-AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage)
-        : mSkAnimatedImage(std::move(animatedImage)) {
+AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
+        : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
     mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration();
 }
 
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index f4e2ba7..a92b62d 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -45,7 +45,9 @@
  */
 class ANDROID_API AnimatedImageDrawable : public SkDrawable {
 public:
-    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage);
+    // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the
+    // Snapshots.
+    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
 
     /**
      * This updates the internal time and returns true if the animation needs
@@ -100,11 +102,17 @@
     Snapshot decodeNextFrame();
     Snapshot reset();
 
+    size_t byteSize() const {
+        return sizeof(this) + mBytesUsed;
+    }
+
 protected:
     virtual void onDraw(SkCanvas* canvas) override;
 
 private:
     sk_sp<SkAnimatedImage> mSkAnimatedImage;
+    const size_t mBytesUsed;
+
     bool mRunning = false;
     bool mStarting = false;
 
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index d04bb2e..f341cf9 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -276,6 +276,8 @@
                         const SkPath& path, float hOffset, float vOffset, const Paint& paint,
                         const Typeface* typeface);
 
+    static int GetApiLevel() { return sApiLevel; }
+
 protected:
     void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 820789d..f4d8051 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -355,7 +355,14 @@
             // Already drew for this vsync pulse, UI draw request missed
             // the deadline for RT animations
             info.out.canDrawThisFrame = false;
-        } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
+        }
+        /* This logic exists to try and recover from a display latch miss, which essentially
+         * results in the bufferqueue being double-buffered instead of triple-buffered.
+         * SurfaceFlinger itself now tries to handle & recover from this situation, so this
+         * logic should no longer be necessary. As it's occasionally triggering when
+         * undesired disable it.
+         * TODO: Remove this entirely if the results are solid.
+        else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
                    (latestVsync - mLastDropVsync) < 500_ms) {
             // It's been several frame intervals, assume the buffer queue is fine
             // or the last drop was too recent
@@ -367,6 +374,7 @@
                 mLastDropVsync = mRenderThread.timeLord().latestVsync();
             }
         }
+        */
     } else {
         info.out.canDrawThisFrame = true;
     }
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 412cc29..2152e1e 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -83,6 +83,20 @@
      */
     public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2;
 
+    /**
+     * GNSS measurement tracking loop state
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "STATE_" }, value = {
+            STATE_CODE_LOCK, STATE_BIT_SYNC, STATE_SUBFRAME_SYNC,
+            STATE_TOW_DECODED, STATE_MSEC_AMBIGUOUS, STATE_SYMBOL_SYNC, STATE_GLO_STRING_SYNC,
+            STATE_GLO_TOD_DECODED, STATE_BDS_D2_BIT_SYNC, STATE_BDS_D2_SUBFRAME_SYNC,
+            STATE_GAL_E1BC_CODE_LOCK, STATE_GAL_E1C_2ND_CODE_LOCK, STATE_GAL_E1B_PAGE_SYNC,
+            STATE_SBAS_SYNC, STATE_TOW_KNOWN, STATE_GLO_TOD_KNOWN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
     /** This GNSS measurement's tracking state is invalid or unknown. */
     public static final int STATE_UNKNOWN = 0;
     /** This GNSS measurement's tracking state has code lock. */
@@ -133,29 +147,68 @@
     private static final int STATE_ALL = 0x3fff;  // 2 bits + 4 bits + 4 bits + 4 bits = 14 bits
 
     /**
-     * The state of the 'Accumulated Delta Range' is invalid or unknown.
+     * GNSS measurement accumulated delta range state
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "ADR_STATE_" }, value = {
+            ADR_STATE_VALID, ADR_STATE_RESET, ADR_STATE_CYCLE_SLIP, ADR_STATE_HALF_CYCLE_RESOLVED,
+            ADR_STATE_HALF_CYCLE_REPORTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AdrState {}
+
+    /**
+     * The state of the value {@link #getAccumulatedDeltaRangeMeters()} is invalid or unknown.
      */
     public static final int ADR_STATE_UNKNOWN = 0;
 
     /**
-     * The state of the 'Accumulated Delta Range' is valid.
+     * The state of the {@link #getAccumulatedDeltaRangeMeters()} is valid.
      */
     public static final int ADR_STATE_VALID = (1<<0);
 
     /**
-     * The state of the 'Accumulated Delta Range' has detected a reset.
+     * The state of the {@link #getAccumulatedDeltaRangeMeters()} has detected a reset.
      */
     public static final int ADR_STATE_RESET = (1<<1);
 
     /**
-     * The state of the 'Accumulated Delta Range' has a cycle slip detected.
+     * The state of the {@link #getAccumulatedDeltaRangeMeters()} has a cycle slip detected.
      */
     public static final int ADR_STATE_CYCLE_SLIP = (1<<2);
 
     /**
-     * All the 'Accumulated Delta Range' flags.
+     * Reports whether the value {@link #getAccumulatedDeltaRangeMeters()} has resolved the half
+     * cycle ambiguity.
+     *
+     * <p> When this bit is set, the {@link #getAccumulatedDeltaRangeMeters()} corresponds to the
+     * carrier phase measurement plus an accumulated integer number of carrier full cycles.
+     *
+     * <p> When this bit is unset, the {@link #getAccumulatedDeltaRangeMeters()} corresponds to the
+     * carrier phase measurement plus an accumulated integer number of carrier half cycles.
      */
-    private static final int ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+    public static final int ADR_STATE_HALF_CYCLE_RESOLVED = (1<<3);
+
+    /**
+     * Reports whether the flag {@link #ADR_STATE_HALF_CYCLE_RESOLVED} has been reported by the
+     * GNSS hardware.
+     *
+     * <p> When this bit is set, the value of {@link #getAccumulatedDeltaRangeUncertaintyMeters()}
+     * can be low (centimeter level) whether or not the half cycle ambiguity is resolved.
+     *
+     * <p> When this bit is unset, the value of {@link #getAccumulatedDeltaRangeUncertaintyMeters()}
+     * is larger, to cover the potential error due to half cycle ambiguity being unresolved.
+     */
+    public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
+
+    /**
+     * All the 'Accumulated Delta Range' flags.
+     * @hide
+     */
+    @TestApi
+    public static final int ADR_STATE_ALL =
+            ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP |
+            ADR_STATE_HALF_CYCLE_RESOLVED | ADR_STATE_HALF_CYCLE_REPORTED;
 
     // End enumerations in sync with gps.h
 
@@ -278,6 +331,7 @@
      *
      * <p>This value helps interpret {@link #getReceivedSvTimeNanos()}.
      */
+    @State
     public int getState() {
         return mState;
     }
@@ -287,7 +341,7 @@
      * @hide
      */
     @TestApi
-    public void setState(int value) {
+    public void setState(@State int value) {
         mState = value;
     }
 
@@ -557,6 +611,7 @@
      * <p>It indicates whether {@link #getAccumulatedDeltaRangeMeters()} is reset or there is a
      * cycle slip (indicating 'loss of lock').
      */
+    @AdrState
     public int getAccumulatedDeltaRangeState() {
         return mAccumulatedDeltaRangeState;
     }
@@ -566,7 +621,7 @@
      * @hide
      */
     @TestApi
-    public void setAccumulatedDeltaRangeState(int value) {
+    public void setAccumulatedDeltaRangeState(@AdrState int value) {
         mAccumulatedDeltaRangeState = value;
     }
 
@@ -589,7 +644,15 @@
         if ((mAccumulatedDeltaRangeState & ADR_STATE_CYCLE_SLIP) == ADR_STATE_CYCLE_SLIP) {
             builder.append("CycleSlip|");
         }
-        int remainingStates = mAccumulatedDeltaRangeState & ~ADR_ALL;
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_HALF_CYCLE_RESOLVED) ==
+                ADR_STATE_HALF_CYCLE_RESOLVED) {
+            builder.append("HalfCycleResolved|");
+        }
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_HALF_CYCLE_REPORTED)
+                == ADR_STATE_HALF_CYCLE_REPORTED) {
+            builder.append("HalfCycleReported|");
+        }
+        int remainingStates = mAccumulatedDeltaRangeState & ~ADR_STATE_ALL;
         if (remainingStates > 0) {
             builder.append("Other(");
             builder.append(Integer.toBinaryString(remainingStates));
@@ -674,7 +737,7 @@
      * L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary
      * common use central frequency, e.g. L1 = 1575.45 MHz for GPS.
      *
-     * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two raw
+     * <p> For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two raw
      * measurement objects will be reported for this same satellite, in one of the measurement
      * objects, all the values related to L1 will be filled, and in the other all of the values
      * related to L5 will be filled.
@@ -709,7 +772,10 @@
 
     /**
      * Returns {@code true} if {@link #getCarrierCycles()} is available, {@code false} otherwise.
+     * 
+     * @deprecated use {@link #getAccumulatedDeltaRangeState()} instead.
      */
+    @Deprecated
     public boolean hasCarrierCycles() {
         return isFlagSet(HAS_CARRIER_CYCLES);
     }
@@ -720,16 +786,24 @@
      * <p>The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
      *
      * <p>The value is only available if {@link #hasCarrierCycles()} is {@code true}.
+     *
+     * @deprecated use {@link #getAccumulatedDeltaRangeMeters()} instead.
      */
+    @Deprecated
     public long getCarrierCycles() {
         return mCarrierCycles;
     }
 
     /**
      * Sets the number of full carrier cycles between the satellite and the receiver.
+     *
+     * @deprecated use {@link #setAccumulatedDeltaRangeMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
+     * 
      * @hide
      */
     @TestApi
+    @Deprecated
     public void setCarrierCycles(long value) {
         setFlag(HAS_CARRIER_CYCLES);
         mCarrierCycles = value;
@@ -737,9 +811,13 @@
 
     /**
      * Resets the number of full carrier cycles between the satellite and the receiver.
+     * 
+     * @deprecated use {@link #setAccumulatedDeltaRangeMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
      * @hide
      */
     @TestApi
+    @Deprecated
     public void resetCarrierCycles() {
         resetFlag(HAS_CARRIER_CYCLES);
         mCarrierCycles = Long.MIN_VALUE;
@@ -747,7 +825,10 @@
 
     /**
      * Returns {@code true} if {@link #getCarrierPhase()} is available, {@code false} otherwise.
+     * 
+     * @deprecated use {@link #getAccumulatedDeltaRangeState()} instead.
      */
+    @Deprecated
     public boolean hasCarrierPhase() {
         return isFlagSet(HAS_CARRIER_PHASE);
     }
@@ -764,16 +845,24 @@
      * <p>The error estimate for this value is {@link #getCarrierPhaseUncertainty()}.
      *
      * <p>The value is only available if {@link #hasCarrierPhase()} is {@code true}.
+     *
+     * @deprecated use {@link #getAccumulatedDeltaRangeMeters()} instead.
      */
+    @Deprecated
     public double getCarrierPhase() {
         return mCarrierPhase;
     }
 
     /**
      * Sets the RF phase detected by the receiver.
+     * 
+     * @deprecated use {@link #setAccumulatedDeltaRangeMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
+     * 
      * @hide
      */
     @TestApi
+    @Deprecated
     public void setCarrierPhase(double value) {
         setFlag(HAS_CARRIER_PHASE);
         mCarrierPhase = value;
@@ -781,9 +870,14 @@
 
     /**
      * Resets the RF phase detected by the receiver.
+     * 
+     * @deprecated use {@link #setAccumulatedDeltaRangeMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
+     * 
      * @hide
      */
     @TestApi
+    @Deprecated
     public void resetCarrierPhase() {
         resetFlag(HAS_CARRIER_PHASE);
         mCarrierPhase = Double.NaN;
@@ -792,7 +886,10 @@
     /**
      * Returns {@code true} if {@link #getCarrierPhaseUncertainty()} is available, {@code false}
      * otherwise.
+     * 
+     * @deprecated use {@link #getAccumulatedDeltaRangeState()} instead.
      */
+    @Deprecated
     public boolean hasCarrierPhaseUncertainty() {
         return isFlagSet(HAS_CARRIER_PHASE_UNCERTAINTY);
     }
@@ -803,16 +900,24 @@
      * <p>The uncertainty is represented as an absolute (single sided) value.
      *
      * <p>The value is only available if {@link #hasCarrierPhaseUncertainty()} is {@code true}.
+     *
+     * @deprecated use {@link #getAccumulatedDeltaRangeUncertaintyMeters()} instead.
      */
+    @Deprecated
     public double getCarrierPhaseUncertainty() {
         return mCarrierPhaseUncertainty;
     }
 
     /**
      * Sets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+     * 
+     * @deprecated use {@link #setAccumulatedDeltaRangeUncertaintyMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
+     * 
      * @hide
      */
     @TestApi
+    @Deprecated
     public void setCarrierPhaseUncertainty(double value) {
         setFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
         mCarrierPhaseUncertainty = value;
@@ -820,9 +925,14 @@
 
     /**
      * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+     * 
+     * @deprecated use {@link #setAccumulatedDeltaRangeUncertaintyMeters(double)}
+     * and {@link #setAccumulatedDeltaRangeState(int)} instead.
+     * 
      * @hide
      */
     @TestApi
+    @Deprecated
     public void resetCarrierPhaseUncertainty() {
         resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
         mCarrierPhaseUncertainty = Double.NaN;
@@ -859,7 +969,7 @@
             case MULTIPATH_INDICATOR_NOT_DETECTED:
                 return "NotDetected";
             default:
-                return "<Invalid:" + mMultipathIndicator + ">";
+                return "<Invalid: " + mMultipathIndicator + ">";
         }
     }
 
@@ -916,11 +1026,12 @@
      * number. Hence in cases of strong jamming, in the band of this signal, this value will go more
      * negative.
      *
-     * <p>Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW
+     * <p> Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW
      * components) may also affect the typical output of of this value on any given hardware design
      * in an open sky test - the important aspect of this output is that changes in this value are
      * indicative of changes on input signal power in the frequency band for this measurement.
-     * <p>The value is only available if {@link #hasAutomaticGainControlLevelDb()} is {@code true}
+     *
+     * <p> The value is only available if {@link #hasAutomaticGainControlLevelDb()} is {@code true}
      */
     public double getAutomaticGainControlLevelDb() {
         return mAutomaticGainControlLevelInDb;
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
deleted file mode 100644
index e86ad1a..0000000
--- a/location/java/android/location/IFusedProvider.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.location;
-
-import android.hardware.location.IFusedLocationHardware;
-
-/**
- * Interface definition for Location providers that require FLP services.
- * @hide
- */
-oneway interface IFusedProvider {
-    /**
-     * Provides access to a FusedLocationHardware instance needed for the provider to work.
-     *
-     * @param instance      The FusedLocationHardware available for the provider to use.
-     */
-    void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
-}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2dd8c36..a523958 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -23,6 +23,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
@@ -42,12 +43,14 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import com.android.internal.location.ProviderProperties;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Set;
 
 /**
  * This class provides access to the system location services.  These
@@ -234,12 +237,6 @@
         "android.location.HIGH_POWER_REQUEST_CHANGE";
 
     /**
-     * The value returned by {@link LocationManager#getGnssHardwareModelName()} when the hardware
-     * does not support providing the actual value.
-     */
-    public static final String GNSS_HARDWARE_MODEL_NAME_UNKNOWN = "Model Name Unknown";
-
-    /**
      * Broadcast intent action for Settings app to inject a footer at the bottom of location
      * settings.
      *
@@ -1252,12 +1249,40 @@
     @SystemApi
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
-        for (String provider : getAllProviders()) {
+        final List<String> allProvidersList = getAllProviders();
+        // Update all providers on device plus gps and network provider when disabling location.
+        Set<String> allProvidersSet = new ArraySet<>(allProvidersList.size() + 2);
+        allProvidersSet.addAll(allProvidersList);
+        // When disabling location, disable gps and network provider that could have been enabled by
+        // location mode api.
+        if (enabled == false) {
+            allProvidersSet.add(GPS_PROVIDER);
+            allProvidersSet.add(NETWORK_PROVIDER);
+        }
+        if (allProvidersSet.isEmpty()) {
+            return;
+        }
+        // to ensure thread safety, we write the provider name with a '+' or '-'
+        // and let the SettingsProvider handle it rather than reading and modifying
+        // the list of enabled providers.
+        final String prefix = enabled ? "+" : "-";
+        StringBuilder locationProvidersAllowed = new StringBuilder();
+        for (String provider : allProvidersSet) {
+            checkProvider(provider);
             if (provider.equals(PASSIVE_PROVIDER)) {
                 continue;
             }
-            setProviderEnabledForUser(provider, enabled, userHandle);
+            locationProvidersAllowed.append(prefix);
+            locationProvidersAllowed.append(provider);
+            locationProvidersAllowed.append(",");
         }
+        // Remove the trailing comma
+        locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
+        Settings.Secure.putStringForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                locationProvidersAllowed.toString(),
+                userHandle.getIdentifier());
     }
 
     /**
@@ -2176,7 +2201,9 @@
     /**
      * Returns the model year of the GNSS hardware and software build.
      *
-     * May return 0 if the model year is less than 2016.
+     * <p> More details, such as build date, may be available in {@link #getGnssHardwareModelName()}.
+     *
+     * <p> May return 0 if the model year is less than 2016.
      */
     public int getGnssYearOfHardware() {
         try {
@@ -2190,10 +2217,12 @@
      * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware
      * driver.
      *
-     * Will return {@link LocationManager#GNSS_HARDWARE_MODEL_NAME_UNKNOWN} when the GNSS hardware
-     * abstraction layer does not support providing this value.
+     * <p> No device-specific serial number or ID is returned from this API.
+     *
+     * <p> Will return null when the GNSS hardware abstraction layer does not support providing
+     * this value.
      */
-    @NonNull
+    @Nullable
     public String getGnssHardwareModelName() {
         try {
             return mService.getGnssHardwareModelName();
diff --git a/location/lib/Android.mk b/location/lib/Android.mk
index 8424601..6642134 100644
--- a/location/lib/Android.mk
+++ b/location/lib/Android.mk
@@ -42,3 +42,25 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 
 include $(BUILD_PREBUILT)
+
+# ==== Stub library  ===========================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.location.provider-stubs-gen
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
+LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.location.provider.stubs_intermediates/src
+LOCAL_DROIDDOC_OPTIONS:= \
+    -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \
+    -stubpackages com.android.location.provider \
+    -nodocs
+LOCAL_UNINSTALLABLE_MODULE := true
+include $(BUILD_DROIDDOC)
+com_android_nfc_extras_gen_stamp := $(full_target)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.location.provider.stubs
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+LOCAL_SDK_VERSION := current
+LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_nfc_extras_gen_stamp)
+com_android_nfc_extras_gen_stamp :=
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/location/lib/java/com/android/location/provider/ActivityChangedEvent.java b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java
index c7dfc88..843dd67 100644
--- a/location/lib/java/com/android/location/provider/ActivityChangedEvent.java
+++ b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java
@@ -23,6 +23,7 @@
 
 /**
  * A class representing an event for Activity changes.
+ * @hide
  */
 public class ActivityChangedEvent {
     private final List<ActivityRecognitionEvent> mActivityRecognitionEvents;
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java
index a39cff2..e54dea4 100644
--- a/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java
@@ -18,6 +18,7 @@
 
 /**
  * A class that represents an Activity Recognition Event.
+ * @hide
  */
 public class ActivityRecognitionEvent {
     private final String mActivity;
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
index bc2dae1..0eff7d3 100644
--- a/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
@@ -28,6 +28,7 @@
 
 /**
  * A class that exposes {@link IActivityRecognitionHardware} functionality to unbundled services.
+ * @hide
  */
 public final class ActivityRecognitionProvider {
     private final IActivityRecognitionHardware mService;
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java
index 0b878d7..326d901 100644
--- a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderClient.java
@@ -27,6 +27,7 @@
 
 /**
  * A client class for interaction with an Activity-Recognition provider.
+ * @hide
  */
 public abstract class ActivityRecognitionProviderClient {
     private static final String TAG = "ArProviderClient";
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java
index 7139025..42f77b4 100644
--- a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java
@@ -30,6 +30,7 @@
  * A watcher class for Activity-Recognition instances.
  *
  * @deprecated use {@link ActivityRecognitionProviderClient} instead.
+ * @hide
  */
 @Deprecated
 public class ActivityRecognitionProviderWatcher {
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
deleted file mode 100644
index eb3b2f4..0000000
--- a/location/lib/java/com/android/location/provider/FusedLocationHardware.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.provider;
-
-import android.hardware.location.IFusedLocationHardware;
-import android.hardware.location.IFusedLocationHardwareSink;
-
-import android.location.Location;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Class that exposes IFusedLocationHardware functionality to unbundled services.
- */
-public final class FusedLocationHardware {
-    private static final String TAG = "FusedLocationHardware";
-
-    private IFusedLocationHardware mLocationHardware;
-
-    // the list uses a copy-on-write pattern to update its contents
-    HashMap<FusedLocationHardwareSink, DispatcherHandler> mSinkList =
-            new HashMap<FusedLocationHardwareSink, DispatcherHandler>();
-
-    private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
-        @Override
-        public void onLocationAvailable(Location[] locations) {
-            dispatchLocations(locations);
-        }
-
-        @Override
-        public void onDiagnosticDataAvailable(String data) {
-            dispatchDiagnosticData(data);
-        }
-
-        @Override
-        public void onCapabilities(int capabilities) {
-            dispatchCapabilities(capabilities);
-        }
-
-        @Override
-        public void onStatusChanged(int status) {
-            dispatchStatus(status);
-        }
-    };
-
-    /**
-     * @hide
-     */
-    public FusedLocationHardware(IFusedLocationHardware locationHardware) {
-        mLocationHardware = locationHardware;
-    }
-
-    /*
-     * Methods to provide a Facade for IFusedLocationHardware
-     */
-    public void registerSink(FusedLocationHardwareSink sink, Looper looper) {
-        if(sink == null || looper == null) {
-            throw new IllegalArgumentException("Parameter sink and looper cannot be null.");
-        }
-
-        boolean registerSink;
-        synchronized (mSinkList) {
-            // register only on first insertion
-            registerSink = mSinkList.size() == 0;
-            // guarantee uniqueness
-            if(mSinkList.containsKey(sink)) {
-                return;
-            }
-
-            HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
-                    new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
-            newSinkList.put(sink, new DispatcherHandler(looper));
-            mSinkList = newSinkList;
-        }
-
-        if(registerSink) {
-            try {
-                mLocationHardware.registerSink(mInternalSink);
-            } catch(RemoteException e) {
-                Log.e(TAG, "RemoteException at registerSink");
-            }
-        }
-    }
-
-    public void unregisterSink(FusedLocationHardwareSink sink) {
-        if(sink == null) {
-            throw new IllegalArgumentException("Parameter sink cannot be null.");
-        }
-
-        boolean unregisterSink;
-        synchronized(mSinkList) {
-            if(!mSinkList.containsKey(sink)) {
-                //done
-                return;
-            }
-
-            HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
-                    new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
-            newSinkList.remove(sink);
-            //unregister after the last sink
-            unregisterSink = newSinkList.size() == 0;
-
-            mSinkList = newSinkList;
-        }
-
-        if(unregisterSink) {
-            try {
-                mLocationHardware.unregisterSink(mInternalSink);
-            } catch(RemoteException e) {
-                Log.e(TAG, "RemoteException at unregisterSink");
-            }
-        }
-    }
-
-    public int getSupportedBatchSize() {
-        try {
-            return mLocationHardware.getSupportedBatchSize();
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at getSupportedBatchSize");
-            return 0;
-        }
-    }
-
-    public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
-        try {
-            mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at startBatching");
-        }
-    }
-
-    public void stopBatching(int id) {
-        try {
-            mLocationHardware.stopBatching(id);
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at stopBatching");
-        }
-    }
-
-    public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
-        try {
-            mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at updateBatchingOptions");
-        }
-    }
-
-    public void requestBatchOfLocations(int batchSizeRequest) {
-        try {
-            mLocationHardware.requestBatchOfLocations(batchSizeRequest);
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at requestBatchOfLocations");
-        }
-    }
-
-    public void flushBatchedLocations() {
-        try {
-            mLocationHardware.flushBatchedLocations();
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at flushBatchedLocations");
-        }
-    }
-
-    public boolean supportsDiagnosticDataInjection() {
-        try {
-            return mLocationHardware.supportsDiagnosticDataInjection();
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
-            return false;
-        }
-    }
-
-    public void injectDiagnosticData(String data) {
-        try {
-            mLocationHardware.injectDiagnosticData(data);
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at injectDiagnosticData");
-        }
-    }
-
-    public boolean supportsDeviceContextInjection() {
-        try {
-            return mLocationHardware.supportsDeviceContextInjection();
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
-            return false;
-        }
-    }
-
-    public void injectDeviceContext(int deviceEnabledContext) {
-        try {
-            mLocationHardware.injectDeviceContext(deviceEnabledContext);
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at injectDeviceContext");
-        }
-    }
-
-
-    /**
-     * Returns the version of the FLP HAL.
-     *
-     * <p>Version 1 is the initial release.
-     * <p>Version 2 adds the ability to use {@link #flushBatchedLocations},
-     * {@link FusedLocationHardwareSink#onCapabilities}, and
-     * {@link FusedLocationHardwareSink#onStatusChanged}.
-     *
-     * <p>This method is only available on API 23 or later.  Older APIs have version 1.
-     */
-    public int getVersion() {
-        try {
-            return mLocationHardware.getVersion();
-        } catch(RemoteException e) {
-            Log.e(TAG, "RemoteException at getVersion");
-        }
-        return 1;
-    }
-
-    /*
-     * Helper methods and classes
-     */
-    private class DispatcherHandler extends Handler {
-        public static final int DISPATCH_LOCATION = 1;
-        public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
-        public static final int DISPATCH_CAPABILITIES = 3;
-        public static final int DISPATCH_STATUS = 4;
-
-        public DispatcherHandler(Looper looper) {
-            super(looper, null /*callback*/ , true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message message) {
-            MessageCommand command = (MessageCommand) message.obj;
-            switch(message.what) {
-                case DISPATCH_LOCATION:
-                    command.dispatchLocation();
-                    break;
-                case DISPATCH_DIAGNOSTIC_DATA:
-                    command.dispatchDiagnosticData();
-                    break;
-                case DISPATCH_CAPABILITIES:
-                    command.dispatchCapabilities();
-                    break;
-                case DISPATCH_STATUS:
-                    command.dispatchStatus();
-                    break;
-                default:
-                    Log.e(TAG, "Invalid dispatch message");
-                    break;
-            }
-        }
-    }
-
-    private class MessageCommand {
-        private final FusedLocationHardwareSink mSink;
-        private final Location[] mLocations;
-        private final String mData;
-        private final int mCapabilities;
-        private final int mStatus;
-
-        public MessageCommand(
-                FusedLocationHardwareSink sink,
-                Location[] locations,
-                String data,
-                int capabilities,
-                int status) {
-            mSink = sink;
-            mLocations = locations;
-            mData = data;
-            mCapabilities = capabilities;
-            mStatus = status;
-        }
-
-        public void dispatchLocation() {
-            mSink.onLocationAvailable(mLocations);
-        }
-
-        public void dispatchDiagnosticData() {
-            mSink.onDiagnosticDataAvailable(mData);
-        }
-
-        public void dispatchCapabilities() {
-            mSink.onCapabilities(mCapabilities);
-        }
-
-        public void dispatchStatus() {
-            mSink.onStatusChanged(mStatus);
-        }
-    }
-
-    private void dispatchLocations(Location[] locations) {
-        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
-        synchronized (mSinkList) {
-            sinks = mSinkList;
-        }
-
-        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
-            Message message = Message.obtain(
-                    entry.getValue(),
-                    DispatcherHandler.DISPATCH_LOCATION,
-                    new MessageCommand(entry.getKey(), locations, null /*data*/, 0, 0));
-            message.sendToTarget();
-        }
-    }
-
-    private void dispatchDiagnosticData(String data) {
-        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
-        synchronized(mSinkList) {
-            sinks = mSinkList;
-        }
-
-        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
-            Message message = Message.obtain(
-                    entry.getValue(),
-                    DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
-                    new MessageCommand(entry.getKey(), null /*locations*/, data, 0, 0));
-            message.sendToTarget();
-        }
-    }
-
-    private void dispatchCapabilities(int capabilities) {
-        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
-        synchronized(mSinkList) {
-            sinks = mSinkList;
-        }
-
-        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
-            Message message = Message.obtain(
-                    entry.getValue(),
-                    DispatcherHandler.DISPATCH_CAPABILITIES,
-                    new MessageCommand(entry.getKey(), null /*locations*/, null, capabilities, 0));
-            message.sendToTarget();
-        }
-    }
-
-    private void dispatchStatus(int status) {
-        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
-        synchronized(mSinkList) {
-            sinks = mSinkList;
-        }
-
-        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
-            Message message = Message.obtain(
-                    entry.getValue(),
-                    DispatcherHandler.DISPATCH_STATUS,
-                    new MessageCommand(entry.getKey(), null /*locations*/, null, 0, status));
-            message.sendToTarget();
-        }
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
deleted file mode 100644
index 01d37ac..0000000
--- a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.provider;
-
-import android.location.Location;
-
-/**
- * Base class for sinks to interact with FusedLocationHardware.
- *
- * <p>Default implementations allow new methods to be added without crashing
- * clients compiled against an old library version.
- */
-public class FusedLocationHardwareSink {
-    /**
-     * Called when one or more locations are available from the FLP
-     * HAL.
-     */
-    public void onLocationAvailable(Location[] locations) {
-        // default do nothing
-    }
-
-    /**
-     * Called when diagnostic data is available from the FLP HAL.
-     */
-    public void onDiagnosticDataAvailable(String data) {
-        // default do nothing
-    }
-
-    /**
-     * Called when capabilities are available from the FLP HAL.
-     * Should be called once right after initialization.
-     *
-     * @param capabilities A bitmask of capabilities defined in
-     *                     fused_location.h.
-     */
-    public void onCapabilities(int capabilities) {
-        // default do nothing
-    }
-
-    /**
-     * Called when the status changes in the underlying FLP HAL
-     * implementation (the ability to compute location).  This
-     * callback will only be made on version 2 or later
-     * (see {@link FusedLocationHardware#getVersion()}).
-     *
-     * @param status One of FLP_STATUS_LOCATION_AVAILABLE or
-     *               FLP_STATUS_LOCATION_UNAVAILABLE as defined in
-     *               fused_location.h.
-     */
-    public void onStatusChanged(int status) {
-        // default do nothing
-    }
-}
\ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java
index c966ade..78a593b 100644
--- a/location/lib/java/com/android/location/provider/FusedProvider.java
+++ b/location/lib/java/com/android/location/provider/FusedProvider.java
@@ -16,8 +16,6 @@
 
 package com.android.location.provider;
 
-import android.hardware.location.IFusedLocationHardware;
-import android.location.IFusedProvider;
 import android.os.IBinder;
 
 /**
@@ -26,17 +24,12 @@
  * <p>Fused providers can be implemented as services and return the result of
  * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method.
  *
- * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
- * API stable. See README.txt in the root of this package for more information.
+ * @deprecated This class should no longer be used. The location service does not uses this.
+ * This class exist here just to prevent existing apps having reference to this class from
+ * breaking.
  */
+@Deprecated
 public abstract class FusedProvider {
-    private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {
-        @Override
-        public void onFusedLocationHardwareChange(IFusedLocationHardware instance) {
-            setFusedLocationHardware(new FusedLocationHardware(instance));
-        }
-    };
-
     /**
      * Gets the Binder associated with the provider.
      * This is intended to be used for the onBind() method of a service that implements a fused
@@ -45,13 +38,6 @@
      * @return The IBinder instance associated with the provider.
      */
     public IBinder getBinder() {
-        return mProvider;
+        return null;
     }
-
-    /**
-     * Sets the FusedLocationHardware instance in the provider..
-     * @param value     The instance to set. This can be null in cases where the service connection
-     *                  is disconnected.
-     */
-    public abstract void setFusedLocationHardware(FusedLocationHardware value);
 }
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
index d7a34af..f7f3d82 100644
--- a/location/lib/java/com/android/location/provider/GeocodeProvider.java
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -33,6 +33,7 @@
  * <p>IMPORTANT: This class is effectively a public API for unbundled
  * applications, and must remain API stable. See README.txt in the root
  * of this package for more information.
+ * @hide
  */
 public abstract class GeocodeProvider {
 
diff --git a/location/lib/java/com/android/location/provider/GeofenceProvider.java b/location/lib/java/com/android/location/provider/GeofenceProvider.java
index fafaa84..43690ab 100644
--- a/location/lib/java/com/android/location/provider/GeofenceProvider.java
+++ b/location/lib/java/com/android/location/provider/GeofenceProvider.java
@@ -31,6 +31,7 @@
  * <p>IMPORTANT: This class is effectively a public API for unbundled
  * applications, and must remain API stable. See README.txt in the root
  * of this package for more information.
+ * @hide
  */
 public abstract class GeofenceProvider {
 
diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
deleted file mode 100644
index 29818ec..0000000
--- a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.provider;
-
-import android.location.FusedBatchOptions;
-
-/**
- * Class that exposes FusedBatchOptions to the GmsCore .
- */
-public class GmsFusedBatchOptions {
-    private FusedBatchOptions mOptions = new FusedBatchOptions();
-
-    /*
-     * Methods that provide a facade for properties in FusedBatchOptions.
-     */
-    public void setMaxPowerAllocationInMW(double value) {
-        mOptions.setMaxPowerAllocationInMW(value);
-    }
-
-    public double getMaxPowerAllocationInMW() {
-        return mOptions.getMaxPowerAllocationInMW();
-    }
-
-    public void setPeriodInNS(long value) {
-        mOptions.setPeriodInNS(value);
-    }
-
-    public long getPeriodInNS() {
-        return mOptions.getPeriodInNS();
-    }
-
-    public void setSmallestDisplacementMeters(float value) {
-        mOptions.setSmallestDisplacementMeters(value);
-    }
-
-    public float getSmallestDisplacementMeters() {
-        return mOptions.getSmallestDisplacementMeters();
-    }
-
-    public void setSourceToUse(int source) {
-        mOptions.setSourceToUse(source);
-    }
-
-    public void resetSourceToUse(int source) {
-        mOptions.resetSourceToUse(source);
-    }
-
-    public boolean isSourceToUseSet(int source) {
-        return mOptions.isSourceToUseSet(source);
-    }
-
-    public int getSourcesToUse() {
-        return mOptions.getSourcesToUse();
-    }
-
-    public void setFlag(int flag) {
-        mOptions.setFlag(flag);
-    }
-
-    public void resetFlag(int flag) {
-        mOptions.resetFlag(flag);
-    }
-
-    public boolean isFlagSet(int flag) {
-        return mOptions.isFlagSet(flag);
-    }
-
-    public int getFlags() {
-        return mOptions.getFlags();
-    }
-
-    /**
-     * Definition of enum flag sets needed by this class.
-     * Such values need to be kept in sync with the ones in fused_location.h
-     */
-
-    public static final class SourceTechnologies {
-        public static int GNSS = 1<<0;
-        public static int WIFI = 1<<1;
-        public static int SENSORS = 1<<2;
-        public static int CELL = 1<<3;
-        public static int BLUETOOTH = 1<<4;
-    }
-
-    public static final class BatchFlags {
-        public static int WAKEUP_ON_FIFO_FULL = 1<<0;
-        public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
-    }
-
-    /*
-     * Method definitions for internal use.
-     */
-
-    /*
-     * @hide
-     */
-    public FusedBatchOptions getParcelableOptions() {
-        return mOptions;
-    }
-}
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index d717f40..30655f5 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -56,6 +56,7 @@
 public abstract class LocationProviderBase {
     private final String TAG;
 
+    /** @hide */
     protected final ILocationManager mLocationManager;
     private final ProviderProperties mProperties;
     private final IBinder mBinder;
diff --git a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
index 9ee4df21..b1a1bda 100644
--- a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
@@ -41,6 +41,7 @@
         mProperties = properties;
     }
 
+    /** @hide */
     public ProviderProperties getProviderProperties() {
         return mProperties;
     }
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index ad3d1df..6a8e618 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -33,6 +33,7 @@
 public final class ProviderRequestUnbundled {
     private final ProviderRequest mRequest;
 
+    /** @hide */
     public ProviderRequestUnbundled(ProviderRequest request) {
         mRequest = request;
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1536bb6..e408a11 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1352,6 +1352,7 @@
     //====================================================================
     // Offload query
     /**
+     * @hide
      * Returns whether offloaded playback of an audio format is supported on the device.
      * Offloaded playback is where the decoding of an audio stream is not competing with other
      * software resources. In general, it is supported by dedicated hardware, such as audio DSPs.
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 0a1de33..98c2d7f 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -42,6 +42,8 @@
 
     public abstract void setRingerModeInternal(int ringerMode, String caller);
 
+    public abstract void silenceRingerModeInternal(String caller);
+
     public abstract void updateRingerModeAffectedStreamsInternal();
 
     public abstract void setAccessibilityServiceUids(IntArray uids);
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index 4652c18..e39cb7d 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -17,6 +17,9 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -88,10 +91,14 @@
      */
     public static final int MASTERED_FOR_HEADPHONE          = 4;
 
-    AudioPresentation(int presentationId,
+    /**
+     * @hide
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public AudioPresentation(int presentationId,
                         int programId,
-                        Map<String, String> labels,
-                        String language,
+                        @NonNull Map<String, String> labels,
+                        @NonNull String language,
                         @MasteringIndicationType int masteringIndication,
                         boolean audioDescriptionAvailable,
                         boolean spokenSubtitlesAvailable,
@@ -112,6 +119,7 @@
      * decoder. Presentation id is typically sequential, but does not have to be.
      * @hide
      */
+    @VisibleForTesting
     public int getPresentationId() {
         return mPresentationId;
     }
@@ -121,13 +129,14 @@
      * Program id can be used to further uniquely identify the presentation to a decoder.
      * @hide
      */
+    @VisibleForTesting
     public int getProgramId() {
         return mProgramId;
     }
 
     /**
      * @return a map of available text labels for this presentation. Each label is indexed by its
-     * locale corresponding to the language code as specified by ISO 639-2 [42]. Either ISO 639-2/B
+     * locale corresponding to the language code as specified by ISO 639-2. Either ISO 639-2/B
      * or ISO 639-2/T could be used.
      */
     public Map<Locale, String> getLabels() {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3885f90..acab8bb 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -747,7 +747,8 @@
     public static final int FOR_SYSTEM = 4;
     public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
     public static final int FOR_ENCODED_SURROUND = 6;
-    private static final int NUM_FORCE_USE = 7;
+    public static final int FOR_VIBRATE_RINGING = 7;
+    private static final int NUM_FORCE_USE = 8;
 
     public static String forceUseUsageToString(int usage) {
         switch (usage) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 2d5fad5..87b5d43 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -896,6 +896,7 @@
         }
 
         /**
+         * @hide
          * Sets whether this track will play through the offloaded audio path.
          * When set to true, at build time, the audio format will be checked against
          * {@link AudioManager#isOffloadedPlaybackSupported(AudioFormat)} to verify the audio format
@@ -2012,9 +2013,10 @@
      * If the audio presentation is invalid then {@link #ERROR_BAD_VALUE} will be returned.
      * If a multi-stream decoder (MSD) is not present, or the format does not support
      * multiple presentations, then {@link #ERROR_INVALID_OPERATION} will be returned.
+     * {@link #ERROR} is returned in case of any other error.
      * @param presentation see {@link AudioPresentation}. In particular, id should be set.
-     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
-     *    {@link #ERROR_INVALID_OPERATION}
+     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR},
+     *    {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
      * @throws IllegalArgumentException if the audio presentation is null.
      * @throws IllegalStateException if track is not initialized.
      */
@@ -2978,6 +2980,7 @@
     }
 
     /**
+     * @hide
      * Abstract class to receive event notification about the stream playback.
      * See {@link AudioTrack#setStreamEventCallback(Executor, StreamEventCallback)} to register
      * the callback on the given {@link AudioTrack} instance.
@@ -3011,6 +3014,7 @@
     private final Object mStreamEventCbLock = new Object();
 
     /**
+     * @hide
      * Sets the callback for the notification of stream events.
      * @param executor {@link Executor} to handle the callbacks
      * @param eventCallback the callback to receive the stream event notifications
@@ -3030,6 +3034,7 @@
     }
 
     /**
+     * @hide
      * Unregisters the callback for notification of stream events, previously set
      * by {@link #setStreamEventCallback(Executor, StreamEventCallback)}.
      */
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 6d58a94..a53fa11 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -40,6 +40,7 @@
 import java.util.Map;
 
 /**
+ * @hide
  * Structure for data source descriptor.
  *
  * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}
diff --git a/media/java/android/media/Media2DataSource.java b/media/java/android/media/Media2DataSource.java
index 8ee4a70..08df632 100644
--- a/media/java/android/media/Media2DataSource.java
+++ b/media/java/android/media/Media2DataSource.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 
 /**
+ * @hide
  * For supplying media data to the framework. Implement this if your app has
  * special requirements for the way media data is obtained.
  *
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index cf33958..452371a 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -30,6 +30,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * Browses media content offered by a {@link MediaLibraryService2}.
  */
 public class MediaBrowser2 extends MediaController2 {
@@ -142,8 +143,8 @@
     @Override
     MediaBrowser2Provider createProvider(Context context, SessionToken2 token,
             Executor executor, ControllerCallback callback) {
-        return ApiLoader.getProvider(context)
-                .createMediaBrowser2(context, this, token, executor, (BrowserCallback) callback);
+        return ApiLoader.getProvider().createMediaBrowser2(
+                context, this, token, executor, (BrowserCallback) callback);
     }
 
     /**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index ba9056e..e3fba0c 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2359,17 +2359,61 @@
     public static final int CRYPTO_MODE_AES_CBC     = 2;
 
     /**
-     * Metadata describing the structure of a (at least partially) encrypted
-     * input sample.
-     * A buffer's data is considered to be partitioned into "subSamples",
-     * each subSample starts with a (potentially empty) run of plain,
-     * unencrypted bytes followed by a (also potentially empty) run of
-     * encrypted bytes. If pattern encryption applies, each of the latter runs
-     * is encrypted only partly, according to a repeating pattern of "encrypt"
-     * and "skip" blocks. numBytesOfClearData can be null to indicate that all
-     * data is encrypted. This information encapsulates per-sample metadata as
-     * outlined in ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base
-     * media file format files".
+     * Metadata describing the structure of an encrypted input sample.
+     * <p>
+     * A buffer's data is considered to be partitioned into "subSamples". Each subSample starts with
+     * a run of plain, unencrypted bytes followed by a run of encrypted bytes. Either of these runs
+     * may be empty. If pattern encryption applies, each of the encrypted runs is encrypted only
+     * partly, according to a repeating pattern of "encrypt" and "skip" blocks.
+     * {@link #numBytesOfClearData} can be null to indicate that all data is encrypted, and
+     * {@link #numBytesOfEncryptedData} can be null to indicate that all data is clear. At least one
+     * of {@link #numBytesOfClearData} and {@link #numBytesOfEncryptedData} must be non-null.
+     * <p>
+     * This information encapsulates per-sample metadata as outlined in ISO/IEC FDIS 23001-7:2016
+     * "Common encryption in ISO base media file format files".
+     * <p>
+     * <h3>ISO-CENC Schemes</h3>
+     * ISO/IEC FDIS 23001-7:2016 defines four possible schemes by which media may be encrypted,
+     * corresponding to each possible combination of an AES mode with the presence or absence of
+     * patterned encryption.
+     *
+     * <table style="width: 0%">
+     *   <thead>
+     *     <tr>
+     *       <th>&nbsp;</th>
+     *       <th>AES-CTR</th>
+     *       <th>AES-CBC</th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <th>Without Patterns</th>
+     *       <td>cenc</td>
+     *       <td>cbc1</td>
+     *     </tr><tr>
+     *       <th>With Patterns</th>
+     *       <td>cens</td>
+     *       <td>cbcs</td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     *
+     * For {@code CryptoInfo}, the scheme is selected implicitly by the combination of the
+     * {@link #mode} field and the value set with {@link #setPattern}. For the pattern, setting the
+     * pattern to all zeroes (that is, both {@code blocksToEncrypt} and {@code blocksToSkip} are
+     * zero) is interpreted as turning patterns off completely. A scheme that does not use patterns
+     * will be selected, either cenc or cbc1. Setting the pattern to any nonzero value will choose
+     * one of the pattern-supporting schemes, cens or cbcs. The default pattern if
+     * {@link #setPattern} is never called is all zeroes.
+     * <p>
+     * <h4>HLS SAMPLE-AES Audio</h4>
+     * HLS SAMPLE-AES audio is encrypted in a manner compatible with the cbcs scheme, except that it
+     * does not use patterned encryption. However, if {@link #setPattern} is used to set the pattern
+     * to all zeroes, this will be interpreted as selecting the cbc1 scheme. The cbc1 scheme cannot
+     * successfully decrypt HLS SAMPLE-AES audio because of differences in how the IVs are handled.
+     * For this reason, it is recommended that a pattern of {@code 1} encrypted block and {@code 0}
+     * skip blocks be used with HLS SAMPLE-AES audio. This will trigger decryption to use cbcs mode
+     * while still decrypting every block.
      */
     public final static class CryptoInfo {
         /**
@@ -2377,11 +2421,13 @@
          */
         public int numSubSamples;
         /**
-         * The number of leading unencrypted bytes in each subSample.
+         * The number of leading unencrypted bytes in each subSample. If null, all bytes are treated
+         * as encrypted and {@link #numBytesOfEncryptedData} must be specified.
          */
         public int[] numBytesOfClearData;
         /**
-         * The number of trailing encrypted bytes in each subSample.
+         * The number of trailing encrypted bytes in each subSample. If null, all bytes are treated
+         * as clear and {@link #numBytesOfClearData} must be specified.
          */
         public int[] numBytesOfEncryptedData;
         /**
@@ -2400,35 +2446,34 @@
         public int mode;
 
         /**
-         * Metadata describing an encryption pattern for the protected bytes in
-         * a subsample.  An encryption pattern consists of a repeating sequence
-         * of crypto blocks comprised of a number of encrypted blocks followed
-         * by a number of unencrypted, or skipped, blocks.
+         * Metadata describing an encryption pattern for the protected bytes in a subsample.  An
+         * encryption pattern consists of a repeating sequence of crypto blocks comprised of a
+         * number of encrypted blocks followed by a number of unencrypted, or skipped, blocks.
          */
         public final static class Pattern {
             /**
-             * Number of blocks to be encrypted in the pattern. If zero, pattern
-             * encryption is inoperative.
+             * Number of blocks to be encrypted in the pattern. If both this and
+             * {@link #mSkipBlocks} are zero, pattern encryption is inoperative.
              */
             private int mEncryptBlocks;
 
             /**
-             * Number of blocks to be skipped (left clear) in the pattern. If zero,
-             * pattern encryption is inoperative.
+             * Number of blocks to be skipped (left clear) in the pattern. If both this and
+             * {@link #mEncryptBlocks} are zero, pattern encryption is inoperative.
              */
             private int mSkipBlocks;
 
             /**
-             * Construct a sample encryption pattern given the number of blocks to
-             * encrypt and skip in the pattern.
+             * Construct a sample encryption pattern given the number of blocks to encrypt and skip
+             * in the pattern. If both parameters are zero, pattern encryption is inoperative.
              */
             public Pattern(int blocksToEncrypt, int blocksToSkip) {
                 set(blocksToEncrypt, blocksToSkip);
             }
 
             /**
-             * Set the number of blocks to encrypt and skip in a sample encryption
-             * pattern.
+             * Set the number of blocks to encrypt and skip in a sample encryption pattern. If both
+             * parameters are zero, pattern encryption is inoperative.
              */
             public void set(int blocksToEncrypt, int blocksToSkip) {
                 mEncryptBlocks = blocksToEncrypt;
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 20c3209..234a4f4 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -40,6 +40,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * Allows an app to interact with an active {@link MediaSession2} or a
  * {@link MediaSessionService2} in any status. Media buttons and other commands can be sent to
  * the session.
@@ -366,8 +367,8 @@
     MediaController2Provider createProvider(@NonNull Context context,
             @NonNull SessionToken2 token, @NonNull Executor executor,
             @NonNull ControllerCallback callback) {
-        return ApiLoader.getProvider(context)
-                .createMediaController2(context, this, token, executor, callback);
+        return ApiLoader.getProvider().createMediaController2(
+                context, this, token, executor, callback);
     }
 
     /**
@@ -735,8 +736,10 @@
         return mProvider.getPlaylistMetadata_impl();
     }
 
+
     /**
-     * Inserts the media item to the playlist at position index.
+     * Adds the media item to the playlist at position index. Index equals or greater than
+     * the current playlist size will add the item at the end of the playlist.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the playlist,
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index b50c3e4..1967a1c 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -28,6 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
+ * @hide
  * A class with information on a single media item with the metadata information.
  * Media item are application dependent so we cannot guarantee that they contain the right values.
  * <p>
@@ -81,7 +82,7 @@
     }
 
     public static MediaItem2 fromBundle(Context context, Bundle bundle) {
-        return ApiLoader.getProvider(context).fromBundle_MediaItem2(context, bundle);
+        return ApiLoader.getProvider().fromBundle_MediaItem2(context, bundle);
     }
 
     public String toString() {
@@ -164,8 +165,7 @@
          * @param flags
          */
         public Builder(@NonNull Context context, @Flags int flags) {
-            mProvider = ApiLoader.getProvider(context).createMediaItem2Builder(
-                    context, this, flags);
+            mProvider = ApiLoader.getProvider().createMediaItem2Builder(context, this, flags);
         }
 
         /**
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 6cab430..034d17e 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -34,6 +34,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * Base class for media library services.
  * <p>
  * Media library services enable applications to browse media content provided by an application
@@ -210,9 +211,8 @@
             public Builder(@NonNull MediaLibraryService2 service,
                     @NonNull @CallbackExecutor Executor callbackExecutor,
                     @NonNull MediaLibrarySessionCallback callback) {
-                super((instance) -> ApiLoader.getProvider(service)
-                        .createMediaLibraryService2Builder(service, (Builder) instance,
-                                callbackExecutor, callback));
+                super((instance) -> ApiLoader.getProvider().createMediaLibraryService2Builder(
+                        service, (Builder) instance, callbackExecutor, callback));
             }
 
             @Override
@@ -309,7 +309,7 @@
 
     @Override
     MediaSessionService2Provider createProvider() {
-        return ApiLoader.getProvider(this).createMediaLibraryService2(this);
+        return ApiLoader.getProvider().createMediaLibraryService2(this);
     }
 
     /**
@@ -403,7 +403,7 @@
          */
         public LibraryRoot(@NonNull Context context,
                 @NonNull String rootId, @Nullable Bundle extras) {
-            mProvider = ApiLoader.getProvider(context).createMediaLibraryService2LibraryRoot(
+            mProvider = ApiLoader.getProvider().createMediaLibraryService2LibraryRoot(
                     context, this, rootId, extras);
         }
 
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index fb12065..1a15962 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -31,6 +31,7 @@
 import java.util.Set;
 
 /**
+ * @hide
  * Contains metadata about an item, such as the title, artist, etc.
  */
 // New version of MediaMetadata with following changes
@@ -684,7 +685,7 @@
      */
     public static @NonNull MediaMetadata2 fromBundle(@NonNull Context context,
             @Nullable Bundle bundle) {
-        return ApiLoader.getProvider(context).fromBundle_MediaMetadata2(context, bundle);
+        return ApiLoader.getProvider().fromBundle_MediaMetadata2(context, bundle);
     }
 
     /**
@@ -699,8 +700,7 @@
          * {@link MediaMetadata2} must be added.
          */
         public Builder(@NonNull Context context) {
-            mProvider = ApiLoader.getProvider(context).createMediaMetadata2Builder(
-                    context, this);
+            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(context, this);
         }
 
         /**
@@ -711,8 +711,7 @@
          * @param source
          */
         public Builder(@NonNull Context context, @NonNull MediaMetadata2 source) {
-            mProvider = ApiLoader.getProvider(context).createMediaMetadata2Builder(
-                    context, this, source);
+            mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(context, this, source);
         }
 
         /**
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index ece19b9..dcc872c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -43,6 +43,7 @@
 
 
 /**
+ * @hide
  * MediaPlayer2 class can be used to control playback
  * of audio/video files and streams. An example on how to use the methods in
  * this class can be found in {@link android.widget.VideoView}.
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index 48b7a51..1fcf02b 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -26,6 +26,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * Base class for all media players that want media session.
  */
 public abstract class MediaPlayerBase implements AutoCloseable {
@@ -306,8 +307,9 @@
     public static abstract class PlayerEventCallback {
         /**
          * Called when the player's current data source has changed.
+         *
          * @param mpb the player whose data source changed.
-         * @param dsd the new current data source.
+         * @param dsd the new current data source. null, if no more data sources available.
          */
         public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb,
                 @Nullable DataSourceDesc dsd) { }
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
index 6b3620b..453e24a 100644
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ b/media/java/android/media/MediaPlaylistAgent.java
@@ -30,6 +30,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * MediaPlaylistAgent is the abstract class an application needs to derive from to pass an object
  * to a MediaSession2 that will override default playlist handling behaviors. It contains a set of
  * notify methods to signal MediaSession2 that playlist-related state has changed.
@@ -148,7 +149,7 @@
     }
 
     public MediaPlaylistAgent(@NonNull Context context) {
-        mProvider = ApiLoader.getProvider(context).createMediaPlaylistAgent(context, this);
+        mProvider = ApiLoader.getProvider().createMediaPlaylistAgent(context, this);
     }
 
     /**
@@ -228,10 +229,15 @@
     }
 
     /**
-     * Adds the media item to the playlist at the index
+     * Adds the media item to the playlist at position index. Index equals or greater than
+     * the current playlist size will add the item at the end of the playlist.
+     * <p>
+     * This will not change the currently playing media item.
+     * If index is less than or equal to the current index of the playlist,
+     * the current index of the playlist will be incremented correspondingly.
      *
-     * @param index index
-     * @param item media item to add
+     * @param index the index you want to add
+     * @param item the media item you want to add
      */
     public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
         mProvider.addPlaylistItem_impl(index, item);
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 6647831..0f4b5da 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -49,6 +49,7 @@
 import java.util.concurrent.Executor;
 
 /**
+ * @hide
  * Allows a media app to expose its transport controls and playback information in a process to
  * other processes including the Android framework and other apps. Common use cases are as follows.
  * <ul>
@@ -431,16 +432,16 @@
         private final CommandProvider mProvider;
 
         public Command(@NonNull Context context, int commandCode) {
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSession2Command(this, commandCode, null, null);
+            mProvider = ApiLoader.getProvider().createMediaSession2Command(
+                    this, commandCode, null, null);
         }
 
         public Command(@NonNull Context context, @NonNull String action, @Nullable Bundle extras) {
             if (action == null) {
                 throw new IllegalArgumentException("action shouldn't be null");
             }
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSession2Command(this, COMMAND_CODE_CUSTOM, action, extras);
+            mProvider = ApiLoader.getProvider().createMediaSession2Command(
+                    this, COMMAND_CODE_CUSTOM, action, extras);
         }
 
         /**
@@ -488,7 +489,7 @@
          * @hide
          */
         public static Command fromBundle(@NonNull Context context, @NonNull Bundle command) {
-            return ApiLoader.getProvider(context).fromBundle_MediaSession2Command(context, command);
+            return ApiLoader.getProvider().fromBundle_MediaSession2Command(context, command);
         }
     }
 
@@ -499,13 +500,13 @@
         private final CommandGroupProvider mProvider;
 
         public CommandGroup(@NonNull Context context) {
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSession2CommandGroup(context, this, null);
+            mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(
+                    context, this, null);
         }
 
         public CommandGroup(@NonNull Context context, @Nullable CommandGroup others) {
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSession2CommandGroup(context, this, others);
+            mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(
+                    context, this, others);
         }
 
         /**
@@ -559,8 +560,7 @@
          * @hide
          */
         public static @Nullable CommandGroup fromBundle(Context context, Bundle commands) {
-            return ApiLoader.getProvider(context)
-                    .fromBundle_MediaSession2CommandGroup(context, commands);
+            return ApiLoader.getProvider().fromBundle_MediaSession2CommandGroup(context, commands);
         }
     }
 
@@ -1010,7 +1010,7 @@
     // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
     public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> {
         public Builder(Context context) {
-            super((instance) -> ApiLoader.getProvider(context).createMediaSession2Builder(
+            super((instance) -> ApiLoader.getProvider().createMediaSession2Builder(
                     context, (Builder) instance));
         }
 
@@ -1062,9 +1062,8 @@
          */
         public ControllerInfo(@NonNull Context context, int uid, int pid,
                 @NonNull String packageName, @NonNull IInterface callback) {
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSession2ControllerInfo(
-                            context, this, uid, pid, packageName, callback);
+            mProvider = ApiLoader.getProvider().createMediaSession2ControllerInfo(
+                    context, this, uid, pid, packageName, callback);
         }
 
         /**
@@ -1192,8 +1191,8 @@
             private final CommandButtonProvider.BuilderProvider mProvider;
 
             public Builder(@NonNull Context context) {
-                mProvider = ApiLoader.getProvider(context)
-                        .createMediaSession2CommandButtonBuilder(context, this);
+                mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(
+                        context, this);
             }
 
             public @NonNull Builder setCommand(@Nullable Command command) {
@@ -1543,7 +1542,7 @@
      * @see #COMMAND_CODE_PLAYLIST_REPLACE_ITEM
      */
     public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) {
-        // TODO(jaewan): Implement (b/74090741).
+        mProvider.setOnDataSourceMissingHelper_impl(helper);
     }
 
     /**
@@ -1552,7 +1551,7 @@
      * @see #setOnDataSourceMissingHelper(OnDataSourceMissingHelper)
      */
     public void clearOnDataSourceMissingHelper() {
-        // TODO(jaewan): Implement (b/74090741)
+        mProvider.clearOnDataSourceMissingHelper_impl();
     }
 
     /**
@@ -1648,7 +1647,8 @@
     }
 
     /**
-     * Adds the media item to the playlist at position index.
+     * Adds the media item to the playlist at position index. Index equals or greater than
+     * the current playlist size will add the item at the end of the playlist.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the play list,
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 32caf4b..85ac9b2 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 
 /**
+ * @hide
  * Base class for media session services, which is the service version of the {@link MediaSession2}.
  * <p>
  * It's highly recommended for an app to use this instead of {@link MediaSession2} if it wants
@@ -123,7 +124,7 @@
     }
 
     MediaSessionService2Provider createProvider() {
-        return ApiLoader.getProvider(this).createMediaSessionService2(this);
+        return ApiLoader.getProvider().createMediaSessionService2(this);
     }
 
     /**
@@ -220,9 +221,8 @@
          */
         public MediaNotification(@NonNull Context context,
                 int notificationId, @NonNull Notification notification) {
-            mProvider = ApiLoader.getProvider(context)
-                    .createMediaSessionService2MediaNotification(
-                            context, this, notificationId, notification);
+            mProvider = ApiLoader.getProvider().createMediaSessionService2MediaNotification(
+                    context, this, notificationId, notification);
         }
 
         public int getNotificationId() {
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index 29bd922..5f7a334 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -131,7 +131,7 @@
      * @return new Rating2 instance or {@code null} for error
      */
     public static Rating2 fromBundle(@NonNull Context context, @Nullable Bundle bundle) {
-        return ApiLoader.getProvider(context).fromBundle_Rating2(context, bundle);
+        return ApiLoader.getProvider().fromBundle_Rating2(context, bundle);
     }
 
     /**
@@ -154,7 +154,7 @@
      */
     public static @Nullable Rating2 newUnratedRating(@NonNull Context context,
             @Style int ratingStyle) {
-        return ApiLoader.getProvider(context).newUnratedRating_Rating2(context, ratingStyle);
+        return ApiLoader.getProvider().newUnratedRating_Rating2(context, ratingStyle);
     }
 
     /**
@@ -166,7 +166,7 @@
      * @return a new Rating2 instance.
      */
     public static @Nullable Rating2 newHeartRating(@NonNull Context context, boolean hasHeart) {
-        return ApiLoader.getProvider(context).newHeartRating_Rating2(context, hasHeart);
+        return ApiLoader.getProvider().newHeartRating_Rating2(context, hasHeart);
     }
 
     /**
@@ -178,7 +178,7 @@
      * @return a new Rating2 instance.
      */
     public static @Nullable Rating2 newThumbRating(@NonNull Context context, boolean thumbIsUp) {
-        return ApiLoader.getProvider(context).newThumbRating_Rating2(context, thumbIsUp);
+        return ApiLoader.getProvider().newThumbRating_Rating2(context, thumbIsUp);
     }
 
     /**
@@ -196,8 +196,7 @@
      */
     public static @Nullable Rating2 newStarRating(@NonNull Context context,
             @StarStyle int starRatingStyle, float starRating) {
-        return ApiLoader.getProvider(context).newStarRating_Rating2(
-                context, starRatingStyle, starRating);
+        return ApiLoader.getProvider().newStarRating_Rating2(context, starRatingStyle, starRating);
     }
 
     /**
@@ -209,7 +208,7 @@
      * @return null if the rating is out of range, a new Rating2 instance otherwise.
      */
     public static @Nullable Rating2 newPercentageRating(@NonNull Context context, float percent) {
-        return ApiLoader.getProvider(context).newPercentageRating_Rating2(context, percent);
+        return ApiLoader.getProvider().newPercentageRating_Rating2(context, percent);
     }
 
     /**
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
index fdfa43a..f088be3 100644
--- a/media/java/android/media/SessionToken2.java
+++ b/media/java/android/media/SessionToken2.java
@@ -28,6 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
+ * @hide
  * Represents an ongoing {@link MediaSession2} or a {@link MediaSessionService2}.
  * If it's representing a session service, it may not be ongoing.
  * <p>
@@ -80,7 +81,7 @@
      */
     public SessionToken2(@NonNull Context context, @NonNull String packageName,
             @NonNull String serviceName, int uid) {
-        mProvider = ApiLoader.getProvider(context).createSessionToken2(
+        mProvider = ApiLoader.getProvider().createSessionToken2(
                 context, this, packageName, serviceName, uid);
     }
 
@@ -150,7 +151,7 @@
      * @return
      */
     public static SessionToken2 fromBundle(@NonNull Context context, @NonNull Bundle bundle) {
-        return ApiLoader.getProvider(context).fromBundle_SessionToken2(context, bundle);
+        return ApiLoader.getProvider().fromBundle_SessionToken2(context, bundle);
     }
 
     /**
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
index 711f51f..2d96d096 100644
--- a/media/java/android/media/VolumeProvider2.java
+++ b/media/java/android/media/VolumeProvider2.java
@@ -26,6 +26,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
+ * @hide
  * Handles requests to adjust or set the volume on a session. This is also used
  * to push volume updates back to the session. The provider must call
  * {@link #setCurrentVolume(int)} each time the volume being provided changes.
@@ -76,7 +77,7 @@
      */
     public VolumeProvider2(@NonNull Context context, @ControlType int controlType,
             int maxVolume, int currentVolume) {
-        mProvider = ApiLoader.getProvider(context).createVolumeProvider2(
+        mProvider = ApiLoader.getProvider().createVolumeProvider2(
                 context, this, controlType, maxVolume, currentVolume);
     }
 
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 963457b..56664a9 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -52,12 +52,13 @@
     void setOnMediaKeyListener(in IOnMediaKeyListener listener);
 
     // MediaSession2
-    boolean isTrusted(int uid, String packageName);
+    boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
     boolean createSession2(in Bundle sessionToken);
     void destroySession2(in Bundle sessionToken);
-    List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly);
+    List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly,
+            String packageName);
 
     void addSessionTokensListener(in ISessionTokensListener listener, int userId,
             String packageName);
-    void removeSessionTokensListener(in ISessionTokensListener listener);
+    void removeSessionTokensListener(in ISessionTokensListener listener, String packageName);
 }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 051321c..b7f4998 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -342,16 +342,17 @@
     /**
      * Returns whether the api
      *
-     * @param uid uid of the app
      * @param packageName packageName
+     * @param pid pid of the app
+     * @param uid uid of the app
      * @hide
      */
-    public boolean isTrusted(int uid, @NonNull String packageName) {
+    public boolean isTrusted(@NonNull String packageName, int pid, int uid) {
         if (packageName == null) {
             return false;
         }
         try {
-            return mService.isTrusted(uid, packageName);
+            return mService.isTrusted(packageName, pid, uid);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
         }
@@ -390,6 +391,7 @@
     }
 
     /**
+     * @hide
      * Get {@link List} of {@link SessionToken2} whose sessions are active now. This list represents
      * active sessions regardless of whether they're {@link MediaSession2} or
      * {@link MediaSessionService2}.
@@ -403,7 +405,8 @@
     public List<SessionToken2> getActiveSessionTokens() {
         try {
             List<Bundle> bundles = mService.getSessionTokens(
-                    /* activeSessionOnly */ true, /* sessionServiceOnly */ false);
+                    /* activeSessionOnly */ true, /* sessionServiceOnly */ false,
+                    mContext.getPackageName());
             return toTokenList(mContext, bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
@@ -412,6 +415,7 @@
     }
 
     /**
+     * @hide
      * Get {@link List} of {@link SessionToken2} for {@link MediaSessionService2} regardless of their
      * activeness. This list represents media apps that support background playback.
      * <p>
@@ -424,7 +428,8 @@
     public List<SessionToken2> getSessionServiceTokens() {
         try {
             List<Bundle> bundles = mService.getSessionTokens(
-                    /* activeSessionOnly */ false, /* sessionServiceOnly */ true);
+                    /* activeSessionOnly */ false, /* sessionServiceOnly */ true,
+                    mContext.getPackageName());
             return toTokenList(mContext, bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
@@ -433,6 +438,7 @@
     }
 
     /**
+     * @hide
      * Get all {@link SessionToken2}s. This is the combined list of {@link #getActiveSessionTokens()}
      * and {@link #getSessionServiceTokens}.
      * <p>
@@ -447,7 +453,8 @@
     public List<SessionToken2> getAllSessionTokens() {
         try {
             List<Bundle> bundles = mService.getSessionTokens(
-                    /* activeSessionOnly */ false, /* sessionServiceOnly */ false);
+                    /* activeSessionOnly */ false, /* sessionServiceOnly */ false,
+                    mContext.getPackageName());
             return toTokenList(mContext, bundles);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
@@ -456,6 +463,7 @@
     }
 
     /**
+     * @hide
      * Add a listener to be notified when the {@link #getAllSessionTokens()} changes.
      * <p>
      * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the
@@ -508,6 +516,7 @@
     }
 
     /**
+     * @hide
      * Stop receiving session token updates on the specified listener.
      *
      * @param listener The listener to remove.
@@ -521,7 +530,7 @@
             SessionTokensChangedWrapper wrapper = mSessionTokensListener.remove(listener);
             if (wrapper != null) {
                 try {
-                    mService.removeSessionTokensListener(wrapper.mStub);
+                    mService.removeSessionTokensListener(wrapper.mStub, mContext.getPackageName());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error in removeSessionTokensListener.", e);
                 } finally {
@@ -666,6 +675,7 @@
     }
 
     /**
+     * @hide
      * Listens for changes to the {@link #getAllSessionTokens()}. This can be added
      * using {@link #addOnActiveSessionsChangedListener}.
      */
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index cf18bdd..6f82f68 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -46,11 +46,6 @@
 
     private ApiLoader() { }
 
-    @Deprecated
-    public static StaticProvider getProvider(Context context) {
-        return getProvider();
-    }
-
     public static StaticProvider getProvider() {
         if (sMediaUpdatable != null) return sMediaUpdatable;
 
@@ -79,7 +74,7 @@
             ActivityManager.getService().addPackageDependency(ai.packageName);
         }
 
-        PathClassLoader classLoader = new PathClassLoader(ai.sourceDir,
+        ClassLoader classLoader = new PathClassLoader(ai.sourceDir,
                 ai.nativeLibraryDir + File.pathSeparator + System.getProperty("java.library.path"),
                 ClassLoader.getSystemClassLoader().getParent());
         return sMediaUpdatable = (StaticProvider) classLoader.loadClass(UPDATE_CLASS)
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index e5ea386..0faed9d 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -21,7 +21,6 @@
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
 import android.media.MediaPlayerBase;
-import android.media.MediaPlayerBase.PlayerEventCallback;
 import android.media.MediaPlaylistAgent;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
@@ -29,6 +28,7 @@
 import android.media.MediaSession2.CommandButton.Builder;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
 import android.media.MediaSession2.SessionCallback;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
@@ -68,6 +68,8 @@
     int getPlayerState_impl();
     long getPosition_impl();
     long getBufferedPosition_impl();
+    void setOnDataSourceMissingHelper_impl(OnDataSourceMissingHelper helper);
+    void clearOnDataSourceMissingHelper_impl();
 
     interface CommandProvider {
         int getCommandCode_impl();
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 23ef84f6..12d7440 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -39,6 +39,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 #include <jni.h>
+#include <media/stagefright/NuMediaExtractor.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
 
@@ -788,6 +789,41 @@
     return exif_get_long(e->data, o);
 }
 
+static ExifData *getExifFromExtractor(const char *path) {
+    std::unique_ptr<uint8_t[]> exifBuf;
+    ExifData *exifdata = NULL;
+
+    FILE *fp = fopen (path, "rb");
+    if (!fp) {
+        ALOGE("failed to open file");
+        return NULL;
+    }
+
+    sp<NuMediaExtractor> extractor = new NuMediaExtractor();
+    fseek(fp, 0L, SEEK_END);
+    if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
+        ALOGE("failed to setDataSource");
+        fclose(fp);
+        return NULL;
+    }
+
+    off64_t offset;
+    size_t size;
+    if (extractor->getExifOffsetSize(&offset, &size) != OK) {
+        fclose(fp);
+        return NULL;
+    }
+
+    exifBuf.reset(new uint8_t[size]);
+    fseek(fp, offset, SEEK_SET);
+    if (fread(exifBuf.get(), 1, size, fp) == size) {
+        exifdata = exif_data_new_from_data(exifBuf.get(), size);
+    }
+
+    fclose(fp);
+    return exifdata;
+}
+
 MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
                                              MtpObjectInfo& info) {
     MtpString       path;
@@ -834,7 +870,12 @@
         case MTP_FORMAT_EXIF_JPEG:
         case MTP_FORMAT_HEIF:
         case MTP_FORMAT_JFIF: {
-            ExifData *exifdata = exif_data_new_from_file(path);
+            ExifData *exifdata;
+            if (info.mFormat == MTP_FORMAT_HEIF) {
+                exifdata = getExifFromExtractor(path);
+            } else {
+                exifdata = exif_data_new_from_file(path);
+            }
             if (exifdata) {
                 if ((false)) {
                     exif_data_foreach_content(exifdata, foreachcontent, NULL);
@@ -892,7 +933,12 @@
             case MTP_FORMAT_EXIF_JPEG:
             case MTP_FORMAT_HEIF:
             case MTP_FORMAT_JFIF: {
-                ExifData *exifdata = exif_data_new_from_file(path);
+                ExifData *exifdata;
+                if (format == MTP_FORMAT_HEIF) {
+                    exifdata = getExifFromExtractor(path);
+                } else {
+                    exifdata = exif_data_new_from_file(path);
+                }
                 if (exifdata) {
                     if (exifdata->data) {
                         result = malloc(exifdata->size);
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 589608a..1a9ce95 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -150,6 +150,13 @@
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
 
+    <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_no_battery_level">Active</string>
+
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
     <string name="bluetooth_profile_a2dp">Media audio</string>
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the headset or handsfree profile. -->
@@ -1093,4 +1100,7 @@
     <string name="zen_mode_duration_settings_title">Duration</string>
     <!-- Do not disturb: Duration option to always prompt for the duration of dnd -->
     <string name="zen_mode_duration_always_prompt_title">Ask every time</string>
+
+    <!-- time label for event have that happened very recently [CHAR LIMIT=60] -->
+    <string name="time_unit_just_now">Just now</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
index 3c02f6a..2d3dfe4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
@@ -59,7 +59,8 @@
 
     @Override
     public boolean isAvailable() {
-        return mContext.getSystemService(UserManager.class).isAdminUser();
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        return um != null && (um.isAdminUser() || um.isDemoUser());
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
index 85bf4e8..d21da4e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
@@ -45,8 +45,7 @@
                 Build.TYPE.equals("eng") ? 1 : 0) != 0;
         final boolean hasRestriction = um.hasUserRestriction(
                 UserManager.DISALLOW_DEBUGGING_FEATURES);
-        final boolean isAdmin = um.isAdminUser();
-
-        return isAdmin && !hasRestriction && settingEnabled;
+        final boolean isAdminOrDemo = um.isAdminUser() || um.isDemoUser();
+        return isAdminOrDemo && !hasRestriction && settingEnabled;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
new file mode 100644
index 0000000..e2c7747
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.fuelgauge;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Settings.Secure;
+import android.util.Log;
+
+/**
+ * Utilities related to battery saver.
+ */
+public class BatterySaverUtils {
+    private static final String TAG = "BatterySaverUtils";
+
+    private BatterySaverUtils() {
+    }
+
+    private static final boolean DEBUG = false;
+
+    // Broadcast action for SystemUI to show the battery saver confirmation dialog.
+    public static final String ACTION_SHOW_START_SAVER_CONFIRMATION = "PNW.startSaverConfirmation";
+
+    /**
+     * Enable / disable battery saver by user request.
+     * - If it's the first time and needFirstTimeWarning, show the first time dialog.
+     * - If it's 4th time through 8th time, show the schedule suggestion notification.
+     *
+     * @param enable true to disable battery saver.
+     *
+     * @return true if the request succeeded.
+     */
+    public static synchronized boolean setPowerSaveMode(Context context,
+            boolean enable, boolean needFirstTimeWarning) {
+        if (DEBUG) {
+            Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF"));
+        }
+        final ContentResolver cr = context.getContentResolver();
+
+        if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context)) {
+            return false;
+        }
+        if (enable && !needFirstTimeWarning) {
+            setBatterySaverConfirmationAcknowledged(context);
+        }
+
+        if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) {
+            if (enable) {
+                Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
+                        Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1);
+
+                // TODO If enabling, and the count is between 4 and 8 (inclusive), then
+                // show the "battery saver schedule suggestion" notification.
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean maybeShowBatterySaverConfirmation(Context context) {
+        if (Secure.getInt(context.getContentResolver(),
+                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
+            return false; // Already shown.
+        }
+        final Intent i = new Intent(ACTION_SHOW_START_SAVER_CONFIRMATION);
+        context.sendBroadcast(i);
+
+        return true;
+    }
+
+    private static void setBatterySaverConfirmationAcknowledged(Context context) {
+        Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
new file mode 100644
index 0000000..cc69e0e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.users;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.internal.util.UserIcons;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Helper class for managing users, providing methods for removing, adding and switching users.
+ */
+public final class UserManagerHelper {
+    private static final String TAG = "UserManagerHelper";
+    private final Context mContext;
+    private final UserManager mUserManager;
+    private OnUsersUpdateListener mUpdateListener;
+    private final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mUpdateListener.onUsersUpdate();
+        }
+    };
+
+    public UserManagerHelper(Context context) {
+        mContext = context;
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+    }
+
+    /**
+     * Registers a listener for updates to all users - removing, adding users or changing user info.
+     *
+     * @param listener Instance of {@link OnUsersUpdateListener}.
+     */
+    public void registerOnUsersUpdateListener(OnUsersUpdateListener listener) {
+        mUpdateListener = listener;
+        registerReceiver();
+    }
+
+    /**
+     * Unregisters listener by unregistering {@code BroadcastReceiver}.
+     */
+    public void unregisterOnUsersUpdateListener() {
+        unregisterReceiver();
+    }
+
+    /**
+     * Gets {@link UserInfo} for the current user.
+     *
+     * @return {@link UserInfo} for the current user.
+     */
+    public UserInfo getCurrentUserInfo() {
+        return mUserManager.getUserInfo(UserHandle.myUserId());
+    }
+
+    /**
+     * Gets all the other users on the system that are not the current user.
+     *
+     * @return List of {@code UserInfo} for each user that is not the current user.
+     */
+    public List<UserInfo> getAllUsersExcludesCurrentUser() {
+        List<UserInfo> others = mUserManager.getUsers(true);
+
+        for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) {
+            UserInfo userInfo = iterator.next();
+            if (userInfo.id == UserHandle.myUserId()) {
+                // Remove current user from the list.
+                iterator.remove();
+            }
+        }
+        return others;
+    }
+
+    // User information accessors
+
+    /**
+     * Checks whether the user is system user (admin).
+     *
+     * @param userInfo User to check against system user.
+     * @return {@code true} if system user, {@code false} otherwise.
+     */
+    public boolean userIsSystemUser(UserInfo userInfo) {
+        return userInfo.id == UserHandle.USER_SYSTEM;
+    }
+
+    /**
+     * Returns whether this user can be removed from the system.
+     *
+     * @param userInfo User to be removed
+     * @return {@code true} if they can be removed, {@code false} otherwise.
+     */
+    public boolean userCanBeRemoved(UserInfo userInfo) {
+        return !userIsSystemUser(userInfo);
+    }
+
+    /**
+     * Checks whether passed in user is the user that's currently logged in.
+     *
+     * @param userInfo User to check.
+     * @return {@code true} if current user, {@code false} otherwise.
+     */
+    public boolean userIsCurrentUser(UserInfo userInfo) {
+        return getCurrentUserInfo().id == userInfo.id;
+    }
+
+    // Current user information accessors
+
+    /**
+     * Checks if the current user is a demo user.
+     */
+    public boolean isDemoUser() {
+        return mUserManager.isDemoUser();
+    }
+
+    /**
+     * Checks if the current user is a guest user.
+     */
+    public boolean isGuestUser() {
+        return mUserManager.isGuestUser();
+    }
+
+    /**
+     * Checks if the current user is the system user (User 0).
+     */
+    public boolean isSystemUser() {
+        return mUserManager.isSystemUser();
+    }
+
+    // Current user restriction accessors
+
+    /**
+     * Return whether the current user has a restriction.
+     *
+     * @param restriction Restriction to check. Should be a UserManager.* restriction.
+     * @return Whether that restriction exists for the current user.
+     */
+    public boolean hasUserRestriction(String restriction) {
+        return mUserManager.hasUserRestriction(restriction);
+    }
+
+    /**
+     * Checks if the current user can add new users.
+     */
+    public boolean canAddUsers() {
+        return !hasUserRestriction(UserManager.DISALLOW_ADD_USER);
+    }
+
+    /**
+     * Checks if the current user can remove users.
+     */
+    public boolean canRemoveUsers() {
+        return !hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
+    }
+
+    /**
+     * Checks if the current user is allowed to switch to another user.
+     */
+    public boolean canSwitchUsers() {
+        return !hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
+    }
+
+    /**
+     * Checks if the current user can modify accounts. Demo and Guest users cannot modify accounts
+     * even if the DISALLOW_MODIFY_ACCOUNTS restriction is not applied.
+     */
+    public boolean canModifyAccounts() {
+        return !hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS) && !isDemoUser()
+                && !isGuestUser();
+    }
+
+    // User actions
+
+    /**
+     * Creates a new user on the system.
+     *
+     * @param userName Name to give to the newly created user.
+     * @return Newly created user.
+     */
+    public UserInfo createNewUser(String userName) {
+        UserInfo user = mUserManager.createUser(userName, 0 /* flags */);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many, but we haven't
+            // been able to reload the list yet.
+            Log.w(TAG, "can't create user.");
+            return null;
+        }
+        assignDefaultIcon(user);
+        return user;
+    }
+
+    /**
+     * Tries to remove the user that's passed in. System user cannot be removed.
+     * If the user to be removed is current user, it switches to the system user first, and then
+     * removes the user.
+     *
+     * @param userInfo User to be removed
+     * @return {@code true} if user is successfully removed, {@code false} otherwise.
+     */
+    public boolean removeUser(UserInfo userInfo) {
+        if (userInfo.id == UserHandle.USER_SYSTEM) {
+            Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed.");
+            return false;
+        }
+
+        if (userInfo.id == getCurrentUserInfo().id) {
+            switchToUserId(UserHandle.USER_SYSTEM);
+        }
+
+        return mUserManager.removeUser(userInfo.id);
+    }
+
+    /**
+     * Switches (logs in) to another user.
+     *
+     * @param userInfo User to switch to.
+     */
+    public void switchToUser(UserInfo userInfo) {
+        if (userInfo.id == getCurrentUserInfo().id) {
+            return;
+        }
+
+        if (userInfo.isGuest()) {
+            switchToGuest(userInfo.name);
+            return;
+        }
+
+        if (UserManager.isGuestUserEphemeral()) {
+            // If switching from guest, we want to bring up the guest exit dialog instead of
+            // switching
+            UserInfo currUserInfo = getCurrentUserInfo();
+            if (currUserInfo != null && currUserInfo.isGuest()) {
+                return;
+            }
+        }
+
+        switchToUserId(userInfo.id);
+    }
+
+    /**
+     * Creates a guest session and switches into the guest session.
+     *
+     * @param guestName Username for the guest user.
+     */
+    public void switchToGuest(String guestName) {
+        UserInfo guest = mUserManager.createGuest(mContext, guestName);
+        if (guest == null) {
+            // Couldn't create user, most likely because there are too many, but we haven't
+            // been able to reload the list yet.
+            Log.w(TAG, "can't create user.");
+            return;
+        }
+        switchToUserId(guest.id);
+    }
+
+    /**
+     * Gets an icon for the user.
+     *
+     * @param userInfo User for which we want to get the icon.
+     * @return a Bitmap for the icon
+     */
+    public Bitmap getUserIcon(UserInfo userInfo) {
+        Bitmap picture = mUserManager.getUserIcon(userInfo.id);
+
+        if (picture == null) {
+            return assignDefaultIcon(userInfo);
+        }
+
+        return picture;
+    }
+
+    /**
+     * Method for scaling a Bitmap icon to a desirable size.
+     *
+     * @param icon Bitmap to scale.
+     * @param desiredSize Wanted size for the icon.
+     * @return Drawable for the icon, scaled to the new size.
+     */
+    public Drawable scaleUserIcon(Bitmap icon, int desiredSize) {
+        Bitmap scaledIcon = Bitmap.createScaledBitmap(
+                icon, desiredSize, desiredSize, true /* filter */);
+        return new BitmapDrawable(mContext.getResources(), scaledIcon);
+    }
+
+    /**
+     * Sets new Username for the user.
+     *
+     * @param user User whose name should be changed.
+     * @param name New username.
+     */
+    public void setUserName(UserInfo user, String name) {
+        mUserManager.setUserName(user.id, name);
+    }
+
+    private void registerReceiver() {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_ADDED);
+        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+        mContext.registerReceiverAsUser(mUserChangeReceiver, UserHandle.ALL, filter, null, null);
+    }
+
+    /**
+     * Assigns a default icon to a user according to the user's id.
+     *
+     * @param userInfo User to assign a default icon to.
+     * @return Bitmap that has been assigned to the user.
+     */
+    private Bitmap assignDefaultIcon(UserInfo userInfo) {
+        Bitmap bitmap = UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
+        mUserManager.setUserIcon(userInfo.id, bitmap);
+        return bitmap;
+    }
+
+    private void switchToUserId(int id) {
+        try {
+            final ActivityManager am = (ActivityManager)
+                    mContext.getSystemService(Context.ACTIVITY_SERVICE);
+            am.switchUser(id);
+        } catch (Exception e) {
+            Log.e(TAG, "Couldn't switch user.", e);
+        }
+    }
+
+    private void unregisterReceiver() {
+        mContext.unregisterReceiver(mUserChangeReceiver);
+    }
+
+    /**
+     * Interface for listeners that want to register for receiving updates to changes to the users
+     * on the system including removing and adding users, and changing user info.
+     */
+    public interface OnUsersUpdateListener {
+        /**
+         * Method that will get called when users list has been changed.
+         */
+        void onUsersUpdate();
+    }
+}
+
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index 68be2b4..81a2d43 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -27,6 +27,9 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.TtsSpan;
+
+import com.android.settingslib.R;
+
 import java.util.ArrayList;
 import java.util.Locale;
 
@@ -121,8 +124,7 @@
         final RelativeUnit unit;
         final int value;
         if (withSeconds && seconds < 2 * SECONDS_PER_MINUTE) {
-            unit = RelativeUnit.SECONDS;
-            value = seconds;
+            return context.getResources().getString(R.string.time_unit_just_now);
         } else if (seconds < 2 * SECONDS_PER_HOUR) {
             unit = RelativeUnit.MINUTES;
             value = (seconds + SECONDS_PER_MINUTE / 2)
@@ -141,7 +143,7 @@
         final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
                 ULocale.forLocale(locale),
                 null /* default NumberFormat */,
-                RelativeDateTimeFormatter.Style.SHORT,
+                RelativeDateTimeFormatter.Style.LONG,
                 android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
 
         return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
new file mode 100644
index 0000000..325ef3a
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.users;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class UserManagerHelperTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private ActivityManager mActivityManager;
+    @Mock
+    private UserManagerHelper.OnUsersUpdateListener mTestListener;
+
+    private UserManagerHelper mHelper;
+    private UserInfo mCurrentUser;
+    private UserInfo mSystemUser;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);
+        when(mContext.getResources())
+                .thenReturn(InstrumentationRegistry.getTargetContext().getResources());
+        mHelper = new UserManagerHelper(mContext);
+
+        mCurrentUser = createUserInfoForId(UserHandle.myUserId());
+        mSystemUser = createUserInfoForId(UserHandle.USER_SYSTEM);
+        when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(mCurrentUser);
+    }
+
+    @Test
+    public void testUserIsSystemUser() {
+        UserInfo testInfo = new UserInfo();
+
+        testInfo.id = UserHandle.USER_SYSTEM;
+        assertThat(mHelper.userIsSystemUser(testInfo)).isTrue();
+
+        testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id.
+        assertThat(mHelper.userIsSystemUser(testInfo)).isFalse();
+    }
+
+    @Test
+    public void testGetAllUsersExcludesCurrentUser() {
+        int currentUser = UserHandle.myUserId();
+
+        UserInfo otherUser1 = createUserInfoForId(currentUser + 1);
+        UserInfo otherUser2 = createUserInfoForId(currentUser - 1);
+        UserInfo otherUser3 = createUserInfoForId(currentUser + 2);
+
+        List<UserInfo> testUsers = new ArrayList<>();
+        testUsers.add(otherUser1);
+        testUsers.add(otherUser2);
+        testUsers.add(mCurrentUser);
+        testUsers.add(otherUser3);
+
+        when(mUserManager.getUsers(true)).thenReturn(testUsers);
+
+        // Should return 3 users that don't have currentUser id.
+        assertThat(mHelper.getAllUsersExcludesCurrentUser().size()).isEqualTo(3);
+        // Should not contain current user.
+        assertThat(mHelper.getAllUsersExcludesCurrentUser()).doesNotContain(mCurrentUser);
+        // Should contain non-current users.
+        assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser1);
+        assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser2);
+        assertThat(mHelper.getAllUsersExcludesCurrentUser()).contains(otherUser3);
+    }
+
+    @Test
+    public void testUserCanBeRemoved() {
+        UserInfo testInfo = new UserInfo();
+
+        // System user cannot be removed.
+        testInfo.id = UserHandle.USER_SYSTEM;
+        assertThat(mHelper.userCanBeRemoved(testInfo)).isFalse();
+
+        testInfo.id = UserHandle.USER_SYSTEM + 2; // Make it different than system id.
+        assertThat(mHelper.userCanBeRemoved(testInfo)).isTrue();
+    }
+
+    @Test
+    public void testUserIsCurrentUser() {
+        UserInfo testInfo = new UserInfo();
+
+        // System user cannot be removed.
+        testInfo.id = UserHandle.myUserId();
+        assertThat(mHelper.userIsCurrentUser(testInfo)).isTrue();
+
+        testInfo.id = UserHandle.myUserId() + 2;
+        assertThat(mHelper.userIsCurrentUser(testInfo)).isFalse();
+    }
+
+    @Test
+    public void testCanAddUsers() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(false);
+        assertThat(mHelper.canAddUsers()).isTrue();
+
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)).thenReturn(true);
+        assertThat(mHelper.canAddUsers()).isFalse();
+    }
+
+    @Test
+    public void testCanRemoveUsers() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(false);
+        assertThat(mHelper.canRemoveUsers()).isTrue();
+
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)).thenReturn(true);
+        assertThat(mHelper.canRemoveUsers()).isFalse();
+    }
+
+    @Test
+    public void testCanSwitchUsers() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false);
+        assertThat(mHelper.canSwitchUsers()).isTrue();
+
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true);
+        assertThat(mHelper.canSwitchUsers()).isFalse();
+    }
+
+    @Test
+    public void testGuestCannotModifyAccounts() {
+        assertThat(mHelper.canModifyAccounts()).isTrue();
+
+        when(mUserManager.isGuestUser()).thenReturn(true);
+        assertThat(mHelper.canModifyAccounts()).isFalse();
+    }
+
+    @Test
+    public void testDemoUserCannotModifyAccounts() {
+        assertThat(mHelper.canModifyAccounts()).isTrue();
+
+        when(mUserManager.isDemoUser()).thenReturn(true);
+        assertThat(mHelper.canModifyAccounts()).isFalse();
+    }
+
+    @Test
+    public void testUserWithDisallowModifyAccountsRestrictionCannotModifyAccounts() {
+        assertThat(mHelper.canModifyAccounts()).isTrue();
+
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS))
+                .thenReturn(true);
+        assertThat(mHelper.canModifyAccounts()).isFalse();
+    }
+
+    @Test
+    public void testCreateNewUser() {
+        // Verify createUser on UserManager gets called.
+        mHelper.createNewUser("Test User");
+        verify(mUserManager).createUser("Test User", 0);
+
+        when(mUserManager.createUser("Test User", 0)).thenReturn(null);
+        assertThat(mHelper.createNewUser("Test User")).isNull();
+
+        UserInfo newUser = new UserInfo();
+        newUser.name = "Test User";
+        when(mUserManager.createUser("Test User", 0)).thenReturn(newUser);
+        assertThat(mHelper.createNewUser("Test User")).isEqualTo(newUser);
+    }
+
+    @Test
+    public void testRemoveUser() {
+        // Cannot remove system user.
+        assertThat(mHelper.removeUser(mSystemUser)).isFalse();
+
+        // Removing current user, calls "switch" to system user.
+        mHelper.removeUser(mCurrentUser);
+        verify(mActivityManager).switchUser(UserHandle.USER_SYSTEM);
+        verify(mUserManager).removeUser(mCurrentUser.id);
+
+        // Removing non-current, non-system user, simply calls removeUser.
+        UserInfo userToRemove = createUserInfoForId(mCurrentUser.id + 2);
+        mHelper.removeUser(userToRemove);
+        verify(mUserManager).removeUser(mCurrentUser.id + 2);
+    }
+
+    @Test
+    public void testSwitchToUser() {
+        // Switching to current user doesn't do anything.
+        mHelper.switchToUser(mCurrentUser);
+        verify(mActivityManager, never()).switchUser(mCurrentUser.id);
+
+        // Switching to Guest calls createGuest.
+        UserInfo guestInfo = new UserInfo(mCurrentUser.id + 1, "Test Guest", UserInfo.FLAG_GUEST);
+        mHelper.switchToUser(guestInfo);
+        verify(mUserManager).createGuest(mContext, "Test Guest");
+
+        // Switching to non-current, non-guest user, simply calls switchUser.
+        UserInfo userToSwitchTo = new UserInfo(mCurrentUser.id + 5, "Test User", 0);
+        mHelper.switchToUser(userToSwitchTo);
+        verify(mActivityManager).switchUser(mCurrentUser.id + 5);
+    }
+
+    @Test
+    public void testSwitchToGuest() {
+        mHelper.switchToGuest("Test Guest");
+        verify(mUserManager).createGuest(mContext, "Test Guest");
+
+        UserInfo guestInfo = new UserInfo(mCurrentUser.id + 2, "Test Guest", UserInfo.FLAG_GUEST);
+        when(mUserManager.createGuest(mContext, "Test Guest")).thenReturn(guestInfo);
+        mHelper.switchToGuest("Test Guest");
+        verify(mActivityManager).switchUser(mCurrentUser.id + 2);
+    }
+
+    @Test
+    public void testGetUserIcon() {
+        mHelper.getUserIcon(mCurrentUser);
+        verify(mUserManager).getUserIcon(mCurrentUser.id);
+    }
+
+    @Test
+    public void testScaleUserIcon() {
+        Bitmap fakeIcon = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+        Drawable scaledIcon = mHelper.scaleUserIcon(fakeIcon, 300);
+        assertThat(scaledIcon.getIntrinsicWidth()).isEqualTo(300);
+        assertThat(scaledIcon.getIntrinsicHeight()).isEqualTo(300);
+    }
+
+    @Test
+    public void testSetUserName() {
+        UserInfo testInfo = createUserInfoForId(mCurrentUser.id + 3);
+        mHelper.setUserName(testInfo, "New Test Name");
+        verify(mUserManager).setUserName(mCurrentUser.id + 3, "New Test Name");
+    }
+
+    @Test
+    public void testRegisterUserChangeReceiver() {
+        mHelper.registerOnUsersUpdateListener(mTestListener);
+
+        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        ArgumentCaptor<UserHandle> handleCaptor = ArgumentCaptor.forClass(UserHandle.class);
+        ArgumentCaptor<IntentFilter> filterCaptor = ArgumentCaptor.forClass(IntentFilter.class);
+        ArgumentCaptor<String> permissionCaptor = ArgumentCaptor.forClass(String.class);
+        ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+
+        verify(mContext).registerReceiverAsUser(
+                receiverCaptor.capture(),
+                handleCaptor.capture(),
+                filterCaptor.capture(),
+                permissionCaptor.capture(),
+                handlerCaptor.capture());
+
+        // Verify we're listening to Intents from ALL users.
+        assertThat(handleCaptor.getValue()).isEqualTo(UserHandle.ALL);
+
+        // Verify the presence of each intent in the filter.
+        // Verify the exact number of filters. Every time a new intent is added, this test should
+        // get updated.
+        assertThat(filterCaptor.getValue().countActions()).isEqualTo(3);
+        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_REMOVED)).isTrue();
+        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_ADDED)).isTrue();
+        assertThat(filterCaptor.getValue().hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue();
+
+        // Verify that calling the receiver calls the listener.
+        receiverCaptor.getValue().onReceive(mContext, new Intent());
+        verify(mTestListener).onUsersUpdate();
+
+        assertThat(permissionCaptor.getValue()).isNull();
+        assertThat(handlerCaptor.getValue()).isNull();
+
+
+        // Unregister the receiver.
+        mHelper.unregisterOnUsersUpdateListener();
+        verify(mContext).unregisterReceiver(receiverCaptor.getValue());
+    }
+
+    private UserInfo createUserInfoForId(int id) {
+        UserInfo userInfo = new UserInfo();
+        userInfo.id = id;
+        return userInfo;
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index a15f5fc..ccaf3fc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -73,11 +73,22 @@
     }
 
     @Test
-    public void isEnabled_settingsOn_noRestriction_notAdmin_shouldReturnFalse() {
+    public void isEnabled_settingsOn_noRestriction_notAdmin_notDemo_shouldReturnFalse() {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
         ShadowUserManager.getShadow().setIsAdminUser(false);
+        ShadowUserManager.getShadow().setIsDemoUser(false);
 
         assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
     }
+
+    @Test
+    public void isEnabled_settingsOn_noRestriction_notAdmin_isDemo_shouldReturnTrue() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+            Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        ShadowUserManager.getShadow().setIsAdminUser(false);
+        ShadowUserManager.getShadow().setIsDemoUser(true);
+
+        assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
new file mode 100644
index 0000000..b33df30
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.fuelgauge;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Settings.Secure;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class BatterySaverUtilsTest {
+    @Mock
+    Context mMockContext;
+
+    @Mock
+    ContentResolver mMockResolver;
+
+    @Mock
+    PowerManager mMockPowerManager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
+        when(mMockContext.getSystemService(eq(PowerManager.class))).thenReturn(mMockPowerManager);
+        when(mMockPowerManager.setPowerSaveMode(anyBoolean())).thenReturn(true);
+    }
+
+    @Test
+    public void testSetPowerSaveMode_enable_firstCall_needWarning() throws Exception {
+        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
+
+        assertEquals(false, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));
+
+        verify(mMockContext, times(1)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(0)).setPowerSaveMode(anyBoolean());
+
+        // They shouldn't have changed.
+        assertEquals(-1,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(-2,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+
+    @Test
+    public void testSetPowerSaveMode_enable_secondCall_needWarning() throws Exception {
+        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
+        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
+
+        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));
+
+        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+
+        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+
+    @Test
+    public void testSetPowerSaveMode_enable_thridCall_needWarning() throws Exception {
+        Secure.putInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); // Already acked.
+        Secure.putInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 1);
+
+        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, true));
+
+        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+
+        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+
+    @Test
+    public void testSetPowerSaveMode_enable_firstCall_noWarning() throws Exception {
+        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
+
+        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, true, false));
+
+        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+
+        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+
+    @Test
+    public void testSetPowerSaveMode_disable_firstCall_noWarning() throws Exception {
+        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
+
+        // When disabling, needFirstTimeWarning doesn't matter.
+        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, false));
+
+        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));
+
+        assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(-2,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+
+    @Test
+    public void testSetPowerSaveMode_disable_firstCall_needWarning() throws Exception {
+        Secure.putString(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
+        Secure.putString(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, "null");
+
+        // When disabling, needFirstTimeWarning doesn't matter.
+        assertEquals(true, BatterySaverUtils.setPowerSaveMode(mMockContext, false, true));
+
+        verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
+        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));
+
+        assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
+        assertEquals(-2,
+                Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
index 47dd022..532c755 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -114,7 +114,7 @@
     @Test
     public void testFormatRelativeTime_WithSeconds_ShowSeconds() {
         final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
-        final String expectedTime = "40 sec. ago";
+        final String expectedTime = "Just now";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -123,7 +123,7 @@
     @Test
     public void testFormatRelativeTime_NoSeconds_DoNotShowSeconds() {
         final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
-        final String expectedTime = "1 min. ago";
+        final String expectedTime = "1 minute ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
                 expectedTime);
@@ -132,7 +132,7 @@
     @Test
     public void testFormatRelativeTime_LessThanTwoMinutes_withSeconds() {
         final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
-        final String expectedTime = "119 sec. ago";
+        final String expectedTime = "Just now";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -141,7 +141,7 @@
     @Test
     public void testFormatRelativeTime_LessThanTwoMinutes_NoSeconds() {
         final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
-        final String expectedTime = "2 min. ago";
+        final String expectedTime = "2 minutes ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
                 expectedTime);
@@ -150,7 +150,7 @@
     @Test
     public void testFormatRelativeTime_TwoMinutes_withSeconds() {
         final double testMillis = 2 * DateUtils.MINUTE_IN_MILLIS;
-        final String expectedTime = "2 min. ago";
+        final String expectedTime = "2 minutes ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -159,7 +159,7 @@
     @Test
     public void testFormatRelativeTime_LessThanTwoHours_withSeconds() {
         final double testMillis = 119 * DateUtils.MINUTE_IN_MILLIS;
-        final String expectedTime = "119 min. ago";
+        final String expectedTime = "119 minutes ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -168,7 +168,7 @@
     @Test
     public void testFormatRelativeTime_TwoHours_withSeconds() {
         final double testMillis = 2 * DateUtils.HOUR_IN_MILLIS;
-        final String expectedTime = "2 hr. ago";
+        final String expectedTime = "2 hours ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -177,7 +177,7 @@
     @Test
     public void testFormatRelativeTime_LessThanTwoDays_withSeconds() {
         final double testMillis = 47 * DateUtils.HOUR_IN_MILLIS;
-        final String expectedTime = "47 hr. ago";
+        final String expectedTime = "47 hours ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -195,7 +195,7 @@
     @Test
     public void testFormatRelativeTime_FormatZero_WithSeconds() {
         final double testMillis = 0;
-        final String expectedTime = "0 sec. ago";
+        final String expectedTime = "Just now";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
                 expectedTime);
@@ -204,7 +204,7 @@
     @Test
     public void testFormatRelativeTime_FormatZero_NoSeconds() {
         final double testMillis = 0;
-        final String expectedTime = "0 min. ago";
+        final String expectedTime = "0 minutes ago";
 
         assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
                 expectedTime);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 34aae49..2047f58 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -578,6 +578,9 @@
                 Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
                 GlobalSettingsProto.BLE_SCAN_LOW_LATENCY_INTERVAL_MS);
         dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_BACKGROUND_MODE,
+                GlobalSettingsProto.BLE_SCAN_BACKGROUND_MODE);
+        dumpSetting(s, p,
                 Settings.Global.WIFI_SAVED_STATE,
                 GlobalSettingsProto.WIFI_SAVED_STATE);
         dumpSetting(s, p,
@@ -1158,8 +1161,8 @@
                 Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
                 GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES,
-                GlobalSettingsProto.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
+                GlobalSettingsProto.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
         dumpSetting(s, p,
                 Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
                 GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
@@ -1928,6 +1931,9 @@
         dumpSetting(s, p,
                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
                 SecureSettingsProto.BLUETOOTH_ON_WHILE_DRIVING);
+        dumpSetting(s, p,
+                Settings.Secure.VOLUME_HUSH_GESTURE,
+                SecureSettingsProto.VOLUME_HUSH_GESTURE);
         // Please insert new settings using the same order as in Settings.Secure.
 
         p.end(token);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f215c12..7fd0698 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1798,76 +1798,52 @@
         if (TextUtils.isEmpty(value)) {
             return false;
         }
-
-        final char prefix = value.charAt(0);
-        if (prefix != '+' && prefix != '-') {
-            if (forceNotify) {
-                final int key = makeKey(SETTINGS_TYPE_SECURE, owningUserId);
-                mSettingsRegistry.notifyForSettingsChange(key,
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
-            }
+        Setting oldSetting = getSecureSetting(
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
+        if (oldSetting == null) {
             return false;
         }
+        String oldProviders = oldSetting.getValue();
+        List<String> oldProvidersList = TextUtils.isEmpty(oldProviders)
+                ? new ArrayList<>() : new ArrayList<>(Arrays.asList(oldProviders.split(",")));
+        Set<String> newProvidersSet = new ArraySet<>();
+        newProvidersSet.addAll(oldProvidersList);
 
-        // skip prefix
-        value = value.substring(1);
-
-        Setting settingValue = getSecureSetting(
-                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
-        if (settingValue == null) {
-            return false;
-        }
-
-        String oldProviders = !settingValue.isNull() ? settingValue.getValue() : "";
-
-        int index = oldProviders.indexOf(value);
-        int end = index + value.length();
-
-        // check for commas to avoid matching on partial string
-        if (index > 0 && oldProviders.charAt(index - 1) != ',') {
-            index = -1;
-        }
-
-        // check for commas to avoid matching on partial string
-        if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
-            index = -1;
-        }
-
-        String newProviders;
-
-        if (prefix == '+' && index < 0) {
-            // append the provider to the list if not present
-            if (oldProviders.length() == 0) {
-                newProviders = value;
-            } else {
-                newProviders = oldProviders + ',' + value;
+        String[] providerUpdates = value.split(",");
+        boolean inputError = false;
+        for (String provider : providerUpdates) {
+            // do not update location_providers_allowed when input is invalid
+            if (TextUtils.isEmpty(provider)) {
+                inputError = true;
+                break;
             }
-        } else if (prefix == '-' && index >= 0) {
-            // remove the provider from the list if present
-            // remove leading or trailing comma
-            if (index > 0) {
-                index--;
-            } else if (end < oldProviders.length()) {
-                end++;
+            final char prefix = provider.charAt(0);
+            // do not update location_providers_allowed when input is invalid
+            if (prefix != '+' && prefix != '-') {
+                inputError = true;
+                break;
             }
-
-            newProviders = oldProviders.substring(0, index);
-            if (end < oldProviders.length()) {
-                newProviders += oldProviders.substring(end);
+            // skip prefix
+            provider = provider.substring(1);
+            if (prefix == '+') {
+                newProvidersSet.add(provider);
+            } else if (prefix == '-') {
+                newProvidersSet.remove(provider);
             }
-        } else {
+        }
+        String newProviders = TextUtils.join(",", newProvidersSet.toArray());
+        if (inputError == true || newProviders.equals(oldProviders)) {
             // nothing changed, so no need to update the database
             if (forceNotify) {
-                final int key = makeKey(SETTINGS_TYPE_SECURE, owningUserId);
-                mSettingsRegistry.notifyForSettingsChange(key,
+                mSettingsRegistry.notifyForSettingsChange(
+                        makeKey(SETTINGS_TYPE_SECURE, owningUserId),
                         Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
             }
             return false;
         }
-
         return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_SECURE,
-                owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
-                tag, makeDefault, getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
+                owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders, tag,
+                makeDefault, getCallingPackage(), forceNotify, CRITICAL_SECURE_SETTINGS);
     }
 
     private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
@@ -2938,7 +2914,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 161;
+            private static final int SETTINGS_VERSION = 162;
 
             private final int mUserId;
 
@@ -3697,6 +3673,21 @@
                     currentVersion = 161;
                 }
 
+                if (currentVersion == 161) {
+                    // Version 161: Add a gesture for silencing phones
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting currentSetting = secureSettings.getSettingLocked(
+                            Secure.VOLUME_HUSH_GESTURE);
+                    if (currentSetting.isNull()) {
+                        secureSettings.insertSettingLocked(
+                                Secure.VOLUME_HUSH_GESTURE,
+                                Integer.toString(Secure.VOLUME_HUSH_VIBRATE),
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 162;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index e2a8fba..b6f51bc 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -17,8 +17,8 @@
 package com.android.providers.settings;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.fail;
 
 import android.content.ContentResolver;
@@ -32,9 +32,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
-import org.junit.Test;
-
 import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.Test;
 
 /**
  * Tests for the SettingContentProvider.
@@ -688,4 +687,112 @@
             cursor.close();
         }
     }
+
+    @Test
+    public void testUpdateLocationProvidersAllowedLocked_enableProviders() throws Exception {
+        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
+                UserHandle.USER_SYSTEM);
+
+        // Enable one provider
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+gps");
+
+        assertEquals(
+                "Wrong location providers",
+                "gps",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+        // Enable a list of providers, including the one that is already enabled
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                "+gps,+network,+network");
+
+        assertEquals(
+                "Wrong location providers",
+                "gps,network",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+    }
+
+    @Test
+    public void testUpdateLocationProvidersAllowedLocked_disableProviders() throws Exception {
+        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
+                UserHandle.USER_SYSTEM);
+
+        // Disable providers that were enabled
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                "-gps,-network");
+
+        assertEquals(
+                "Wrong location providers",
+                "",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+
+        // Disable a provider that was not enabled
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                "-test");
+
+        assertEquals(
+                "Wrong location providers",
+                "",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+    }
+
+    @Test
+    public void testUpdateLocationProvidersAllowedLocked_enableAndDisable() throws Exception {
+        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
+                UserHandle.USER_SYSTEM);
+
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                "+gps,+network,+test");
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test");
+
+        assertEquals(
+                "Wrong location providers",
+                "gps,network",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+    }
+
+    @Test
+    public void testUpdateLocationProvidersAllowedLocked_invalidInput() throws Exception {
+        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
+                UserHandle.USER_SYSTEM);
+
+        // update providers with a invalid string
+        updateStringViaProviderApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                "+gps, invalid-string");
+
+        // Verifies providers list does not change
+        assertEquals(
+                "Wrong location providers",
+                "",
+                queryStringViaProviderApi(
+                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+    }
 }
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index f65efb8..68293d9 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -37,6 +37,7 @@
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
     SystemUISharedLib \
+    android-support-car \
     android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
diff --git a/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml b/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml
new file mode 100644
index 0000000..25b449a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <corners
+        android:bottomLeftRadius="@dimen/car_radius_3"
+        android:topLeftRadius="0dp"
+        android:bottomRightRadius="@dimen/car_radius_3"
+        android:topRightRadius="0dp"
+        />
+</shape>
diff --git a/packages/SystemUI/res/layout/car_volume_dialog.xml b/packages/SystemUI/res/layout/car_volume_dialog.xml
new file mode 100644
index 0000000..dca50a5
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_volume_dialog.xml
@@ -0,0 +1,68 @@
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="@dimen/car_margin"
+    android:layout_marginEnd="@dimen/car_margin"
+    android:background="@drawable/car_rounded_bg_bottom"
+    android:theme="@style/qs_theme"
+    android:clipChildren="false" >
+    <LinearLayout
+        android:id="@+id/volume_dialog"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|top"
+        android:orientation="vertical"
+        android:clipChildren="false" >
+
+        <LinearLayout
+            android:id="@+id/main"
+            android:layout_width="match_parent"
+            android:minWidth="@dimen/volume_dialog_panel_width"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:elevation="@dimen/volume_panel_elevation" >
+            <LinearLayout
+                android:id="@+id/car_volume_dialog_rows"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:orientation="vertical" >
+                <!-- volume rows added and removed here! :-) -->
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/car_single_line_list_item_height"
+        android:gravity="center"
+        android:layout_marginEnd="@dimen/car_keyline_1">
+        <ImageButton
+            android:id="@+id/expand"
+            android:layout_gravity="center"
+            android:layout_width="@dimen/car_primary_icon_size"
+            android:layout_height="@dimen/car_primary_icon_size"
+            android:layout_marginEnd="@dimen/car_keyline_1"
+            android:src="@drawable/car_ic_arrow_drop_up"
+            android:tint="@color/car_tint"
+            android:scaleType="fitCenter"
+        />
+    </FrameLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/car_volume_dialog_row.xml b/packages/SystemUI/res/layout/car_volume_dialog_row.xml
new file mode 100644
index 0000000..14baf49
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_volume_dialog_row.xml
@@ -0,0 +1,47 @@
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:tag="row"
+    android:layout_height="@dimen/car_single_line_list_item_height"
+    android:layout_width="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:theme="@style/qs_theme">
+
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:gravity="center"
+        android:layout_gravity="center"
+        android:orientation="horizontal" >
+        <com.android.keyguard.AlphaOptimizedImageButton
+            android:id="@+id/volume_row_icon"
+            android:layout_width="@dimen/car_primary_icon_size"
+            android:layout_height="@dimen/car_primary_icon_size"
+            android:layout_marginStart="@dimen/car_keyline_1"
+            android:tint="@color/car_tint"
+            android:scaleType="fitCenter"
+            android:soundEffectsEnabled="false" />
+        <SeekBar
+                android:id="@+id/volume_row_slider"
+                android:clickable="true"
+                android:layout_marginStart="@dimen/car_keyline_3"
+                android:layout_marginEnd="@dimen/car_keyline_3"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/car_single_line_list_item_height"/>
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 2da03d2..cc6e3bf 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -50,6 +50,7 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:layout_gravity="center_vertical"
+        android:paddingEnd="1dp"
         android:visibility="gone" />
     <Space
         android:id="@+id/mobile_roaming_space"
diff --git a/packages/SystemUI/res/values-sw600dp/bools.xml b/packages/SystemUI/res/values-sw600dp/bools.xml
new file mode 100644
index 0000000..05e38bd
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+    <!-- Whether to show the user switcher in quick settings when only a single user is present. -->
+    <bool name="qs_show_user_switcher_for_single_user">true</bool>
+</resources>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
new file mode 100644
index 0000000..499e24e
--- /dev/null
+++ b/packages/SystemUI/res/values/bools.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+    <!-- Whether to show the user switcher in quick settings when only a single user is present. -->
+    <bool name="qs_show_user_switcher_for_single_user">false</bool>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5b038b1..906ca4a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -79,9 +79,6 @@
     <!-- The color of the material notification background when dark -->
     <color name="notification_material_background_dark_color">#ff333333</color>
 
-    <!-- The color of the material notification background when low priority -->
-    <color name="notification_material_background_low_priority_color">#fff5f5f5</color>
-
     <!-- The color of the dividing line between grouped notifications. -->
     <color name="notification_divider_color">#FF616161</color>
 
@@ -91,9 +88,6 @@
     <!-- The color of the ripples on the untinted notifications -->
     <color name="notification_ripple_untinted_color">#28000000</color>
 
-    <!-- The color of the ripples on the low priority notifications -->
-    <color name="notification_ripple_color_low_priority">#30000000</color>
-
     <!-- The color of the ripples on the tinted notifications -->
     <color name="notification_ripple_tinted_color">#30ffffff</color>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3c8a695..a4b7608 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -669,7 +669,7 @@
     <string name="ethernet_label">Ethernet</string>
 
     <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_header_onboarding_text">Press &amp; hold on the icons for more options</string>
+    <string name="quick_settings_header_onboarding_text">Touch &amp; hold icons for more options</string>
     <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_label">Do not disturb</string>
     <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
@@ -1353,8 +1353,6 @@
 
     <string name="volume_dialog_title">%s volume controls</string>
 
-    <string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
-    <string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
     <string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring</string>
 
     <string name="output_title">Media output</string>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 9a3a825..b89e15d 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -27,7 +27,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.media.AudioAttributes;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -37,6 +36,7 @@
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.settingslib.Utils;
+import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
@@ -72,6 +72,8 @@
             "PNW.clickedThermalShutdownWarning";
     private static final String ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING =
             "PNW.dismissedThermalShutdownWarning";
+    private static final String ACTION_SHOW_START_SAVER_CONFIRMATION =
+            BatterySaverUtils.ACTION_SHOW_START_SAVER_CONFIRMATION;
 
     private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -404,7 +406,7 @@
         d.setTitle(R.string.battery_saver_confirmation_title);
         d.setMessage(com.android.internal.R.string.battery_saver_description);
         d.setNegativeButton(android.R.string.cancel, null);
-        d.setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode);
+        d.setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverModeNoConfirmation);
         d.setShowForAllUsers(true);
         d.setOnDismissListener(new OnDismissListener() {
             @Override
@@ -416,8 +418,8 @@
         mSaverConfirmation = d;
     }
 
-    private void setSaverMode(boolean mode) {
-        mPowerMan.setPowerSaveMode(mode);
+    private void setSaverMode(boolean mode, boolean needFirstTimeWarning) {
+        BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning);
     }
 
     private final class Receiver extends BroadcastReceiver {
@@ -431,8 +433,9 @@
             filter.addAction(ACTION_DISMISSED_TEMP_WARNING);
             filter.addAction(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING);
             filter.addAction(ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING);
+            filter.addAction(ACTION_SHOW_START_SAVER_CONFIRMATION);
             mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
-                    android.Manifest.permission.STATUS_BAR_SERVICE, mHandler);
+                    android.Manifest.permission.DEVICE_POWER, mHandler);
         }
 
         @Override
@@ -443,6 +446,9 @@
                 dismissLowBatteryNotification();
                 mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
             } else if (action.equals(ACTION_START_SAVER)) {
+                setSaverMode(true, true);
+                dismissLowBatteryNotification();
+            } else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) {
                 dismissLowBatteryNotification();
                 showStartSaverConfirmation();
             } else if (action.equals(ACTION_DISMISSED_WARNING)) {
@@ -461,15 +467,6 @@
         }
     }
 
-    private final OnClickListener mStartSaverMode = new OnClickListener() {
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            AsyncTask.execute(new Runnable() {
-                @Override
-                public void run() {
-                    setSaverMode(true);
-                }
-            });
-        }
-    };
+    private final OnClickListener mStartSaverModeNoConfirmation =
+            (dialog, which) -> setSaverMode(true, false);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index ac86c8a..f08219a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -137,24 +137,9 @@
     void updateBatteryWarningLevels() {
         int critLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
-
-        final ContentResolver resolver = mContext.getContentResolver();
-        final int defWarnLevel = mContext.getResources().getInteger(
+        int warnLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
-        final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver,
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
 
-        // Note LOW_POWER_MODE_TRIGGER_LEVEL can take any value between 0 and 100, but
-        // for the UI purposes, let's cap it at 15% -- i.e. even if the trigger level is higher
-        // like 50%, let's not show the "low battery" notification until it hits
-        // config_lowBatteryWarningLevel, which is 15% by default.
-        // LOW_POWER_MODE_TRIGGER_LEVEL is still used in other places as-is. For example, if it's
-        // 50, then battery saver kicks in when the battery level hits 50%.
-        int warnLevel =  Math.min(defWarnLevel, lowPowerModeTriggerLevel);
-
-        if (warnLevel == 0) {
-            warnLevel = defWarnLevel;
-        }
         if (warnLevel < critLevel) {
             warnLevel = critLevel;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ea3a60b..8923952 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -42,16 +42,14 @@
     };
 
 
-    private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
-    private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
+    private final ArrayList<TileRecord> mTiles = new ArrayList<>();
+    private final ArrayList<TilePage> mPages = new ArrayList<>();
 
     private PageIndicator mPageIndicator;
 
     private int mNumPages;
     private PageListener mPageListener;
 
-    private int mPosition;
-    private boolean mOffPage;
     private boolean mListening;
     private Scroller mScroller;
 
@@ -85,16 +83,12 @@
     public void setListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
-        if (mListening) {
-            setPageListening(mPosition, true);
-            if (mOffPage) {
-                setPageListening(mPosition + 1, true);
-            }
-        } else {
-            // Make sure no pages are listening.
-            for (int i = 0; i < mPages.size(); i++) {
-                mPages.get(i).setListening(false);
-            }
+        updateListening();
+    }
+
+    private void updateListening() {
+        for (TilePage tilePage : mPages) {
+            tilePage.setListening(tilePage.getParent() == null ? false : mListening);
         }
     }
 
@@ -137,43 +131,6 @@
         super.computeScroll();
     }
 
-    /**
-     * Sets individual pages to listening or not.  If offPage it will set
-     * the next page after position to listening as well since we are in between
-     * pages.
-     */
-    private void setCurrentPage(int position, boolean offPage) {
-        if (mPosition == position && mOffPage == offPage) return;
-        if (mListening) {
-            if (mPosition != position) {
-                // Clear out the last pages from listening.
-                setPageListening(mPosition, false);
-                if (mOffPage) {
-                    setPageListening(mPosition + 1, false);
-                }
-                // Set the new pages to listening
-                setPageListening(position, true);
-                if (offPage) {
-                    setPageListening(position + 1, true);
-                }
-            } else if (mOffPage != offPage) {
-                // Whether we are showing position + 1 has changed.
-                setPageListening(mPosition + 1, offPage);
-            }
-        }
-        // Save the current state.
-        mPosition = position;
-        mOffPage = offPage;
-    }
-
-    private void setPageListening(int position, boolean listening) {
-        if (position >= mPages.size()) return;
-        if (isLayoutRtl()) {
-            position = mPages.size() - 1 - position;
-        }
-        mPages.get(position).setListening(listening);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
@@ -362,7 +319,6 @@
                 public void onPageScrolled(int position, float positionOffset,
                         int positionOffsetPixels) {
                     if (mPageIndicator == null) return;
-                    setCurrentPage(position, positionOffset != 0);
                     mPageIndicator.setLocation(position + positionOffset);
                     if (mPageListener != null) {
                         mPageListener.onPageChanged(positionOffsetPixels == 0 &&
@@ -407,11 +363,14 @@
     }
 
     private final PagerAdapter mAdapter = new PagerAdapter() {
+        @Override
         public void destroyItem(ViewGroup container, int position, Object object) {
             if (DEBUG) Log.d(TAG, "Destantiating " + position);
             container.removeView((View) object);
+            updateListening();
         }
 
+        @Override
         public Object instantiateItem(ViewGroup container, int position) {
             if (DEBUG) Log.d(TAG, "Instantiating " + position);
             if (isLayoutRtl()) {
@@ -419,6 +378,7 @@
             }
             ViewGroup view = mPages.get(position);
             container.addView(view);
+            updateListening();
             return view;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7da109d..bfbfbf6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -140,7 +140,6 @@
         setMargins(mQSFooter);
         setMargins(mQSPanel);
         setMargins(mHeader);
-        setMargins(mQSCustomizer);
     }
 
     private void setMargins(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index dbf1745..0fa6597 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.graphics.PorterDuff.Mode;
@@ -49,7 +50,6 @@
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.MultiUserSwitch;
 import com.android.systemui.statusbar.phone.SettingsButton;
@@ -257,17 +257,31 @@
         mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
-
         final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
-
-
-        mMultiUserSwitch.setVisibility(mExpanded
-                && UserManager.get(mContext).isUserSwitcherEnabled()
-                ? View.VISIBLE : View.INVISIBLE);
-
+        mMultiUserSwitch.setVisibility(showUserSwitcher(isDemo) ? View.VISIBLE : View.INVISIBLE);
         mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
     }
 
+    private boolean showUserSwitcher(boolean isDemo) {
+        if (!mExpanded || isDemo || !UserManager.supportsMultipleUsers()) {
+            return false;
+        }
+        UserManager userManager = UserManager.get(mContext);
+        if (userManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
+            return false;
+        }
+        int switchableUserCount = 0;
+        for (UserInfo user : userManager.getUsers(true)) {
+            if (user.supportsSwitchToByUser()) {
+                ++switchableUserCount;
+                if (switchableUserCount > 1) {
+                    return true;
+                }
+            }
+        }
+        return getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user);
+    }
+
     private void updateListeners() {
         if (mListening) {
             mUserInfoController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 9759b69..eb95866 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -15,42 +15,33 @@
 package com.android.systemui.qs.customize;
 
 import android.content.Context;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.TextView;
-import com.android.systemui.R;
+
 import com.android.systemui.plugins.qs.QSIconView;
+import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.tileimpl.QSTileView;
-import java.util.Objects;
 
 public class CustomizeTileView extends QSTileView {
+    private boolean mShowAppLabel;
 
-    private TextView mAppLabel;
-    private int mLabelMinLines;
     public CustomizeTileView(Context context, QSIconView icon) {
         super(context, icon);
     }
 
-    @Override
-    protected void createLabel() {
-        super.createLabel();
-        mLabelMinLines = mLabel.getMinLines();
-        mAppLabel = findViewById(R.id.app_label);
-        mAppLabel.setAlpha(.6f);
-    }
-
     public void setShowAppLabel(boolean showAppLabel) {
-        mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
+        mShowAppLabel = showAppLabel;
+        mSecondLine.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
         mLabel.setSingleLine(showAppLabel);
     }
 
-    public void setAppLabel(CharSequence label) {
-        if (!Objects.equals(label, mAppLabel.getText())) {
-            mAppLabel.setText(label);
-        }
+    @Override
+    protected void handleStateChanged(QSTile.State state) {
+        super.handleStateChanged(state);
+        mSecondLine.setVisibility(mShowAppLabel ? View.VISIBLE : View.GONE);
     }
 
     public TextView getAppLabel() {
-        return mAppLabel;
+        return mSecondLine;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 3ba5fe6..441d29b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -274,7 +274,6 @@
                     R.string.accessibility_qs_edit_tile_label, position + 1, info.state.label);
         }
         holder.mTileView.onStateChanged(info.state);
-        holder.mTileView.setAppLabel(info.appLabel);
         holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
 
         if (mAccessibilityManager.isTouchExplorationEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 2ac592f..8bf4096 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.service.quicksettings.TileService;
+import android.text.TextUtils;
 import android.widget.Button;
 
 import com.android.systemui.Dependency;
@@ -169,7 +170,8 @@
         info.state.expandedAccessibilityClassName =
                 Button.class.getName();
         info.spec = spec;
-        info.appLabel = appLabel;
+        info.state.secondaryLabel = (isSystem || TextUtils.equals(state.label, appLabel))
+                ? null : appLabel;
         info.isSystem = isSystem;
         mTiles.add(info);
         mSpecs.add(spec);
@@ -186,7 +188,6 @@
 
     public static class TileInfo {
         public String spec;
-        public CharSequence appLabel;
         public QSTile.State state;
         public boolean isSystem;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 40b8d78..834feb7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -85,6 +85,7 @@
     private String mTileSpec;
     private EnforcedAdmin mEnforcedAdmin;
     private boolean mShowingDetail;
+    private int mIsFullQs;
 
     public abstract TState newTileState();
 
@@ -110,18 +111,7 @@
      * listening client it will go into the listening state.
      */
     public void setListening(Object listener, boolean listening) {
-        if (listening) {
-            if (mListeners.add(listener) && mListeners.size() == 1) {
-                if (DEBUG) Log.d(TAG, "setListening " + true);
-                mHandler.obtainMessage(H.SET_LISTENING, 1, 0).sendToTarget();
-                refreshState(); // Ensure we get at least one refresh after listening.
-            }
-        } else {
-            if (mListeners.remove(listener) && mListeners.size() == 0) {
-                if (DEBUG) Log.d(TAG, "setListening " + false);
-                mHandler.obtainMessage(H.SET_LISTENING, 0, 0).sendToTarget();
-            }
-        }
+        mHandler.obtainMessage(H.SET_LISTENING, listening ? 1 : 0, 0, listener).sendToTarget();
     }
 
     protected long getStaleTimeout() {
@@ -205,19 +195,10 @@
             logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
         }
         return logMaker.setSubtype(getMetricsCategory())
-                .addTaggedData(FIELD_CONTEXT, isFullQs())
+                .addTaggedData(FIELD_CONTEXT, mIsFullQs)
                 .addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
     }
 
-    private int isFullQs() {
-        for (Object listener : mListeners) {
-            if (TilePage.class.equals(listener.getClass())) {
-                return 1;
-            }
-        }
-        return 0;
-    }
-
     public void showDetail(boolean show) {
         mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
     }
@@ -352,6 +333,32 @@
         handleRefreshState(null);
     }
 
+    private void handleSetListeningInternal(Object listener, boolean listening) {
+        if (listening) {
+            if (mListeners.add(listener) && mListeners.size() == 1) {
+                if (DEBUG) Log.d(TAG, "handleSetListening true");
+                handleSetListening(listening);
+                refreshState(); // Ensure we get at least one refresh after listening.
+            }
+        } else {
+            if (mListeners.remove(listener) && mListeners.size() == 0) {
+                if (DEBUG) Log.d(TAG, "handleSetListening false");
+                handleSetListening(listening);
+            }
+        }
+        updateIsFullQs();
+    }
+
+    private void updateIsFullQs() {
+        for (Object listener : mListeners) {
+            if (TilePage.class.equals(listener.getClass())) {
+                mIsFullQs = 1;
+                return;
+            }
+        }
+        mIsFullQs = 0;
+    }
+
     protected abstract void handleSetListening(boolean listening);
 
     protected void handleDestroy() {
@@ -464,8 +471,8 @@
                     name = "handleClearState";
                     handleClearState();
                 } else if (msg.what == SET_LISTENING) {
-                    name = "handleSetListening";
-                    handleSetListening(msg.arg1 != 0);
+                    name = "handleSetListeningInternal";
+                    handleSetListeningInternal(msg.obj, msg.arg1 != 0);
                 } else if (msg.what == STALE) {
                     name = "handleStale";
                     handleStale();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index 45c20a0..4774785 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -40,7 +40,7 @@
     private static final boolean DUAL_TARGET_ALLOWED = false;
     private View mDivider;
     protected TextView mLabel;
-    private TextView mSecondLine;
+    protected TextView mSecondLine;
     private ImageView mPadLock;
     private int mState;
     private ViewGroup mLabelContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 7db2a50..068fd3f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.screenshot;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
 import static com.android.systemui.screenshot.GlobalScreenshot.SHARING_INTENT;
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT;
 
@@ -26,11 +28,11 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.admin.DevicePolicyManager;
 import android.app.Notification;
 import android.app.Notification.BigPictureStyle;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -58,7 +60,6 @@
 import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 import android.view.LayoutInflater;
@@ -517,6 +518,7 @@
                     | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
                 PixelFormat.TRANSLUCENT);
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
+        mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mNotificationManager =
             (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 8c28af5..8b6b5fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -99,7 +99,6 @@
     private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
             = new PathInterpolator(0, 0, 0.5f, 1);
     private final int mTintedRippleColor;
-    private final int mLowPriorityRippleColor;
     protected final int mNormalRippleColor;
     private final AccessibilityManager mAccessibilityManager;
     private final DoubleTapHelper mDoubleTapHelper;
@@ -134,7 +133,6 @@
     private float mAppearAnimationFraction = -1.0f;
     private float mAppearAnimationTranslation;
     private final int mNormalColor;
-    private final int mLowPriorityColor;
     private boolean mIsBelowSpeedBump;
     private FalsingManager mFalsingManager;
 
@@ -191,12 +189,8 @@
         setClipChildren(false);
         setClipToPadding(false);
         mNormalColor = context.getColor(R.color.notification_material_background_color);
-        mLowPriorityColor = context.getColor(
-                R.color.notification_material_background_low_priority_color);
         mTintedRippleColor = context.getColor(
                 R.color.notification_ripple_tinted_color);
-        mLowPriorityRippleColor = context.getColor(
-                R.color.notification_ripple_color_low_priority);
         mNormalRippleColor = context.getColor(
                 R.color.notification_ripple_untinted_color);
         mFalsingManager = FalsingManager.getInstance(context);
@@ -997,8 +991,6 @@
         }
         if (withTint && mBgTint != NO_COLOR) {
             return mBgTint;
-        } else if (mIsBelowSpeedBump) {
-            return mLowPriorityColor;
         } else {
             return mNormalColor;
         }
@@ -1007,8 +999,6 @@
     protected int getRippleColor() {
         if (mBgTint != 0) {
             return mTintedRippleColor;
-        } else if (mIsBelowSpeedBump) {
-            return mLowPriorityRippleColor;
         } else {
             return mNormalRippleColor;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 9bd8080..6b9567d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -88,6 +88,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
 
 public class ExpandableNotificationRow extends ActivatableNotificationView
         implements PluginListener<NotificationMenuRowPlugin> {
@@ -179,6 +180,7 @@
     private boolean mExpandAnimationRunning;
     private AboveShelfChangedListener mAboveShelfChangedListener;
     private HeadsUpManager mHeadsUpManager;
+    private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
     private View mHelperButton;
     private boolean mChildIsExpanding;
 
@@ -1115,13 +1117,21 @@
 
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         boolean wasAboveShelf = isAboveShelf();
+        boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
         mHeadsupDisappearRunning = headsUpAnimatingAway;
         mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+        if (changed && mHeadsUpAnimatingAwayListener != null) {
+            mHeadsUpAnimatingAwayListener.accept(headsUpAnimatingAway);
+        }
         if (isAboveShelf() != wasAboveShelf) {
             mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
         }
     }
 
+    public void setHeadsUpAnimatingAwayListener(Consumer<Boolean> listener) {
+        mHeadsUpAnimatingAwayListener = listener;
+    }
+
     /**
      * @return if the view was just heads upped and is now animating away. During such a time the
      * layout needs to be kept consistent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 48828ab..7a7cc99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -332,6 +332,7 @@
         row.setOnExpandClickListener(mPresenter);
         row.setInflationCallback(this);
         row.setLongPressListener(getNotificationLongClicker());
+        mListContainer.bindRow(row);
         mRemoteInputManager.bindRow(row);
 
         // Get the app name.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 1127075..886d6f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -75,7 +75,7 @@
                 if (shouldApply) {
                     // lets gray it out
                     int grey = view.getContext().getColor(
-                            com.android.internal.R.color.notification_icon_default_color);
+                            com.android.internal.R.color.notification_default_color_light);
                     imageView.getDrawable().setColorFilter(grey, PorterDuff.Mode.SRC_ATOP);
                 } else {
                     // lets reset it
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
index 0c19ec0..af9a3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListContainer.java
@@ -188,4 +188,11 @@
     default void applyExpandAnimationParams(ExpandAnimationParameters params) {}
 
     default void setExpandingNotification(ExpandableNotificationRow row) {}
+
+    /**
+     * Bind a newly created row.
+     *
+     * @param row The notification to bind.
+     */
+    default void bindRow(ExpandableNotificationRow row) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index aecf5fb..41c7559 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -177,7 +177,7 @@
             mShelfState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
                     getFullyClosedTranslation());
             mShelfState.zTranslation = ambientState.getBaseZHeight();
-            if (mAmbientState.isDark()) {
+            if (mAmbientState.isDark() && !mAmbientState.hasPulsingNotifications()) {
                 mShelfState.yTranslation = mAmbientState.getDarkTopPadding();
             }
             float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5bb85e2..603902a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -165,7 +165,7 @@
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         if (mNotification != null) {
             setDecorColor(getContext().getColor(
-                    com.android.internal.R.color.notification_icon_default_color));
+                    com.android.internal.R.color.notification_default_color_light));
         }
         reloadDimens();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index 80854ec..2b7949b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -76,7 +76,6 @@
      * notification.
      */
     private final Context mPackageContext;
-    private boolean mIsLowPriority;
 
     public MediaNotificationProcessor(Context context, Context packageContext) {
         this(context, packageContext, new ImageGradientColorizer());
@@ -146,10 +145,7 @@
                 int foregroundColor = selectForegroundColor(backgroundColor, palette);
                 builder.setColorPalette(backgroundColor, foregroundColor);
             } else {
-                int id = mIsLowPriority
-                        ? R.color.notification_material_background_low_priority_color
-                        : R.color.notification_material_background_color;
-                backgroundColor = mContext.getColor(id);
+                backgroundColor = mContext.getColor(R.color.notification_material_background_color);
             }
             Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
                     mContext.getResources().getConfiguration().getLayoutDirection() ==
@@ -307,8 +303,4 @@
     private boolean isWhite(float[] hslColor) {
         return hslColor[2] >= WHITE_MIN_LIGHTNESS;
     }
-
-    public void setIsLowPriority(boolean isLowPriority) {
-        mIsLowPriority = isLowPriority;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 251e04b..78df77f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -122,9 +122,9 @@
         mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
         mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
         mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
-        mColor = resolveColor(mExpandButton);
         mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
         mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
+        mColor = mNotificationHeader.getOriginalIconColor();
         getDozer().setColor(mColor);
     }
 
@@ -132,16 +132,6 @@
         mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener());
     }
 
-    private int resolveColor(ImageView icon) {
-        if (icon != null && icon.getDrawable() != null) {
-            ColorFilter filter = icon.getDrawable().getColorFilter();
-            if (filter instanceof PorterDuffColorFilter) {
-                return ((PorterDuffColorFilter) filter).getColor();
-            }
-        }
-        return 0;
-    }
-
     @Override
     public void onContentUpdated(ExpandableNotificationRow row) {
         super.onContentUpdated(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index f5110a2d..0143d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -584,15 +584,9 @@
                         mSbn.getNotification());
                 Context packageContext = mSbn.getPackageContext(mContext);
                 Notification notification = mSbn.getNotification();
-                if (mIsLowPriority) {
-                    int backgroundColor = mContext.getColor(
-                            R.color.notification_material_background_low_priority_color);
-                    recoveredBuilder.setBackgroundColorHint(backgroundColor);
-                }
                 if (notification.isMediaNotification()) {
                     MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
                             packageContext);
-                    processor.setIsLowPriority(mIsLowPriority);
                     processor.processNotification(notification, recoveredBuilder);
                 }
                 return createRemoteViews(mReInflateFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index c576801..9ec5609 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -30,6 +30,9 @@
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
 /**
  * Controls the appearance of heads up notifications in the icon area and the header itself.
  */
@@ -43,11 +46,19 @@
     private final HeadsUpStatusBarView mHeadsUpStatusBarView;
     private final View mClockView;
     private final DarkIconDispatcher mDarkIconDispatcher;
+    private final NotificationPanelView mPanelView;
+    private final Consumer<ExpandableNotificationRow>
+            mSetTrackingHeadsUp = this::setTrackingHeadsUp;
+    private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
+    private final BiConsumer<Float, Float> mSetExpandedHeight = this::setExpandedHeight;
     private float mExpandedHeight;
     private boolean mIsExpanded;
     private float mExpandFraction;
     private ExpandableNotificationRow mTrackedChild;
     private boolean mShown;
+    private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
+            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
+                    -> updatePanelTranslation();
 
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
@@ -75,18 +86,29 @@
         headsUpStatusBarView.setOnDrawingRectChangedListener(
                 () -> updateIsolatedIconLocation(true /* requireUpdate */));
         mStackScroller = stackScroller;
-        panelView.addTrackingHeadsUpListener(this::setTrackingHeadsUp);
-        panelView.setVerticalTranslationListener(this::updatePanelTranslation);
+        mPanelView = panelView;
+        panelView.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
+        panelView.addVerticalTranslationListener(mUpdatePanelTranslation);
         panelView.setHeadsUpAppearanceController(this);
-        mStackScroller.addOnExpandedHeightListener(this::setExpandedHeight);
-        mStackScroller.addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-                        -> updatePanelTranslation());
+        mStackScroller.addOnExpandedHeightListener(mSetExpandedHeight);
+        mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mClockView = clockView;
         mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
         mDarkIconDispatcher.addDarkReceiver(this);
     }
 
+
+    public void destroy() {
+        mHeadsUpManager.removeListener(this);
+        mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null);
+        mPanelView.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
+        mPanelView.removeVerticalTranslationListener(mUpdatePanelTranslation);
+        mPanelView.setHeadsUpAppearanceController(null);
+        mStackScroller.removeOnExpandedHeightListener(mSetExpandedHeight);
+        mStackScroller.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
+        mDarkIconDispatcher.removeDarkReceiver(this);
+    }
+
     private void updateIsolatedIconLocation(boolean requireStateUpdate) {
         mNotificationIconAreaController.setIsolatedIconLocation(
                 mHeadsUpStatusBarView.getIconDrawingRect(), requireStateUpdate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2a1813f..d609ae7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -60,10 +60,6 @@
     private final FalsingManager mFalsingManager;
     private final DismissCallbackRegistry mDismissCallbackRegistry;
     private final Handler mHandler;
-    protected KeyguardHostView mKeyguardView;
-    protected ViewGroup mRoot;
-    private boolean mShowingSoon;
-    private int mBouncerPromptReason;
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
@@ -72,7 +68,14 @@
                 }
             };
     private final Runnable mRemoveViewRunnable = this::removeView;
+
     private int mStatusBarHeight;
+    private float mExpansion;
+    protected KeyguardHostView mKeyguardView;
+    protected ViewGroup mRoot;
+    private boolean mShowingSoon;
+    private int mBouncerPromptReason;
+    private boolean mIsAnimatingAway;
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -252,6 +255,7 @@
             mKeyguardView.cancelDismissAction();
             mKeyguardView.cleanUp();
         }
+        mIsAnimatingAway = false;
         if (mRoot != null) {
             mRoot.setVisibility(View.INVISIBLE);
             if (destroyView) {
@@ -267,6 +271,7 @@
      * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
      */
     public void startPreHideAnimation(Runnable runnable) {
+        mIsAnimatingAway = true;
         if (mKeyguardView != null) {
             mKeyguardView.startDisappearAnimation(runnable);
         } else if (runnable != null) {
@@ -290,7 +295,16 @@
     }
 
     public boolean isShowing() {
-        return mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE);
+        return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
+                && mExpansion == 0;
+    }
+
+    /**
+     * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
+     *         hidden yet, {@code false} otherwise.
+     */
+    public boolean isAnimatingAway() {
+        return mIsAnimatingAway;
     }
 
     public void prepare() {
@@ -308,7 +322,8 @@
      * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
      */
     public void setExpansion(float fraction) {
-        if (mKeyguardView != null) {
+        mExpansion = fraction;
+        if (mKeyguardView != null && !mIsAnimatingAway) {
             float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
             mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
             mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index fcbd37c..8fb0620 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -679,11 +679,12 @@
 
     public void updateStates() {
         updateSlippery();
+        reloadNavIcons();
         updateNavButtonIcons();
     }
 
     private void updateSlippery() {
-        setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
+        setSlippery(!isQuickStepSwipeUpEnabled() || mPanelView.isFullyExpanded());
     }
 
     private void setSlippery(boolean slippery) {
@@ -818,8 +819,6 @@
     public void onOverviewProxyConnectionChanged(boolean isConnected) {
         updateStates();
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        reloadNavIcons();
-        updateNavButtonIcons();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6852df6..64e205d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -247,7 +247,7 @@
     private int mStackScrollerMeasuringPass;
     private ArrayList<Consumer<ExpandableNotificationRow>> mTrackingHeadsUpListeners
             = new ArrayList<>();
-    private Runnable mVerticalTranslationListener;
+    private ArrayList<Runnable> mVerticalTranslationListener = new ArrayList<>();
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
@@ -2360,6 +2360,14 @@
 
     @Override
     public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+
+        // When we're unpinning the notification via active edge they remain heads-upped,
+        // we need to make sure that an animation happens in this case, otherwise the notification
+        // will stick to the top without any interaction.
+        if (isFullyCollapsed() && headsUp.isHeadsUp()) {
+            mNotificationStackScroller.generateHeadsUpAnimation(headsUp, false);
+            headsUp.setHeadsUpIsVisible();
+        }
     }
 
     @Override
@@ -2423,8 +2431,9 @@
     protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
         mQsFrame.setTranslationX(translation);
-        if (mVerticalTranslationListener != null) {
-            mVerticalTranslationListener.run();
+        int size = mVerticalTranslationListener.size();
+        for (int i = 0; i < size; i++) {
+            mVerticalTranslationListener.get(i).run();
         }
     }
 
@@ -2736,8 +2745,16 @@
         mTrackingHeadsUpListeners.add(listener);
     }
 
-    public void setVerticalTranslationListener(Runnable verticalTranslationListener) {
-        mVerticalTranslationListener = verticalTranslationListener;
+    public void removeTrackingHeadsUpListener(Consumer<ExpandableNotificationRow> listener) {
+        mTrackingHeadsUpListeners.remove(listener);
+    }
+
+    public void addVerticalTranslationListener(Runnable verticalTranslationListener) {
+        mVerticalTranslationListener.add(verticalTranslationListener);
+    }
+
+    public void removeVerticalTranslationListener(Runnable verticalTranslationListener) {
+        mVerticalTranslationListener.remove(verticalTranslationListener);
     }
 
     public void setHeadsUpAppearanceController(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index b448967..c4d7e72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -28,6 +28,7 @@
     public static final String TAG = PanelBar.class.getSimpleName();
     private static final boolean SPEW = false;
     private boolean mBouncerShowing;
+    private boolean mExpanded;
 
     public static final void LOG(String fmt, Object... args) {
         if (!DEBUG) return;
@@ -71,10 +72,15 @@
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
 
         setImportantForAccessibility(important);
+        updateVisibility();
 
         if (mPanel != null) mPanel.setImportantForAccessibility(important);
     }
 
+    private void updateVisibility() {
+        mPanel.setVisibility(mExpanded || mBouncerShowing ? VISIBLE : INVISIBLE);
+    }
+
     public boolean panelEnabled() {
         return true;
     }
@@ -124,7 +130,8 @@
         boolean fullyOpened = false;
         if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
         PanelView pv = mPanel;
-        pv.setVisibility(expanded || mBouncerShowing ? VISIBLE : INVISIBLE);
+        mExpanded = expanded;
+        updateVisibility();
         // adjust any other panels that may be partially visible
         if (expanded) {
             if (mState == STATE_CLOSED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 19544b1..9abbfb83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -352,7 +352,7 @@
 
     @Override
     public void onDraw(Canvas canvas) {
-        if (mNavigationBarView.isQuickScrubEnabled()) {
+        if (!mNavigationBarView.isQuickScrubEnabled()) {
             return;
         }
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index feb7dc3..e6a9b46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -95,6 +95,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
@@ -209,6 +210,7 @@
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -604,6 +606,8 @@
     private View mNavigationBarView;
     protected ActivityLaunchAnimator mActivityLaunchAnimator;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
+    private boolean mVibrateOnOpening;
+    private VibratorHelper mVibratorHelper;
 
     @Override
     public void start() {
@@ -641,6 +645,9 @@
         updateDisplaySize();
 
         Resources res = mContext.getResources();
+        mVibrateOnOpening = mContext.getResources().getBoolean(
+                R.bool.config_vibrateOnIconAnimation);
+        mVibratorHelper = Dependency.get(VibratorHelper.class);
         mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
         mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
 
@@ -809,6 +816,10 @@
                     mStatusBarView.setPanel(mNotificationPanel);
                     mStatusBarView.setScrimController(mScrimController);
                     mStatusBarView.setBouncerShowing(mBouncerShowing);
+                    if (mHeadsUpAppearanceController != null) {
+                        // This view is being recreated, let's destroy the old one
+                        mHeadsUpAppearanceController.destroy();
+                    }
                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);
                     setAreThereNotifications();
@@ -2153,6 +2164,9 @@
         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
             if (mNotificationPanel.isFullyCollapsed()) {
+                if (mVibrateOnOpening) {
+                    mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+                }
                 mNotificationPanel.expand(true /* animate */);
                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
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 a9c467e..56a7b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -150,8 +150,7 @@
             mBouncer.setExpansion(expansion);
             if (expansion == 1) {
                 mBouncer.onFullyHidden();
-                updateStates();
-            } else if (!mBouncer.isShowing()) {
+            } else if (!mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
                 mBouncer.show(true /* resetSecuritySelection */, false /* notifyFalsing */);
             } else if (noLongerTracking) {
                 // Notify that falsing manager should stop its session when user stops touching,
@@ -159,6 +158,9 @@
                 // data.
                 mBouncer.onFullyShown();
             }
+            if (expansion == 0 || expansion == 1) {
+                updateStates();
+            }
         }
         mLastTracking = tracking;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 49f880c..7221efa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.fuelgauge.BatterySaverUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -93,7 +94,7 @@
 
     @Override
     public void setPowerSaveMode(boolean powerSave) {
-        mPowerManager.setPowerSaveMode(powerSave);
+        BatterySaverUtils.setPowerSaveMode(mContext, powerSave, /*needFirstTimeWarning*/ true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index b22ce18..0adb439 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -64,6 +64,7 @@
             .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
             .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
             .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+            .setUids(null)
             .build();
     private static final int NO_NETWORK = -1;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
index a36c966..f98b3d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationRoundnessManager.java
@@ -47,6 +47,11 @@
         updateRounding(headsUp, true /* animate */);
     }
 
+    public void onHeadsupAnimatingAwayChanged(ExpandableNotificationRow row,
+            boolean isAnimatingAway) {
+        updateRounding(row, false /* animate */);
+    }
+
     private void updateRounding(ActivatableNotificationView view, boolean animate) {
         float topRoundness = getRoundness(view, true /* top */);
         float bottomRoundness = getRoundness(view, false /* top */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a572450..dc94203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -109,6 +109,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 /**
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
@@ -3022,6 +3023,12 @@
     }
 
     @Override
+    public void bindRow(ExpandableNotificationRow row) {
+        row.setHeadsUpAnimatingAwayListener(animatingAway
+                -> mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway));
+    }
+
+    @Override
     public void applyExpandAnimationParams(ExpandAnimationParameters params) {
         mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
         requestChildrenUpdate();
@@ -4525,6 +4532,13 @@
     }
 
     /**
+     * Stop a listener from listening to the expandedHeight.
+     */
+    public void removeOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
+        mExpandedHeightListeners.remove(listener);
+    }
+
+    /**
      * A listener that is notified when the empty space below the notifications is clicked on
      */
     public interface OnEmptySpaceClickListener {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
new file mode 100644
index 0000000..41b094a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings.Global;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.ImageButton;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.VolumeDialog;
+import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.VolumeDialogController.State;
+import com.android.systemui.plugins.VolumeDialogController.StreamState;
+
+/**
+ * Car version of the volume dialog.
+ *
+ * A client of VolumeDialogControllerImpl and its state model.
+ *
+ * Methods ending in "H" must be called on the (ui) handler.
+ */
+public class CarVolumeDialogImpl implements VolumeDialog {
+    private static final String TAG = Util.logTag(CarVolumeDialogImpl.class);
+
+    private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
+    private static final int UPDATE_ANIMATION_DURATION = 80;
+
+    private final Context mContext;
+    private final H mHandler = new H();
+    private final VolumeDialogController mController;
+
+    private Window mWindow;
+    private CustomDialog mDialog;
+    private ViewGroup mDialogView;
+    private ViewGroup mDialogRowsView;
+    private final List<VolumeRow> mRows = new ArrayList<>();
+    private ConfigurableTexts mConfigurableTexts;
+    private final SparseBooleanArray mDynamic = new SparseBooleanArray();
+    private final KeyguardManager mKeyguard;
+    private final Object mSafetyWarningLock = new Object();
+    private final ColorStateList mActiveSliderTint;
+    private final ColorStateList mInactiveSliderTint;
+
+    private boolean mShowing;
+
+    private int mActiveStream;
+    private int mPrevActiveStream;
+    private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
+    private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
+    private State mState;
+    private SafetyWarningDialog mSafetyWarning;
+    private boolean mHovering = false;
+    private boolean mExpanded = false;
+    private View mExpandBtn;
+
+    public CarVolumeDialogImpl(Context context) {
+        mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
+        mController = Dependency.get(VolumeDialogController.class);
+        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
+        mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
+    }
+
+    public void init(int windowType, Callback callback) {
+        initDialog();
+
+        mController.addCallback(mControllerCallbackH, mHandler);
+        mController.getState();
+    }
+
+    @Override
+    public void destroy() {
+        mController.removeCallback(mControllerCallbackH);
+        mHandler.removeCallbacksAndMessages(null);
+    }
+
+    private void initDialog() {
+        mDialog = new CustomDialog(mContext);
+
+        mConfigurableTexts = new ConfigurableTexts(mContext);
+        mHovering = false;
+        mShowing = false;
+        mWindow = mDialog.getWindow();
+        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+        mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
+            | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+        mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+            | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+        mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
+        final WindowManager.LayoutParams lp = mWindow.getAttributes();
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+        lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+        lp.windowAnimations = -1;
+        mWindow.setAttributes(lp);
+        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+        mDialog.setCanceledOnTouchOutside(true);
+        mDialog.setContentView(R.layout.car_volume_dialog);
+        mDialog.setOnShowListener(dialog -> {
+            mDialogView.setTranslationY(-mDialogView.getHeight());
+            mDialogView.setAlpha(0);
+            mDialogView.animate()
+                .alpha(1)
+                .translationY(0)
+                .setDuration(300)
+                .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
+                .start();
+        });
+        mExpandBtn = mDialog.findViewById(R.id.expand);
+        mExpandBtn.setOnClickListener(v -> {
+            mExpanded = !mExpanded;
+            updateRowsH(getActiveRow());
+        });
+        mDialogView = mDialog.findViewById(R.id.volume_dialog);
+        mDialogView.setOnHoverListener((v, event) -> {
+            int action = event.getActionMasked();
+            mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+                || (action == MotionEvent.ACTION_HOVER_MOVE);
+            rescheduleTimeoutH();
+            return true;
+        });
+
+        mDialogRowsView = mDialog.findViewById(R.id.car_volume_dialog_rows);
+
+        if (mRows.isEmpty()) {
+            addRow(AudioManager.STREAM_MUSIC,
+                R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true);
+            addRow(AudioManager.STREAM_RING,
+                R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
+            addRow(AudioManager.STREAM_ALARM,
+                R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
+        } else {
+            addExistingRows();
+        }
+
+        updateRowsH(getActiveRow());
+    }
+
+    private ColorStateList loadColorStateList(int colorResId) {
+        return ColorStateList.valueOf(mContext.getColor(colorResId));
+    }
+
+    public void setStreamImportant(int stream, boolean important) {
+        mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
+    }
+
+    public void setAutomute(boolean automute) {
+        if (mAutomute == automute) return;
+        mAutomute = automute;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    public void setSilentMode(boolean silentMode) {
+        if (mSilentMode == silentMode) return;
+        mSilentMode = silentMode;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
+        boolean defaultStream) {
+        addRow(stream, iconRes, iconMuteRes, important, defaultStream, false);
+    }
+
+    private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
+        boolean defaultStream, boolean dynamic) {
+        if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream);
+        VolumeRow row = new VolumeRow();
+        initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
+        mDialogRowsView.addView(row.view);
+        mRows.add(row);
+    }
+
+    private void addExistingRows() {
+        int N = mRows.size();
+        for (int i = 0; i < N; i++) {
+            final VolumeRow row = mRows.get(i);
+            initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important,
+                row.defaultStream);
+            mDialogRowsView.addView(row.view);
+            updateVolumeRowH(row);
+        }
+    }
+
+    private VolumeRow getActiveRow() {
+        for (VolumeRow row : mRows) {
+            if (row.stream == mActiveStream) {
+                return row;
+            }
+        }
+        return mRows.get(0);
+    }
+
+    private VolumeRow findRow(int stream) {
+        for (VolumeRow row : mRows) {
+            if (row.stream == stream) return row;
+        }
+        return null;
+    }
+
+    public void dump(PrintWriter writer) {
+        writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
+        writer.print("  mShowing: "); writer.println(mShowing);
+        writer.print("  mActiveStream: "); writer.println(mActiveStream);
+        writer.print("  mDynamic: "); writer.println(mDynamic);
+        writer.print("  mAutomute: "); writer.println(mAutomute);
+        writer.print("  mSilentMode: "); writer.println(mSilentMode);
+    }
+
+    private static int getImpliedLevel(SeekBar seekBar, int progress) {
+        final int m = seekBar.getMax();
+        final int n = m / 100 - 1;
+        final int level = progress == 0 ? 0
+            : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+        return level;
+    }
+
+    @SuppressLint("InflateParams")
+    private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
+        boolean important, boolean defaultStream) {
+        row.stream = stream;
+        row.iconRes = iconRes;
+        row.iconMuteRes = iconMuteRes;
+        row.important = important;
+        row.defaultStream = defaultStream;
+        row.view = mDialog.getLayoutInflater().inflate(R.layout.car_volume_dialog_row, null);
+        row.view.setId(row.stream);
+        row.view.setTag(row);
+        row.slider =  row.view.findViewById(R.id.volume_row_slider);
+        row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
+        row.anim = null;
+
+        row.icon = row.view.findViewById(R.id.volume_row_icon);
+        row.icon.setImageResource(iconRes);
+    }
+
+    public void show(int reason) {
+        mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
+    }
+
+    public void dismiss(int reason) {
+        mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget();
+    }
+
+    private void showH(int reason) {
+        if (D.BUG) Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]);
+        mHandler.removeMessages(H.SHOW);
+        mHandler.removeMessages(H.DISMISS);
+        rescheduleTimeoutH();
+        if (mShowing) return;
+        mShowing = true;
+
+        mDialog.show();
+        Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
+        mController.notifyVisible(true);
+    }
+
+    protected void rescheduleTimeoutH() {
+        mHandler.removeMessages(H.DISMISS);
+        final int timeout = computeTimeoutH();
+        mHandler.sendMessageDelayed(mHandler
+            .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
+        if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
+        mController.userActivity();
+    }
+
+    private int computeTimeoutH() {
+        if (mHovering) return 16000;
+        if (mSafetyWarning != null) return 5000;
+        return 3000;
+    }
+
+    protected void dismissH(int reason) {
+        mHandler.removeMessages(H.DISMISS);
+        mHandler.removeMessages(H.SHOW);
+        if (!mShowing) return;
+        mDialogView.animate().cancel();
+        mShowing = false;
+
+        mDialogView.setTranslationY(0);
+        mDialogView.setAlpha(1);
+        mDialogView.animate()
+            .alpha(0)
+            .translationY(-mDialogView.getHeight())
+            .setDuration(250)
+            .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+            .withEndAction(() -> mHandler.postDelayed(() -> {
+                if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
+                mDialog.dismiss();
+            }, 50))
+            .start();
+
+        Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
+        mController.notifyVisible(false);
+        synchronized (mSafetyWarningLock) {
+            if (mSafetyWarning != null) {
+                if (D.BUG) Log.d(TAG, "SafetyWarning dismissed");
+                mSafetyWarning.dismiss();
+            }
+        }
+    }
+
+    private boolean shouldBeVisibleH(VolumeRow row) {
+        if (mExpanded) {
+            return true;
+        }
+        return row.defaultStream;
+    }
+
+    private void updateRowsH(final VolumeRow activeRow) {
+        if (D.BUG) Log.d(TAG, "updateRowsH");
+        if (!mShowing) {
+            trimObsoleteH();
+        }
+        // apply changes to all rows
+        for (final VolumeRow row : mRows) {
+            final boolean isActive = row == activeRow;
+            final boolean shouldBeVisible = shouldBeVisibleH(row);
+            Util.setVisOrGone(row.view, shouldBeVisible);
+            if (row.view.isShown()) {
+                updateVolumeRowSliderTintH(row, isActive);
+            }
+        }
+    }
+
+    private void trimObsoleteH() {
+        if (D.BUG) Log.d(TAG, "trimObsoleteH");
+        for (int i = mRows.size() - 1; i >= 0; i--) {
+            final VolumeRow row = mRows.get(i);
+            if (row.ss == null || !row.ss.dynamic) continue;
+            if (!mDynamic.get(row.stream)) {
+                mRows.remove(i);
+                mDialogRowsView.removeView(row.view);
+            }
+        }
+    }
+
+    protected void onStateChangedH(State state) {
+        mState = state;
+        mDynamic.clear();
+        // add any new dynamic rows
+        for (int i = 0; i < state.states.size(); i++) {
+            final int stream = state.states.keyAt(i);
+            final StreamState ss = state.states.valueAt(i);
+            if (!ss.dynamic) continue;
+            mDynamic.put(stream, true);
+            if (findRow(stream) == null) {
+                addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true,
+                    false, true);
+            }
+        }
+
+        if (mActiveStream != state.activeStream) {
+            mPrevActiveStream = mActiveStream;
+            mActiveStream = state.activeStream;
+            updateRowsH(getActiveRow());
+            rescheduleTimeoutH();
+        }
+        for (VolumeRow row : mRows) {
+            updateVolumeRowH(row);
+        }
+
+    }
+
+    private void updateVolumeRowH(VolumeRow row) {
+        if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream);
+        if (mState == null) return;
+        final StreamState ss = mState.states.get(row.stream);
+        if (ss == null) return;
+        row.ss = ss;
+        if (ss.level > 0) {
+            row.lastAudibleLevel = ss.level;
+        }
+        if (ss.level == row.requestedLevel) {
+            row.requestedLevel = -1;
+        }
+        final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
+        final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
+        final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
+        final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
+        final boolean isRingVibrate = isRingStream
+            && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
+        final boolean isRingSilent = isRingStream
+            && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
+        final boolean isZenPriorityOnly = mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
+        final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
+            : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream)
+                : isZenPriorityOnly ? ((isAlarmStream && mState.disallowAlarms) ||
+                    (isMusicStream && mState.disallowMedia) ||
+                    (isRingStream && mState.disallowRinger) ||
+                    (isSystemStream && mState.disallowSystem))
+                    : false;
+
+        // update slider max
+        final int max = ss.levelMax * 100;
+        if (max != row.slider.getMax()) {
+            row.slider.setMax(max);
+        }
+
+        // update icon
+        final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
+        row.icon.setEnabled(iconEnabled);
+        row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
+        final int iconRes =
+            isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
+                : isRingSilent || zenMuted ? row.iconMuteRes
+                    : ss.routedToBluetooth ?
+                        (ss.muted ? R.drawable.ic_volume_media_bt_mute
+                            : R.drawable.ic_volume_media_bt)
+                        : mAutomute && ss.level == 0 ? row.iconMuteRes
+                            : (ss.muted ? row.iconMuteRes : row.iconRes);
+        row.icon.setImageResource(iconRes);
+        row.iconState =
+            iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
+                : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
+                    ? Events.ICON_STATE_MUTE
+                    : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes)
+                        ? Events.ICON_STATE_UNMUTE
+                        : Events.ICON_STATE_UNKNOWN;
+        if (iconEnabled) {
+            if (isRingStream) {
+                if (isRingVibrate) {
+                    row.icon.setContentDescription(mContext.getString(
+                        R.string.volume_stream_content_description_unmute,
+                        getStreamLabelH(ss)));
+                } else {
+                    if (mController.hasVibrator()) {
+                        row.icon.setContentDescription(mContext.getString(
+                            R.string.volume_stream_content_description_vibrate,
+                            getStreamLabelH(ss)));
+                    } else {
+                        row.icon.setContentDescription(mContext.getString(
+                            R.string.volume_stream_content_description_mute,
+                            getStreamLabelH(ss)));
+                    }
+                }
+            } else {
+                if (ss.muted || mAutomute && ss.level == 0) {
+                    row.icon.setContentDescription(mContext.getString(
+                        R.string.volume_stream_content_description_unmute,
+                        getStreamLabelH(ss)));
+                } else {
+                    row.icon.setContentDescription(mContext.getString(
+                        R.string.volume_stream_content_description_mute,
+                        getStreamLabelH(ss)));
+                }
+            }
+        } else {
+            row.icon.setContentDescription(getStreamLabelH(ss));
+        }
+
+        // ensure tracking is disabled if zenMuted
+        if (zenMuted) {
+            row.tracking = false;
+        }
+
+        // update slider
+        final boolean enableSlider = !zenMuted;
+        final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0
+            : row.ss.level;
+        updateVolumeRowSliderH(row, enableSlider, vlevel);
+    }
+
+    private String getStreamLabelH(StreamState ss) {
+        if (ss.remoteLabel != null) {
+            return ss.remoteLabel;
+        }
+        try {
+            return mContext.getResources().getString(ss.name);
+        } catch (Resources.NotFoundException e) {
+            Slog.e(TAG, "Can't find translation for stream " + ss);
+            return "";
+        }
+    }
+
+    private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
+        if (isActive) {
+            row.slider.requestFocus();
+        }
+        final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
+            : mInactiveSliderTint;
+        if (tint == row.cachedSliderTint) return;
+        row.cachedSliderTint = tint;
+        row.slider.setProgressTintList(tint);
+        row.slider.setThumbTintList(tint);
+    }
+
+    private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) {
+        row.slider.setEnabled(enable);
+        updateVolumeRowSliderTintH(row, row.stream == mActiveStream);
+        if (row.tracking) {
+            return;  // don't update if user is sliding
+        }
+        final int progress = row.slider.getProgress();
+        final int level = getImpliedLevel(row.slider, progress);
+        final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
+        final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
+            < USER_ATTEMPT_GRACE_PERIOD;
+        mHandler.removeMessages(H.RECHECK, row);
+        if (mShowing && rowVisible && inGracePeriod) {
+            if (D.BUG) Log.d(TAG, "inGracePeriod");
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(H.RECHECK, row),
+                row.userAttempt + USER_ATTEMPT_GRACE_PERIOD);
+            return;  // don't update if visible and in grace period
+        }
+        if (vlevel == level) {
+            if (mShowing && rowVisible) {
+                return;  // don't clamp if visible
+            }
+        }
+        final int newProgress = vlevel * 100;
+        if (progress != newProgress) {
+            if (mShowing && rowVisible) {
+                // animate!
+                if (row.anim != null && row.anim.isRunning()
+                    && row.animTargetProgress == newProgress) {
+                    return;  // already animating to the target progress
+                }
+                // start/update animation
+                if (row.anim == null) {
+                    row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
+                    row.anim.setInterpolator(new DecelerateInterpolator());
+                } else {
+                    row.anim.cancel();
+                    row.anim.setIntValues(progress, newProgress);
+                }
+                row.animTargetProgress = newProgress;
+                row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+                row.anim.start();
+            } else {
+                // update slider directly to clamped value
+                if (row.anim != null) {
+                    row.anim.cancel();
+                }
+                row.slider.setProgress(newProgress, true);
+            }
+        }
+    }
+
+    private void recheckH(VolumeRow row) {
+        if (row == null) {
+            if (D.BUG) Log.d(TAG, "recheckH ALL");
+            trimObsoleteH();
+            for (VolumeRow r : mRows) {
+                updateVolumeRowH(r);
+            }
+        } else {
+            if (D.BUG) Log.d(TAG, "recheckH " + row.stream);
+            updateVolumeRowH(row);
+        }
+    }
+
+    private void setStreamImportantH(int stream, boolean important) {
+        for (VolumeRow row : mRows) {
+            if (row.stream == stream) {
+                row.important = important;
+                return;
+            }
+        }
+    }
+
+    private void showSafetyWarningH(int flags) {
+        if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0
+            || mShowing) {
+            synchronized (mSafetyWarningLock) {
+                if (mSafetyWarning != null) {
+                    return;
+                }
+                mSafetyWarning = new SafetyWarningDialog(mContext, mController.getAudioManager()) {
+                    @Override
+                    protected void cleanUp() {
+                        synchronized (mSafetyWarningLock) {
+                            mSafetyWarning = null;
+                        }
+                        recheckH(null);
+                    }
+                };
+                mSafetyWarning.show();
+            }
+            recheckH(null);
+        }
+        rescheduleTimeoutH();
+    }
+
+    private final VolumeDialogController.Callbacks mControllerCallbackH
+        = new VolumeDialogController.Callbacks() {
+        @Override
+        public void onShowRequested(int reason) {
+            showH(reason);
+        }
+
+        @Override
+        public void onDismissRequested(int reason) {
+            dismissH(reason);
+        }
+
+        @Override
+        public void onScreenOff() {
+            dismissH(Events.DISMISS_REASON_SCREEN_OFF);
+        }
+
+        @Override
+        public void onStateChanged(State state) {
+            onStateChangedH(state);
+        }
+
+        @Override
+        public void onLayoutDirectionChanged(int layoutDirection) {
+            mDialogView.setLayoutDirection(layoutDirection);
+        }
+
+        @Override
+        public void onConfigurationChanged() {
+            mDialog.dismiss();
+            initDialog();
+            mConfigurableTexts.update();
+        }
+
+        @Override
+        public void onShowVibrateHint() {
+            if (mSilentMode) {
+                mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
+            }
+        }
+
+        @Override
+        public void onShowSilentHint() {
+            if (mSilentMode) {
+                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+            }
+        }
+
+        @Override
+        public void onShowSafetyWarning(int flags) {
+            showSafetyWarningH(flags);
+        }
+
+        @Override
+        public void onAccessibilityModeChanged(Boolean showA11yStream) {
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int SHOW = 1;
+        private static final int DISMISS = 2;
+        private static final int RECHECK = 3;
+        private static final int RECHECK_ALL = 4;
+        private static final int SET_STREAM_IMPORTANT = 5;
+        private static final int RESCHEDULE_TIMEOUT = 6;
+        private static final int STATE_CHANGED = 7;
+
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SHOW: showH(msg.arg1); break;
+                case DISMISS: dismissH(msg.arg1); break;
+                case RECHECK: recheckH((VolumeRow) msg.obj); break;
+                case RECHECK_ALL: recheckH(null); break;
+                case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break;
+                case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
+                case STATE_CHANGED: onStateChangedH(mState); break;
+            }
+        }
+    }
+
+    private final class CustomDialog extends Dialog implements DialogInterface {
+        public CustomDialog(Context context) {
+            super(context, com.android.systemui.R.style.qs_theme);
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            rescheduleTimeoutH();
+            return super.dispatchTouchEvent(ev);
+        }
+
+        @Override
+        protected void onStart() {
+            super.setCanceledOnTouchOutside(true);
+            super.onStart();
+        }
+
+        @Override
+        protected void onStop() {
+            super.onStop();
+            mHandler.sendEmptyMessage(H.RECHECK_ALL);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            if (isShowing()) {
+                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                    dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
+        private final VolumeRow mRow;
+
+        private VolumeSeekBarChangeListener(VolumeRow row) {
+            mRow = row;
+        }
+
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            if (mRow.ss == null) return;
+            if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream)
+                + " onProgressChanged " + progress + " fromUser=" + fromUser);
+            if (!fromUser) return;
+            if (mRow.ss.levelMin > 0) {
+                final int minProgress = mRow.ss.levelMin * 100;
+                if (progress < minProgress) {
+                    seekBar.setProgress(minProgress);
+                    progress = minProgress;
+                }
+            }
+            final int userLevel = getImpliedLevel(seekBar, progress);
+            if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
+                mRow.userAttempt = SystemClock.uptimeMillis();
+                if (mRow.requestedLevel != userLevel) {
+                    mController.setStreamVolume(mRow.stream, userLevel);
+                    mRow.requestedLevel = userLevel;
+                    Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
+                        userLevel);
+                }
+            }
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream);
+            mController.setActiveStream(mRow.stream);
+            mRow.tracking = true;
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
+            mRow.tracking = false;
+            mRow.userAttempt = SystemClock.uptimeMillis();
+            final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
+            Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
+            if (mRow.ss.level != userLevel) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
+                    USER_ATTEMPT_GRACE_PERIOD);
+            }
+        }
+    }
+
+    private static class VolumeRow {
+        private View view;
+        private ImageButton icon;
+        private SeekBar slider;
+        private int stream;
+        private StreamState ss;
+        private long userAttempt;  // last user-driven slider change
+        private boolean tracking;  // tracking slider touch
+        private int requestedLevel = -1;  // pending user-requested level via progress changed
+        private int iconRes;
+        private int iconMuteRes;
+        private boolean important;
+        private boolean defaultStream;
+        private ColorStateList cachedSliderTint;
+        private int iconState;  // from Events
+        private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
+        private int animTargetProgress;
+        private int lastAudibleLevel = 1;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 0203c43..6e5b548 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.media.VolumePolicy;
@@ -80,6 +81,7 @@
         Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
                 .withPlugin(VolumeDialog.class)
                 .withDefault(this::createDefault)
+                .withFeature(PackageManager.FEATURE_AUTOMOTIVE, this::createCarDefault)
                 .withCallback(dialog -> {
                     if (mDialog != null) {
                         mDialog.destroy();
@@ -100,6 +102,14 @@
         return impl;
     }
 
+    private VolumeDialog createCarDefault() {
+        CarVolumeDialogImpl impl = new CarVolumeDialogImpl(mContext);
+        impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
+        impl.setAutomute(true);
+        impl.setSilentMode(false);
+        return impl;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (VOLUME_DOWN_SILENT.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e94d6bd..1c8a26c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -451,11 +451,11 @@
                 toastText = R.string.volume_dialog_ringer_guidance_ring;
                 break;
             case RINGER_MODE_SILENT:
-                toastText = R.string.volume_dialog_ringer_guidance_silent;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
                 break;
             case RINGER_MODE_VIBRATE:
             default:
-                toastText = R.string.volume_dialog_ringer_guidance_vibrate;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
         }
 
         Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index ebb088b..107ce1e 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -40,6 +40,7 @@
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
     SystemUISharedLib \
+    android-support-car \
     android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index 34e444e..231a1866 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -40,17 +40,22 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.function.Consumer;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ExpandableNotificationRowTest extends SysuiTestCase {
 
     private ExpandableNotificationRow mGroup;
     private NotificationTestHelper mNotificationTestHelper;
+    boolean mHeadsUpAnimatingAway = false;
 
     @Before
     public void setUp() throws Exception {
         mNotificationTestHelper = new NotificationTestHelper(mContext);
         mGroup = mNotificationTestHelper.createGroup();
+        mGroup.setHeadsUpAnimatingAwayListener(
+                animatingAway -> mHeadsUpAnimatingAway = animatingAway);
     }
 
     @Test
@@ -195,4 +200,12 @@
         mGroup.getAppOpsOnClickListener().onClick(view);
         verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any());
     }
+
+    @Test
+    public void testHeadsUpAnimatingAwayListener() {
+        mGroup.setHeadsUpAnimatingAway(true);
+        Assert.assertEquals(true, mHeadsUpAnimatingAway);
+        mGroup.setHeadsUpAnimatingAway(false);
+        Assert.assertEquals(false, mHeadsUpAnimatingAway);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index c904ef3..7a61bfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -16,8 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -26,6 +29,7 @@
 import android.view.View;
 import android.widget.TextView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.TestableDependency;
 import com.android.systemui.statusbar.CommandQueue;
@@ -46,6 +50,10 @@
 @RunWith(AndroidJUnit4.class)
 public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
 
+    private final NotificationStackScrollLayout mStackScroller =
+            mock(NotificationStackScrollLayout.class);
+    private final NotificationPanelView mPanelView = mock(NotificationPanelView.class);
+    private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private ExpandableNotificationRow mFirst;
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
@@ -55,7 +63,7 @@
     public void setUp() throws Exception {
         NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
         mFirst = testHelper.createRow();
-        mDependency.injectMockDependency(DarkIconDispatcher.class);
+        mDependency.injectTestDependency(DarkIconDispatcher.class, mDarkIconDispatcher);
         mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
                 mock(TextView.class));
         mHeadsUpManager = mock(HeadsUpManagerPhone.class);
@@ -63,8 +71,8 @@
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
                 mHeadsUpStatusBarView,
-                mock(NotificationStackScrollLayout.class),
-                mock(NotificationPanelView.class),
+                mStackScroller,
+                mPanelView,
                 new View(mContext));
         mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
     }
@@ -110,4 +118,20 @@
         mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
         Assert.assertEquals(mFirst.getHeaderVisibleAmount(), 1.0f, 0.0f);
     }
+
+    @Test
+    public void testDestroy() {
+        reset(mHeadsUpManager);
+        reset(mDarkIconDispatcher);
+        reset(mPanelView);
+        reset(mStackScroller);
+        mHeadsUpAppearanceController.destroy();
+        verify(mHeadsUpManager).removeListener(any());
+        verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any());
+        verify(mPanelView).removeVerticalTranslationListener(any());
+        verify(mPanelView).removeTrackingHeadsUpListener(any());
+        verify(mPanelView).setHeadsUpAppearanceController(any());
+        verify(mStackScroller).removeOnExpandedHeightListener(any());
+        verify(mStackScroller).removeOnLayoutChangeListener(any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index f3a8417..a37947d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -22,8 +22,6 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.calls;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
@@ -238,9 +236,19 @@
     }
 
     @Test
-    public void testIsShowing() {
+    public void testIsShowing_animated() {
         Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing());
-        mBouncer.show(true);
+        mBouncer.show(true /* reset */);
+        Assert.assertTrue("Should be showing", mBouncer.isShowing());
+    }
+
+    @Test
+    public void testIsShowing_forSwipeUp() {
+        mBouncer.setExpansion(1f);
+        mBouncer.show(true /* reset */, false /* animated */);
+        Assert.assertFalse("Should only be showing after collapsing notification panel",
+                mBouncer.isShowing());
+        mBouncer.setExpansion(0f);
         Assert.assertTrue("Should be showing", mBouncer.isShowing());
     }
 
@@ -269,6 +277,25 @@
     }
 
     @Test
+    public void testIsHiding_preHideOrHide() {
+        Assert.assertFalse("Should not be hiding on initial state", mBouncer.isAnimatingAway());
+        mBouncer.startPreHideAnimation(null /* runnable */);
+        Assert.assertTrue("Should be hiding during pre-hide", mBouncer.isAnimatingAway());
+        mBouncer.hide(false /* destroyView */);
+        Assert.assertFalse("Should be hidden after hide()", mBouncer.isAnimatingAway());
+    }
+
+    @Test
+    public void testIsHiding_skipsTranslation() {
+        mBouncer.show(false /* reset */);
+        reset(mKeyguardHostView);
+        mBouncer.startPreHideAnimation(null /* runnable */);
+        mBouncer.setExpansion(0.5f);
+        verify(mKeyguardHostView, never()).setTranslationY(anyFloat());
+        verify(mKeyguardHostView, never()).setAlpha(anyFloat());
+    }
+
+    @Test
     public void testIsSecure() {
         Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 7ca9d73..f76de5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -19,11 +19,15 @@
 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.anyInt;
+import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -32,6 +36,9 @@
 import android.content.pm.StringParceledListSlice;
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.UserManager;
 import android.security.IKeyChainService;
 import android.support.test.runner.AndroidJUnit4;
@@ -61,6 +68,7 @@
     private final UserManager mUserManager = mock(UserManager.class);
     private SecurityControllerImpl mSecurityController;
     private CountDownLatch mStateChangedLatch;
+    private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class);
 
     // implementing SecurityControllerCallback
     @Override
@@ -72,7 +80,7 @@
     public void setUp() throws Exception {
         mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
         mContext.addMockSystemService(Context.USER_SERVICE, mUserManager);
-        mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mock(ConnectivityManager.class));
+        mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mConnectivityManager);
 
         Intent intent = new Intent(IKeyChainService.class.getName());
         ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
@@ -176,4 +184,12 @@
         //assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS));
         //assertFalse(mSecurityController.hasCACertInCurrentUser());
     }
+
+    @Test
+    public void testNetworkRequest() {
+        verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat(
+                (NetworkRequest request) -> request.networkCapabilities.getUids() == null
+                        && request.networkCapabilities.getCapabilities().length == 0
+                ), any(NetworkCallback.class));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
index 1d2c01d..28d1aff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationRoundnessManagerTest.java
@@ -46,6 +46,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.HashSet;
+import java.util.function.Consumer;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -61,7 +62,11 @@
     public void setUp() throws Exception {
         NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
         mFirst = testHelper.createRow();
+        mFirst.setHeadsUpAnimatingAwayListener(animatingAway
+                -> mRoundnessManager.onHeadsupAnimatingAwayChanged(mFirst, animatingAway));
         mSecond = testHelper.createRow();
+        mSecond.setHeadsUpAnimatingAwayListener(animatingAway
+                -> mRoundnessManager.onHeadsupAnimatingAwayChanged(mSecond, animatingAway));
         mRoundnessManager.setOnRoundingChangedCallback(mRoundnessCallback);
         mRoundnessManager.setAnimatedChildren(mAnimatedChildren);
         mRoundnessManager.setFirstAndLastBackgroundChild(mFirst, mFirst);
@@ -153,4 +158,24 @@
         Assert.assertEquals(0.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
         Assert.assertEquals(0.0f, mFirst.getCurrentTopRoundness(), 0.0f);
     }
+
+    @Test
+    public void testRoundingUpdatedWhenAnimatingAwayTrue() {
+        mRoundnessManager.setExpanded(0.0f, 0.0f);
+        mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
+        mFirst.setHeadsUpAnimatingAway(true);
+        Assert.assertEquals(1.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
+        Assert.assertEquals(1.0f, mFirst.getCurrentTopRoundness(), 0.0f);
+    }
+
+
+    @Test
+    public void testRoundingUpdatedWhenAnimatingAwayFalse() {
+        mRoundnessManager.setExpanded(0.0f, 0.0f);
+        mRoundnessManager.setFirstAndLastBackgroundChild(mSecond, mSecond);
+        mFirst.setHeadsUpAnimatingAway(true);
+        mFirst.setHeadsUpAnimatingAway(false);
+        Assert.assertEquals(0.0f, mFirst.getCurrentBottomRoundness(), 0.0f);
+        Assert.assertEquals(0.0f, mFirst.getCurrentTopRoundness(), 0.0f);
+    }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0cc60e3..9417f04 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3964,7 +3964,8 @@
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned (only in success case)
+    // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned in the response, or -1 if
+    // the service returned a null response.
     // NOTE: starting on OS P, it also added:
     // Type TYPE_CLOSE: Service returned a null response.
     // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
@@ -5541,6 +5542,11 @@
     // OS: P
     FIELD_ANOMALY_TYPE = 1366;
 
+    // ACTION: Settings > Anomaly receiver > Anomaly received
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ANOMALY_TRIGGERED = 1367;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 0763fa1..39d0070 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1134,14 +1134,38 @@
     NUM_CLIENTS_CHANGED = 2;
   }
 
+  // Soft AP channel bandwidth types
+  enum ChannelBandwidth {
+
+    BANDWIDTH_INVALID = 0;
+
+    BANDWIDTH_20_NOHT = 1;
+
+    BANDWIDTH_20 = 2;
+
+    BANDWIDTH_40 = 3;
+
+    BANDWIDTH_80 = 4;
+
+    BANDWIDTH_80P80 = 5;
+
+    BANDWIDTH_160 = 6;
+  }
+
   // Type of event being recorded
   optional SoftApEventType event_type = 1;
 
-  // Absolute time when event happened
+  // Time passed since last boot in milliseconds
   optional int64 time_stamp_millis = 2;
 
   // Number of connected clients if event_type is NUM_CLIENTS_CHANGED, otherwise zero.
   optional int32 num_connected_clients = 3;
+
+  // Channel frequency used for Soft AP
+  optional int32 channel_frequency = 4;
+
+  // Channel bandwidth used for Soft AP
+  optional ChannelBandwidth channel_bandwidth = 5;
 }
 
 // Wps connection metrics
diff --git a/services/art-profile b/services/art-profile
index d2cde02..93e580a 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -10677,7 +10677,6 @@
 PLcom/android/server/location/CountryDetectorBase;-><init>(Landroid/content/Context;)V
 PLcom/android/server/location/CountryDetectorBase;->notifyListener(Landroid/location/Country;)V
 PLcom/android/server/location/CountryDetectorBase;->setCountryListener(Landroid/location/CountryListener;)V
-PLcom/android/server/location/FlpHardwareProvider;->isSupported()Z
 PLcom/android/server/location/GeocoderProxy;-><init>(Landroid/content/Context;IIILandroid/os/Handler;)V
 PLcom/android/server/location/GeocoderProxy;->bind()Z
 PLcom/android/server/location/GeocoderProxy;->createAndBind(Landroid/content/Context;IIILandroid/os/Handler;)Lcom/android/server/location/GeocoderProxy;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a5339e0..009e723 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -80,6 +80,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.autofill.AutofillManagerService.PackageCompatState;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.FileDescriptor;
@@ -108,10 +109,6 @@
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
 
-    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
-    private static final List<String> DEFAULT_BUTTONS = Arrays.asList("url_bar",
-            "location_bar_edit_text");
-
     private final Context mContext;
     private final AutoFillUI mUi;
 
@@ -575,7 +572,7 @@
     private String getWhitelistedCompatModePackagesFromSettings() {
         return Settings.Global.getString(
                 mContext.getContentResolver(),
-                Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+                Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
     }
 
     @Nullable
@@ -600,7 +597,7 @@
             final List<String> urlBarIds;
             if (urlBlockIndex == -1) {
                 packageName = packageBlock;
-                urlBarIds = DEFAULT_BUTTONS; // TODO(b/74445943): back to null
+                urlBarIds = null;
             } else {
                 if (packageBlock.charAt(packageBlock.length() - 1)
                         != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
@@ -655,7 +652,7 @@
     /**
      * Compatibility mode metadata per package.
      */
-    private static final class PackageCompatState {
+    static final class PackageCompatState {
         private final long maxVersionCode;
         private final String[] urlBarResourceIds;
 
@@ -666,8 +663,8 @@
 
         @Override
         public String toString() {
-            return "PackageCompatState: [maxVersionCode=" + maxVersionCode
-                    + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]";
+            return "maxVersionCode=" + maxVersionCode
+                    + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds);
         }
     }
 
@@ -756,6 +753,25 @@
                 }
             }
         }
+
+        private void dump(String prefix, PrintWriter pw) {
+             if (mUserSpecs == null) {
+                 pw.println("N/A");
+                 return;
+             }
+             pw.println();
+             final String prefix2 = prefix + "  ";
+             for (int i = 0; i < mUserSpecs.size(); i++) {
+                 final int user = mUserSpecs.keyAt(i);
+                 pw.print(prefix); pw.print("User: "); pw.println(user);
+                 final ArrayMap<String,PackageCompatState> perUser = mUserSpecs.get(i);
+                 for (int j = 0; j < perUser.size(); j++) {
+                     final String packageName = perUser.keyAt(j);
+                     final PackageCompatState state = perUser.valueAt(j);
+                     pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state);
+                }
+            }
+        }
     }
 
     final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@@ -1121,6 +1137,7 @@
 
             boolean oldDebug = sDebug;
             final String prefix = "  ";
+            final String prefix2 = "    ";
             try {
                 synchronized (mLock) {
                     oldDebug = sDebug;
@@ -1145,8 +1162,8 @@
                     }
                     mUi.dump(pw);
                     pw.print("Autofill Compat State: ");
-                    pw.println(mAutofillCompatState.mUserSpecs);
-                    pw.print(prefix); pw.print("from settings: ");
+                    mAutofillCompatState.dump(prefix2, pw);
+                    pw.print(prefix2); pw.print("from settings: ");
                     pw.println(getWhitelistedCompatModePackagesFromSettings());
                 }
                 if (showHistory) {
@@ -1179,7 +1196,7 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES), false, this,
+                    Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, this,
                     UserHandle.USER_ALL);
         }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 54ea3ba..ef0d7e6 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1189,7 +1189,7 @@
     boolean isFieldClassificationEnabledLocked() {
         return Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
-                Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 0,
+                Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
                 mUserId) == 1;
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5c41f3f..7bb532e 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -26,6 +26,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.WindowManager;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
@@ -107,6 +108,13 @@
     }
 
     @NonNull
+    public static String paramsToString(@NonNull WindowManager.LayoutParams params) {
+        final StringBuilder builder = new StringBuilder(25);
+        params.dumpDimensions(builder);
+        return builder.toString();
+    }
+
+    @NonNull
     static ArrayMap<AutofillId, AutofillValue> getFields(@NonNull Dataset dataset) {
         final ArrayList<AutofillId> ids = dataset.getFieldIds();
         final ArrayList<AutofillValue> values = dataset.getFieldValues();
@@ -128,7 +136,7 @@
         return log;
     }
 
-    public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable String text) {
+    public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
         if (text == null) {
             pw.println("null");
         } else {
@@ -173,6 +181,7 @@
      * @param structure Assist structure
      * @param urlBarIds list of ids; only the first id found will be sanitized.
      */
+    @Nullable
     public static void sanitizeUrlBar(@NonNull AssistStructure structure,
             @NonNull String[] urlBarIds) {
         final ViewNode urlBarNode = findViewNode(structure, (node) -> {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7f57615..1e1de35 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -596,6 +596,9 @@
             }
             if (response == null) {
                 processNullResponseLocked(requestFlags);
+                mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
+                        .setType(MetricsEvent.TYPE_SUCCESS)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1));
                 return;
             }
 
@@ -2074,8 +2077,11 @@
             if (saveTriggerId != null) {
                 writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION);
             }
-            saveOnAllViewsInvisible =
-                    (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
+            int flags = saveInfo.getFlags();
+            if (mCompatMode) {
+                flags |= SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE;
+            }
+            saveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
 
             // We only need to track views if we want to save once they become invisible.
             if (saveOnAllViewsInvisible) {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 0dbdc13..03c5850 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -206,29 +206,51 @@
 
     @Override
     public String toString() {
-        return "ViewState: [id=" + id + ", datasetId=" + mDatasetId
-                + ", currentValue=" + mCurrentValue
-                + ", autofilledValue=" + mAutofilledValue
-                + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
+        final StringBuilder builder = new StringBuilder("ViewState: [id=").append(id);
+        if (mDatasetId != null) {
+            builder.append("datasetId:" ).append(mDatasetId);
+        }
+        builder.append("state:" ).append(getStateAsString());
+        if (mCurrentValue != null) {
+            builder.append("currentValue:" ).append(mCurrentValue);
+        }
+        if (mAutofilledValue != null) {
+            builder.append("autofilledValue:" ).append(mAutofilledValue);
+        }
+        if (mSanitizedValue != null) {
+            builder.append("sanitizedValue:" ).append(mSanitizedValue);
+        }
+        if (mVirtualBounds != null) {
+            builder.append("virtualBounds:" ).append(mVirtualBounds);
+        }
+        return builder.toString();
     }
 
     void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("id:" ); pw.println(this.id);
-        pw.print(prefix); pw.print("datasetId:" ); pw.println(this.mDatasetId);
+        pw.print(prefix); pw.print("id:" ); pw.println(id);
+        if (mDatasetId != null) {
+            pw.print(prefix); pw.print("datasetId:" ); pw.println(mDatasetId);
+        }
         pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
-        pw.print(prefix); pw.print("response:");
-        if (mResponse == null) {
-            pw.println("N/A");
-        } else {
+        if (mResponse != null) {
+            pw.print(prefix); pw.print("response:");
             if (sVerbose) {
                 pw.println(mResponse);
             } else {
-                pw.println(mResponse.getRequestId());
+                pw.print("id=");pw.println(mResponse.getRequestId());
             }
         }
-        pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
-        pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
-        pw.print(prefix); pw.print("sanitizedValue:" ); pw.println(mSanitizedValue);
-        pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
+        if (mCurrentValue != null) {
+            pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
+        }
+        if (mAutofilledValue != null) {
+            pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
+        }
+        if (mSanitizedValue != null) {
+            pw.print(prefix); pw.print("sanitizedValue:" ); pw.println(mSanitizedValue);
+        }
+        if (mVirtualBounds != null) {
+            pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
+        }
     }
 }
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index ef4656b..edfc412 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.autofill.ui;
 
+import static com.android.server.autofill.Helper.paramsToString;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 
@@ -37,7 +38,6 @@
 import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -568,12 +568,24 @@
 
         @Override
         public String toString() {
-            return "ViewItem: [dataset=" + (dataset == null ? "null" : dataset.getId())
-                    + ", value=" + (value == null ? "null" : value.length() + "_chars")
-                    + ", filterable=" + filterable
-                    + ", filter=" + (filter == null ? "null" : filter.pattern().length() + "_chars")
-                    + ", view=" + view.getAutofillId()
-                    + "]";
+            final StringBuilder builder = new StringBuilder("ViewItem:[view=")
+                    .append(view.getAutofillId());
+            final String datasetId = dataset == null ? null : dataset.getId();
+            if (datasetId != null) {
+                builder.append(", dataset=").append(datasetId);
+            }
+            if (value != null) {
+                // Cannot print value because it could contain PII
+                builder.append(", value=").append(value.length()).append("_chars");
+            }
+            if (filterable) {
+                builder.append(", filterable");
+            }
+            if (filter != null) {
+                // Filter should not have PII, but it could be a huge regexp
+                builder.append(", filter=").append(filter.pattern().length()).append("_chars");
+            }
+            return builder.append(']').toString();
         }
     }
 
@@ -583,8 +595,7 @@
                 boolean fitsSystemWindows, int layoutDirection) {
             if (sVerbose) {
                 Slog.v(TAG, "AutofillWindowPresenter.show(): fit=" + fitsSystemWindows
-                        + ", epicenter="+ transitionEpicenter + ", dir=" + layoutDirection
-                        + ", params=" + p);
+                        + ", params=" + paramsToString(p));
             }
             UiThread.getHandler().post(() -> mWindow.show(p));
         }
@@ -616,7 +627,9 @@
          * Shows the window.
          */
         public void show(WindowManager.LayoutParams params) {
-            if (sVerbose) Slog.v(TAG, "show(): showing=" + mShowing + ", params="+  params);
+            if (sVerbose) {
+                Slog.v(TAG, "show(): showing=" + mShowing + ", params=" + paramsToString(params));
+            }
             try {
                 // Okay here is a bit of voodoo - we want to show the window as system
                 // controlled one so it covers app windows - adjust the params accordingly.
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 4cac707..d6f6c6c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -215,6 +215,13 @@
     // Timeout interval for deciding that a bind or clear-data has taken too long
     private static final long TIMEOUT_INTERVAL = 10 * 1000;
 
+    // Timeout intervals for agent backup & restore operations
+    public static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
+    public static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
+    public static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
+    public static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
+    public static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
+
     // User confirmation timeout for a full backup/restore operation.  It's this long in
     // order to give them time to enter the backup password.
     private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
@@ -225,7 +232,6 @@
     private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
 
     private BackupManagerConstants mConstants;
-    private BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private Context mContext;
     private PackageManager mPackageManager;
     private IPackageManager mPackageManagerBinder;
@@ -309,10 +315,6 @@
         return mConstants;
     }
 
-    public BackupAgentTimeoutParameters getAgentTimeoutParameters() {
-        return mAgentTimeoutParameters;
-    }
-
     public Context getContext() {
         return mContext;
     }
@@ -854,10 +856,6 @@
         // require frequent starting and stopping.
         mConstants.start();
 
-        mAgentTimeoutParameters = new
-                BackupAgentTimeoutParameters(mBackupHandler, mContext.getContentResolver());
-        mAgentTimeoutParameters.start();
-
         // Set up the various sorts of package tracking we do
         mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
         initPackageTracking();
@@ -3409,7 +3407,7 @@
             }
             mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport);
             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
-                    mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
+                    TIMEOUT_RESTORE_INTERVAL);
         }
         return mActiveRestoreSession;
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
index aabe7f6..7b021c6 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
@@ -191,7 +191,4 @@
   void dump(FileDescriptor fd, PrintWriter pw, String[] args);
 
   IBackupManager getBackupManagerBinder();
-
-  // Gets access to the backup/restore agent timeout parameters.
-  BackupAgentTimeoutParameters getAgentTimeoutParameters();
 }
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index f08c655..4755877 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -4,8 +4,8 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
-
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL;
 
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
@@ -59,7 +59,6 @@
     private ParcelFileDescriptor mSavedState;
     private ParcelFileDescriptor mBackupData;
     private ParcelFileDescriptor mNewState;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public KeyValueAdbBackupEngine(OutputStream output, PackageInfo packageInfo,
             BackupManagerServiceInterface backupManagerService, PackageManager packageManager,
@@ -82,7 +81,6 @@
                 pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX);
 
         mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME);
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     public void backupOnePackage() throws IOException {
@@ -150,9 +148,8 @@
     // Return true on backup success, false otherwise
     private boolean invokeAgentForAdbBackup(String packageName, IBackupAgent agent) {
         int token = mBackupManagerService.generateRandomIntegerToken();
-        long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
         try {
-            mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null,
+            mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null,
                     OP_TYPE_BACKUP_WAIT);
 
             // Start backup and wait for BackupManagerService to get callback for success or timeout
@@ -234,14 +231,14 @@
     }
 
     private void writeBackupData() throws IOException {
+
         int token = mBackupManagerService.generateRandomIntegerToken();
-        long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
 
         ParcelFileDescriptor[] pipes = null;
         try {
             pipes = ParcelFileDescriptor.createPipe();
 
-            mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null,
+            mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null,
                     OP_TYPE_BACKUP_WAIT);
 
             // We will have to create a runnable that will read the manifest and backup data we
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 597da21..0582aba 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -25,6 +25,9 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
+import static com.android.server.backup.BackupManagerService
+        .TIMEOUT_SHARED_BACKUP_INTERVAL;
 
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
@@ -42,9 +45,8 @@
 import android.util.StringBuilderPrinter;
 
 import com.android.server.AppWidgetBackupBridge;
-import com.android.server.backup.BackupAgentTimeoutParameters;
-import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.utils.FullBackupUtils;
 
 import java.io.BufferedOutputStream;
@@ -73,7 +75,6 @@
     private final long mQuota;
     private final int mOpToken;
     private final int mTransportFlags;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     class FullBackupRunner implements Runnable {
 
@@ -136,8 +137,8 @@
                 final boolean isSharedStorage =
                         mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
                 final long timeout = isSharedStorage ?
-                        mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
-                        mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
+                        TIMEOUT_SHARED_BACKUP_INTERVAL :
+                        TIMEOUT_FULL_BACKUP_INTERVAL;
 
                 if (DEBUG) {
                     Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
@@ -179,7 +180,6 @@
         mQuota = quota;
         mOpToken = opToken;
         mTransportFlags = transportFlags;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     public int preflightCheck() throws RemoteException {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
index d441cf6..40b6967 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
@@ -19,6 +19,7 @@
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.app.backup.IBackupManager;
 import android.content.ComponentName;
@@ -32,7 +33,6 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IObbBackupService;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.utils.FullBackupUtils;
 
@@ -46,12 +46,10 @@
 
     private BackupManagerService backupManagerService;
     volatile IObbBackupService mService;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public FullBackupObbConnection(BackupManagerService backupManagerService) {
         this.backupManagerService = backupManagerService;
         mService = null;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     public void establish() {
@@ -77,10 +75,8 @@
         try {
             pipes = ParcelFileDescriptor.createPipe();
             int token = backupManagerService.generateRandomIntegerToken();
-            long fullBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT);
+                    token, TIMEOUT_FULL_BACKUP_INTERVAL, null, OP_TYPE_BACKUP_WAIT);
             mService.backupObbs(pkg.packageName, pipes[1], token,
                     backupManagerService.getBackupManagerBinder());
             FullBackupUtils.routeSocketDataToOutput(pipes[0], out);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 1ea3eb5..2c2dd85 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -22,6 +22,7 @@
 import static com.android.server.backup.BackupManagerService.OP_PENDING;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.annotation.Nullable;
 import android.app.IBackupAgent;
@@ -43,7 +44,6 @@
 
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.EventLogTags;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FullBackupJob;
 import com.android.server.backup.BackupManagerService;
@@ -146,7 +146,6 @@
     private volatile boolean mIsDoingBackup;
     private volatile boolean mCancelAll;
     private final int mCurrentOpToken;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public PerformFullTransportBackupTask(BackupManagerService backupManagerService,
             TransportClient transportClient,
@@ -168,7 +167,6 @@
         mUserInitiated = userInitiated;
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
 
         if (backupManagerService.isBackupOperationInProgress()) {
             if (DEBUG) {
@@ -700,11 +698,9 @@
         @Override
         public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) {
             int result;
-            long fullBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
                 backupManagerService.prepareOperationTimeout(
-                        mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
+                        mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT);
                 backupManagerService.addBackupTrace("preflighting");
                 if (MORE_DEBUG) {
                     Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
@@ -717,7 +713,7 @@
                 // timeout had been produced.  In case of a real backstop timeout, mResult
                 // will still contain the value it was constructed with, AGENT_ERROR, which
                 // intentionaly falls into the "just report failure" code.
-                mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
+                mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
 
                 long totalSize = mResult.get();
                 // If preflight timed out, mResult will contain error code as int.
@@ -773,10 +769,8 @@
 
         @Override
         public long getExpectedSizeOrErrorCode() {
-            long fullBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
+                mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
                 return mResult.get();
             } catch (InterruptedException e) {
                 return BackupTransport.NO_MORE_DATA;
@@ -869,10 +863,8 @@
         // If preflight succeeded, returns positive number - preflight size,
         // otherwise return negative error code.
         long getPreflightResultBlocking() {
-            long fullBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
+                mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
                 if (mIsCancelled) {
                     return BackupManager.ERROR_BACKUP_CANCELLED;
                 }
@@ -887,10 +879,8 @@
         }
 
         int getBackupResultBlocking() {
-            long fullBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
+                mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
                 if (mIsCancelled) {
                     return BackupManager.ERROR_BACKUP_CANCELLED;
                 }
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 5886862..136fada 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -19,6 +19,7 @@
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
 
 import android.app.backup.RestoreSet;
 import android.content.Intent;
@@ -33,7 +34,6 @@
 
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.EventLogTags;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
@@ -81,12 +81,10 @@
     public static final int MSG_OP_COMPLETE = 21;
 
     private final BackupManagerService backupManagerService;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public BackupHandler(BackupManagerService backupManagerService, Looper looper) {
         super(looper);
         this.backupManagerService = backupManagerService;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     public void handleMessage(Message msg) {
@@ -324,8 +322,7 @@
 
                     // Done: reset the session timeout clock
                     removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-                    sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
-                            mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
+                    sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
 
                     params.listener.onFinished(callerLogString);
                 }
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 0313066..11394e66 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -24,6 +24,7 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
 
@@ -56,7 +57,6 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
@@ -142,7 +142,6 @@
     private boolean mFinished;
     private final boolean mUserInitiated;
     private final boolean mNonIncremental;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     private volatile boolean mCancelAll;
 
@@ -163,7 +162,6 @@
         mPendingFullBackups = pendingFullBackups;
         mUserInitiated = userInitiated;
         mNonIncremental = nonIncremental;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
 
         mStateDir = new File(backupManagerService.getBaseStateDir(), dirName);
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
@@ -713,10 +711,8 @@
 
             // Initiate the target's backup pass
             backupManagerService.addBackupTrace("setting timeout");
-            long kvBackupAgentTimeoutMillis =
-                    mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    mEphemeralOpToken, kvBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
+                    mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT);
             backupManagerService.addBackupTrace("calling agent doBackup()");
 
             agent.doBackup(
diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
index 6175629..e4f3a9d 100644
--- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
+++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
@@ -18,10 +18,10 @@
 
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.util.Slog;
 
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 
@@ -37,22 +37,18 @@
     private BackupManagerService backupManagerService;
     final CountDownLatch mLatch;
     private final int mCurrentOpToken;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public AdbRestoreFinishedLatch(BackupManagerService backupManagerService,
             int currentOpToken) {
         this.backupManagerService = backupManagerService;
         mLatch = new CountDownLatch(1);
         mCurrentOpToken = currentOpToken;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     void await() {
         boolean latched = false;
-        long fullBackupAgentTimeoutMillis =
-                mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
         try {
-            latched = mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
+            latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
             Slog.w(TAG, "Interrupted!");
         }
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index f168afed..c1a1c1d 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -23,6 +23,9 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
+import static com.android.server.backup.BackupManagerService
+        .TIMEOUT_SHARED_BACKUP_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 
 import android.app.ApplicationThreadConstants;
@@ -40,11 +43,10 @@
 import android.util.Slog;
 
 import com.android.server.LocalServices;
-import com.android.server.backup.BackupAgentTimeoutParameters;
-import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
+import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.fullbackup.FullBackupObbConnection;
 import com.android.server.backup.utils.BytesReadListener;
 import com.android.server.backup.utils.FullBackupRestoreObserverUtils;
@@ -119,8 +121,6 @@
 
     final int mEphemeralOpToken;
 
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
-
     public FullRestoreEngine(BackupManagerService backupManagerService,
             BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
             IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks,
@@ -135,7 +135,6 @@
         mAllowObbs = allowObbs;
         mBuffer = new byte[32 * 1024];
         mBytes = 0;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
     }
 
     public IBackupAgent getAgent() {
@@ -382,8 +381,8 @@
                         long toCopy = info.size;
                         final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
                         final long timeout = isSharedStorage ?
-                                mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
-                                mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
+                                TIMEOUT_SHARED_BACKUP_INTERVAL :
+                                TIMEOUT_RESTORE_INTERVAL;
                         try {
                             mBackupManagerService.prepareOperationTimeout(token,
                                     timeout,
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 221637c..dacde0b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -16,6 +16,8 @@
 
 package com.android.server.backup.restore;
 
+import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
 import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC;
 import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION;
 import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME;
@@ -26,8 +28,8 @@
 import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
-import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 
 import android.app.ApplicationThreadConstants;
@@ -47,7 +49,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -100,7 +101,6 @@
     private byte[] mWidgetData = null;
 
     private long mBytes;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     // Runner that can be placed on a separate thread to do in-process invocation
     // of the "restore finished" API asynchronously.  Used by adb restore.
@@ -155,7 +155,6 @@
         mAgentPackage = null;
         mTargetApp = null;
         mObbConnection = new FullBackupObbConnection(backupManagerService);
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
 
         // Which packages we've already wiped data on.  We prepopulate this
         // with a whitelist of packages known to be unclearable.
@@ -644,11 +643,9 @@
                     if (okay) {
                         boolean agentSuccess = true;
                         long toCopy = info.size;
-                        long restoreAgentTimeoutMillis =
-                                mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
                         try {
                             mBackupManagerService.prepareOperationTimeout(
-                                    token, restoreAgentTimeoutMillis, null, OP_TYPE_RESTORE_WAIT);
+                                    token, TIMEOUT_RESTORE_INTERVAL, null, OP_TYPE_RESTORE_WAIT);
 
                             if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
                                 if (DEBUG) {
@@ -823,12 +820,10 @@
                 // In the adb restore case, we do restore-finished here
                 if (doRestoreFinished) {
                     final int token = mBackupManagerService.generateRandomIntegerToken();
-                    long fullBackupAgentTimeoutMillis =
-                            mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
                     final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch(
                             mBackupManagerService, token);
                     mBackupManagerService.prepareOperationTimeout(
-                            token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT);
+                            token, TIMEOUT_FULL_BACKUP_INTERVAL, latch, OP_TYPE_RESTORE_WAIT);
                     if (mTargetApp.processName.equals("system")) {
                         if (MORE_DEBUG) {
                             Slog.d(TAG, "system agent - restoreFinished on thread");
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 069e3b6..4b467e5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -23,6 +23,9 @@
 import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL;
 import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.BackupManagerService
+        .TIMEOUT_RESTORE_FINISHED_INTERVAL;
+import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
@@ -56,7 +59,6 @@
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.BackupUtils;
 import com.android.server.backup.PackageManagerBackupAgent;
@@ -158,7 +160,6 @@
     ParcelFileDescriptor mNewState;
 
     private final int mEphemeralOpToken;
-    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     // This task can assume that the wakelock is properly held for it and doesn't have to worry
     // about releasing it.
@@ -189,7 +190,6 @@
         mFinished = false;
         mDidLaunch = false;
         mListener = listener;
-        mAgentTimeoutParameters = backupManagerService.getAgentTimeoutParameters();
 
         if (targetPackage != null) {
             // Single package restore
@@ -760,9 +760,8 @@
             // Kick off the restore, checking for hung agents.  The timeout or
             // the operationComplete() callback will schedule the next step,
             // so we do not do that here.
-            long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
+                    mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL, this, OP_TYPE_RESTORE_WAIT);
             mAgent.doRestore(mBackupData, appVersionCode, mNewState,
                     mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
         } catch (Exception e) {
@@ -814,11 +813,9 @@
             Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName);
         }
         try {
-            long restoreAgentFinishedTimeoutMillis =
-                    mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis();
             backupManagerService
                     .prepareOperationTimeout(mEphemeralOpToken,
-                            restoreAgentFinishedTimeoutMillis, this,
+                            TIMEOUT_RESTORE_FINISHED_INTERVAL, this,
                             OP_TYPE_RESTORE_WAIT);
             mAgent.doRestoreFinished(mEphemeralOpToken,
                     backupManagerService.getBackupManagerBinder());
@@ -1112,10 +1109,9 @@
         } else {
             // We were invoked via an active restore session, not by the Package
             // Manager, so start up the session timeout again.
-            long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
             backupManagerService.getBackupHandler().sendEmptyMessageDelayed(
                     MSG_RESTORE_SESSION_TIMEOUT,
-                    restoreAgentTimeoutMillis);
+                    TIMEOUT_RESTORE_INTERVAL);
         }
 
         // Kick off any work that may be needed regarding app widget restores
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 6d773e6..cec4f1a 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -261,6 +261,12 @@
                 // we need to deliver the allow-while-idle alarms for this uid, package
                 unblockAllUnrestrictedAlarms();
             }
+
+            if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
+                Slog.v(TAG, "Package " + packageName + "/" + uid
+                        + " toggled into fg service restriction");
+                stopForegroundServicesForUidPackage(uid, packageName);
+            }
         }
 
         /**
@@ -354,6 +360,13 @@
         }
 
         /**
+         * Called when an app goes into forced app standby and its foreground
+         * services need to be removed from that state.
+         */
+        public void stopForegroundServicesForUidPackage(int uid, String packageName) {
+        }
+
+        /**
          * Called when the job restrictions for multiple UIDs might have changed, so the alarm
          * manager should re-evaluate all restrictions for all blocked jobs.
          */
@@ -1057,6 +1070,16 @@
     }
 
     /**
+     * @return whether foreground services should be suppressed in the background
+     * due to forced app standby for the given app
+     */
+    public boolean areForegroundServicesRestricted(int uid, @NonNull String packageName) {
+        synchronized (mLock) {
+            return isRunAnyRestrictedLocked(uid, packageName);
+        }
+    }
+
+    /**
      * @return whether force-app-standby is effective for a UID package-name.
      */
     private boolean isRestricted(int uid, @NonNull String packageName,
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
new file mode 100644
index 0000000..2ed4516
--- /dev/null
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.os.Binder;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.os.BinderCallsStats;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class BinderCallsStatsService extends Binder {
+
+    private static final String TAG = "BinderCallsStatsService";
+
+    private static final String PERSIST_SYS_BINDER_CPU_STATS_TRACKING
+            = "persist.sys.binder_cpu_stats_tracking";
+
+    public static void start() {
+        BinderCallsStatsService service = new BinderCallsStatsService();
+        ServiceManager.addService("binder_calls_stats", service);
+        // TODO Enable by default on eng/userdebug builds
+        boolean trackingEnabledDefault = false;
+        boolean trackingEnabled = SystemProperties.getBoolean(PERSIST_SYS_BINDER_CPU_STATS_TRACKING,
+                trackingEnabledDefault);
+
+        if (trackingEnabled) {
+            Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by "
+                    + PERSIST_SYS_BINDER_CPU_STATS_TRACKING);
+            BinderCallsStats.getInstance().setTrackingEnabled(true);
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        BinderCallsStats.getInstance().dump(pw);
+    }
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 30d31b8..088f366 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1386,6 +1386,12 @@
         }
     }
 
+    private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
+        if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(Binder.getCallingUid())) {
+            nc.addCapability(NET_CAPABILITY_FOREGROUND);
+        }
+    }
+
     @Override
     public NetworkState[] getAllNetworkState() {
         // Require internal since we're handing out IMSI details
@@ -4411,15 +4417,13 @@
 
         NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         restrictRequestUidsForCaller(nc);
-        if (!ConnectivityManager.checkChangePermission(mContext)) {
-            // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
-            // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
-            // onLost and onAvailable callbacks when networks move in and out of the background.
-            // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
-            // can't request networks.
-            nc.addCapability(NET_CAPABILITY_FOREGROUND);
-        }
-        ensureValidNetworkSpecifier(networkCapabilities);
+        // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
+        // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
+        // onLost and onAvailable callbacks when networks move in and out of the background.
+        // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
+        // can't request networks.
+        restrictBackgroundRequestForCaller(nc);
+        ensureValidNetworkSpecifier(nc);
 
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 5b57c14..f6ff359 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -3663,16 +3663,21 @@
             }
         }
 
+        boolean reenableMinimumNonAuxSystemImes = false;
         // TODO: The following code should find better place to live.
         if (!resetDefaultEnabledIme) {
             boolean enabledImeFound = false;
+            boolean enabledNonAuxImeFound = false;
             final List<InputMethodInfo> enabledImes = mSettings.getEnabledInputMethodListLocked();
             final int N = enabledImes.size();
             for (int i = 0; i < N; ++i) {
                 final InputMethodInfo imi = enabledImes.get(i);
                 if (mMethodList.contains(imi)) {
                     enabledImeFound = true;
-                    break;
+                    if (!imi.isAuxiliaryIme()) {
+                        enabledNonAuxImeFound = true;
+                        break;
+                    }
                 }
             }
             if (!enabledImeFound) {
@@ -3681,12 +3686,18 @@
                 }
                 resetDefaultEnabledIme = true;
                 resetSelectedInputMethodAndSubtypeLocked("");
+            } else if (!enabledNonAuxImeFound) {
+                if (DEBUG) {
+                    Slog.i(TAG, "All the enabled non-Aux IMEs are gone. Do partial reset.");
+                }
+                reenableMinimumNonAuxSystemImes = true;
             }
         }
 
-        if (resetDefaultEnabledIme) {
+        if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
             final ArrayList<InputMethodInfo> defaultEnabledIme =
-                    InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList);
+                    InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
+                            reenableMinimumNonAuxSystemImes);
             final int N = defaultEnabledIme.size();
             for (int i = 0; i < N; ++i) {
                 final InputMethodInfo imi =  defaultEnabledIme.get(i);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 45a4dfb9..d09a161 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -36,6 +36,7 @@
 import android.net.IpSecTransformResponse;
 import android.net.IpSecTunnelInterfaceResponse;
 import android.net.IpSecUdpEncapResponse;
+import android.net.LinkAddress;
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
@@ -618,10 +619,8 @@
                                 spi,
                                 mConfig.getMarkValue(),
                                 mConfig.getMarkMask());
-            } catch (ServiceSpecificException e) {
-                // FIXME: get the error code and throw is at an IOException from Errno Exception
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
+            } catch (RemoteException | ServiceSpecificException e) {
+                Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
             }
 
             getResourceTracker().give();
@@ -677,14 +676,14 @@
         @Override
         public void freeUnderlyingResources() {
             try {
-                mSrvConfig
-                        .getNetdInstance()
-                        .ipSecDeleteSecurityAssociation(
-                                mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
-            } catch (ServiceSpecificException e) {
-                // FIXME: get the error code and throw is at an IOException from Errno Exception
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
+                if (!mOwnedByTransform) {
+                    mSrvConfig
+                            .getNetdInstance()
+                            .ipSecDeleteSecurityAssociation(
+                                    mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                }
+            } catch (ServiceSpecificException | RemoteException e) {
+                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
             }
 
             mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
@@ -829,15 +828,13 @@
                                         0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff);
                     }
                 }
-            } catch (ServiceSpecificException e) {
-                // FIXME: get the error code and throw is at an IOException from Errno Exception
-            } catch (RemoteException e) {
+            } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(
                         TAG,
                         "Failed to delete VTI with interface name: "
                                 + mInterfaceName
                                 + " and id: "
-                                + mResourceId);
+                                + mResourceId, e);
             }
 
             getResourceTracker().give();
@@ -1319,7 +1316,9 @@
      * from multiple local IP addresses over the same tunnel.
      */
     @Override
-    public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) {
+    public synchronized void addAddressToTunnelInterface(
+            int tunnelResourceId, LinkAddress localAddr) {
+        enforceNetworkStackPermission();
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
 
         // Get tunnelInterface record; if no such interface is found, will throw
@@ -1327,8 +1326,21 @@
         TunnelInterfaceRecord tunnelInterfaceInfo =
                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
 
-        // TODO: Add calls to netd:
-        //       Add address to TunnelInterface
+        try {
+            // We can assume general validity of the IP address, since we get them as a
+            // LinkAddress, which does some validation.
+            mSrvConfig
+                    .getNetdInstance()
+                    .interfaceAddAddress(
+                            tunnelInterfaceInfo.mInterfaceName,
+                            localAddr.getAddress().getHostAddress(),
+                            localAddr.getPrefixLength());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**
@@ -1337,7 +1349,8 @@
      */
     @Override
     public synchronized void removeAddressFromTunnelInterface(
-            int tunnelResourceId, String localAddr) {
+            int tunnelResourceId, LinkAddress localAddr) {
+        enforceNetworkStackPermission();
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
 
         // Get tunnelInterface record; if no such interface is found, will throw
@@ -1345,8 +1358,21 @@
         TunnelInterfaceRecord tunnelInterfaceInfo =
                 userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
 
-        // TODO: Add calls to netd:
-        //       Remove address from TunnelInterface
+        try {
+            // We can assume general validity of the IP address, since we get them as a
+            // LinkAddress, which does some validation.
+            mSrvConfig
+                    .getNetdInstance()
+                    .interfaceDelAddress(
+                            tunnelInterfaceInfo.mInterfaceName,
+                            localAddr.getAddress().getHostAddress(),
+                            localAddr.getPrefixLength());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**
@@ -1467,6 +1493,13 @@
         IpSecAlgorithm crypt = c.getEncryption();
         IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
 
+        String cryptName;
+        if (crypt == null) {
+            cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : "";
+        } else {
+            cryptName = crypt.getName();
+        }
+
         mSrvConfig
                 .getNetdInstance()
                 .ipSecAddSecurityAssociation(
@@ -1481,7 +1514,7 @@
                         (auth != null) ? auth.getName() : "",
                         (auth != null) ? auth.getKey() : new byte[] {},
                         (auth != null) ? auth.getTruncationLengthBits() : 0,
-                        (crypt != null) ? crypt.getName() : "",
+                        cryptName,
                         (crypt != null) ? crypt.getKey() : new byte[] {},
                         (crypt != null) ? crypt.getTruncationLengthBits() : 0,
                         (authCrypt != null) ? authCrypt.getName() : "",
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 65e90bad..26b83f5 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -82,8 +83,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.server.location.ActivityRecognitionProxy;
-import com.android.server.location.FlpHardwareProvider;
-import com.android.server.location.FusedProxy;
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GeofenceProxy;
@@ -491,13 +490,6 @@
         if (gpsProvider != null && gpsProvider.isEnabled()) {
             gpsProvider.disable();
         }
-
-        // it is needed to check if FLP HW provider is supported before accessing the instance, this
-        // avoids an exception to be thrown by the singleton factory method
-        if (FlpHardwareProvider.isSupported()) {
-            FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
-            flpHardwareProvider.cleanup();
-        }
     }
 
     /**
@@ -686,27 +678,6 @@
             Slog.e(TAG, "no geocoder provider found");
         }
 
-        // bind to fused hardware provider if supported
-        // in devices without support, requesting an instance of FlpHardwareProvider will raise an
-        // exception, so make sure we only do that when supported
-        FlpHardwareProvider flpHardwareProvider;
-        if (FlpHardwareProvider.isSupported()) {
-            flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
-            FusedProxy fusedProxy = FusedProxy.createAndBind(
-                    mContext,
-                    mLocationHandler,
-                    flpHardwareProvider.getLocationHardware(),
-                    com.android.internal.R.bool.config_enableHardwareFlpOverlay,
-                    com.android.internal.R.string.config_hardwareFlpPackageName,
-                    com.android.internal.R.array.config_locationProviderPackageNames);
-            if (fusedProxy == null) {
-                Slog.d(TAG, "Unable to bind FusedProxy.");
-            }
-        } else {
-            flpHardwareProvider = null;
-            Slog.d(TAG, "FLP HAL not supported");
-        }
-
         // bind to geofence provider
         GeofenceProxy provider = GeofenceProxy.createAndBind(
                 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
@@ -714,7 +685,7 @@
                 com.android.internal.R.array.config_locationProviderPackageNames,
                 mLocationHandler,
                 mGpsGeofenceProxy,
-                flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
+                null);
         if (provider == null) {
             Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
         }
@@ -1161,11 +1132,12 @@
      * Returns the model name of the GNSS hardware.
      */
     @Override
+    @Nullable
     public String getGnssHardwareModelName() {
         if (mGnssSystemInfoProvider != null) {
             return mGnssSystemInfoProvider.getGnssHardwareModelName();
         } else {
-            return LocationManager.GNSS_HARDWARE_MODEL_NAME_UNKNOWN;
+            return null;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 4a65733..ff65951 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -24,8 +24,6 @@
 import android.util.PrintWriterPrinter;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.ActiveInstrumentationProto;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index eb4e32e..e84c5f4 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -56,9 +56,10 @@
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
+import com.android.server.AppStateTracker;
+import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.ActivityManagerService.NeededUriGrants;
-import com.android.server.am.proto.ActiveServicesProto;
 
 import android.app.ActivityManager;
 import android.app.AppGlobals;
@@ -165,6 +166,44 @@
     };
 
     /**
+     * Watch for apps being put into forced app standby, so we can step their fg
+     * services down.
+     */
+    class ForcedStandbyListener extends AppStateTracker.Listener {
+        @Override
+        public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
+            synchronized (mAm) {
+                final ServiceMap smap = getServiceMapLocked(UserHandle.getUserId(uid));
+                final int N = smap.mServicesByName.size();
+                final ArrayList<ServiceRecord> toStop = new ArrayList<>(N);
+                for (int i = 0; i < N; i++) {
+                    final ServiceRecord r = smap.mServicesByName.valueAt(i);
+                    if (uid == r.serviceInfo.applicationInfo.uid
+                            || packageName.equals(r.serviceInfo.packageName)) {
+                        if (r.isForeground) {
+                            toStop.add(r);
+                        }
+                    }
+                }
+
+                // Now stop them all
+                final int numToStop = toStop.size();
+                if (numToStop > 0 && DEBUG_FOREGROUND_SERVICE) {
+                    Slog.i(TAG, "Package " + packageName + "/" + uid
+                            + " entering FAS with foreground services");
+                }
+                for (int i = 0; i < numToStop; i++) {
+                    final ServiceRecord r = toStop.get(i);
+                    if (DEBUG_FOREGROUND_SERVICE) {
+                        Slog.i(TAG, "  Stopping fg for service " + r);
+                    }
+                    setServiceForegroundInnerLocked(r, 0, null, 0);
+                }
+            }
+        }
+    }
+
+    /**
      * Information about an app that is currently running one or more foreground services.
      * (This maps directly to the running apps we show in the notification.)
      */
@@ -302,6 +341,11 @@
                 ? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
     }
 
+    void systemServicesReady() {
+        AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
+        ast.addListener(new ForcedStandbyListener());
+    }
+
     ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {
         // TODO: Deal with global services
         if (DEBUG_MU)
@@ -327,6 +371,12 @@
         return getServiceMapLocked(callingUser).mServicesByName;
     }
 
+    private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
+        final int mode = mAm.mAppOpsService.checkOperation(
+                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
+        return (mode != AppOpsManager.MODE_ALLOWED);
+    }
+
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
             int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
             throws TransactionTooLargeException {
@@ -365,13 +415,24 @@
             return null;
         }
 
+        // If the app has strict background restrictions, we treat any service
+        // start analogously to the legacy-app forced-restrictions case.
+        boolean forcedStandby = false;
+        if (appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
+            if (DEBUG_FOREGROUND_SERVICE) {
+                Slog.d(TAG, "Forcing bg-only service start only for "
+                        + r.name.flattenToShortString());
+            }
+            forcedStandby = true;
+        }
+
         // If this isn't a direct-to-foreground start, check our ability to kick off an
         // arbitrary service
-        if (!r.startRequested && !fgRequired) {
+        if (forcedStandby || (!r.startRequested && !fgRequired)) {
             // Before going further -- if this app is not allowed to start services in the
             // background, then at this point we aren't going to let it period.
             final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
-                    r.appInfo.targetSdkVersion, callingPid, false, false);
+                    r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
             if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                 Slog.w(TAG, "Background start not allowed: service "
                         + service + " to " + r.name.flattenToShortString()
@@ -625,7 +686,7 @@
                 ServiceRecord service = services.mServicesByName.valueAt(i);
                 if (service.appInfo.uid == uid && service.startRequested) {
                     if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
-                            service.appInfo.targetSdkVersion, -1, false, false)
+                            service.appInfo.targetSdkVersion, -1, false, false, false)
                             != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
@@ -1019,7 +1080,10 @@
         }
     }
 
-    private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
+    /**
+     * @param id Notification ID.  Zero === exit foreground state for the given service.
+     */
+    private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
             Notification notification, int flags) {
         if (id != 0) {
             if (notification == null) {
@@ -1061,44 +1125,56 @@
                 mAm.mHandler.removeMessages(
                         ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
             }
-            if (r.foregroundId != id) {
-                cancelForegroundNotificationLocked(r);
-                r.foregroundId = id;
-            }
-            notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
-            r.foregroundNoti = notification;
-            if (!r.isForeground) {
-                final ServiceMap smap = getServiceMapLocked(r.userId);
-                if (smap != null) {
-                    ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
-                    if (active == null) {
-                        active = new ActiveForegroundApp();
-                        active.mPackageName = r.packageName;
-                        active.mUid = r.appInfo.uid;
-                        active.mShownWhileScreenOn = mScreenOn;
-                        if (r.app != null) {
-                            active.mAppOnTop = active.mShownWhileTop =
-                                    r.app.uidRecord.curProcState
-                                            <= ActivityManager.PROCESS_STATE_TOP;
-                        }
-                        active.mStartTime = active.mStartVisibleTime
-                                = SystemClock.elapsedRealtime();
-                        smap.mActiveForegroundApps.put(r.packageName, active);
-                        requestUpdateActiveForegroundAppsLocked(smap, 0);
-                    }
-                    active.mNumActive++;
+
+            // Apps under strict background restrictions simply don't get to have foreground
+            // services, so now that we've enforced the startForegroundService() contract
+            // we only do the machinery of making the service foreground when the app
+            // is not restricted.
+            if (!appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
+                if (r.foregroundId != id) {
+                    cancelForegroundNotificationLocked(r);
+                    r.foregroundId = id;
                 }
-                r.isForeground = true;
-                StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
-                        StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
+                notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+                r.foregroundNoti = notification;
+                if (!r.isForeground) {
+                    final ServiceMap smap = getServiceMapLocked(r.userId);
+                    if (smap != null) {
+                        ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
+                        if (active == null) {
+                            active = new ActiveForegroundApp();
+                            active.mPackageName = r.packageName;
+                            active.mUid = r.appInfo.uid;
+                            active.mShownWhileScreenOn = mScreenOn;
+                            if (r.app != null) {
+                                active.mAppOnTop = active.mShownWhileTop =
+                                        r.app.uidRecord.curProcState
+                                        <= ActivityManager.PROCESS_STATE_TOP;
+                            }
+                            active.mStartTime = active.mStartVisibleTime
+                                    = SystemClock.elapsedRealtime();
+                            smap.mActiveForegroundApps.put(r.packageName, active);
+                            requestUpdateActiveForegroundAppsLocked(smap, 0);
+                        }
+                        active.mNumActive++;
+                    }
+                    r.isForeground = true;
+                    StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
+                            r.appInfo.uid, r.shortName,
+                            StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
+                }
+                r.postNotification();
+                if (r.app != null) {
+                    updateServiceForegroundLocked(r.app, true);
+                }
+                getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
+                mAm.notifyPackageUse(r.serviceInfo.packageName,
+                        PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
+            } else {
+                if (DEBUG_FOREGROUND_SERVICE) {
+                    Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
+                }
             }
-            r.postNotification();
-            if (r.app != null) {
-                updateServiceForegroundLocked(r.app, true);
-            }
-            getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
-            mAm.notifyPackageUse(r.serviceInfo.packageName,
-                                 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
         } else {
             if (r.isForeground) {
                 final ServiceMap smap = getServiceMapLocked(r.userId);
@@ -1106,7 +1182,8 @@
                     decActiveForegroundAppLocked(smap, r);
                 }
                 r.isForeground = false;
-                StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
+                StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
+                        r.appInfo.uid, r.shortName,
                         StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
                 if (r.app != null) {
                     mAm.updateLruProcessLocked(r.app, false, null);
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 4498077..4a8bc87 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -35,9 +35,9 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.proto.ActivityDisplayProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityDisplayProto.STACKS;
-import static com.android.server.am.proto.ActivityDisplayProto.ID;
+import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityDisplayProto.STACKS;
+import static com.android.server.am.ActivityDisplayProto.ID;
 
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fb8f749..457564b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -123,7 +123,6 @@
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -205,7 +204,6 @@
 import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
@@ -390,8 +388,8 @@
 import android.view.RemoteAnimationDefinition;
 import android.view.View;
 import android.view.WindowManager;
-
 import android.view.autofill.AutofillManagerInternal;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -443,19 +441,19 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
-import com.android.server.am.proto.ActivityManagerServiceProto;
-import com.android.server.am.proto.ActivityManagerServiceDumpActivitiesProto;
-import com.android.server.am.proto.ActivityManagerServiceDumpBroadcastsProto;
-import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto;
-import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
-import com.android.server.am.proto.ActivityManagerServiceDumpServicesProto;
-import com.android.server.am.proto.GrantUriProto;
-import com.android.server.am.proto.ImportanceTokenProto;
-import com.android.server.am.proto.MemInfoDumpProto;
-import com.android.server.am.proto.NeededUriGrantsProto;
-import com.android.server.am.proto.ProcessOomProto;
-import com.android.server.am.proto.ProcessToGcProto;
-import com.android.server.am.proto.StickyBroadcastProto;
+import com.android.server.am.ActivityManagerServiceProto;
+import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
+import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto;
+import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
+import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
+import com.android.server.am.ActivityManagerServiceDumpServicesProto;
+import com.android.server.am.GrantUriProto;
+import com.android.server.am.ImportanceTokenProto;
+import com.android.server.am.MemInfoDumpProto;
+import com.android.server.am.NeededUriGrantsProto;
+import com.android.server.am.ProcessOomProto;
+import com.android.server.am.ProcessToGcProto;
+import com.android.server.am.StickyBroadcastProto;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
@@ -2853,6 +2851,7 @@
         public void onBootPhase(int phase) {
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
                 mService.mBatteryStatsService.systemServicesReady();
+                mService.mServices.systemServicesReady();
             }
         }
 
@@ -9118,7 +9117,7 @@
 
     public boolean isAppStartModeDisabled(int uid, String packageName) {
         synchronized (this) {
-            return getAppStartModeLocked(uid, packageName, 0, -1, false, true)
+            return getAppStartModeLocked(uid, packageName, 0, -1, false, true, false)
                     == ActivityManager.APP_START_MODE_DISABLED;
         }
     }
@@ -9194,12 +9193,12 @@
     }
 
     int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
-            int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
+            int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
         UidRecord uidRec = mActiveUids.get(uid);
         if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
                 + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
                 + (uidRec != null ? uidRec.idle : false));
-        if (uidRec == null || alwaysRestrict || uidRec.idle) {
+        if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
             boolean ephemeral;
             if (uidRec == null) {
                 ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
@@ -17093,8 +17092,8 @@
 
             if (mRunningVoice != null) {
                 final long vrToken = proto.start(ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
-                proto.write(ActivityManagerServiceDumpProcessesProto.VoiceProto.SESSION, mRunningVoice.toString());
-                mVoiceWakeLock.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VoiceProto.WAKELOCK);
+                proto.write(ActivityManagerServiceDumpProcessesProto.Voice.SESSION, mRunningVoice.toString());
+                mVoiceWakeLock.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Voice.WAKELOCK);
                 proto.end(vrToken);
             }
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 19ca3be..ccc17a3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -112,16 +112,16 @@
 import static com.android.server.am.TaskPersister.DEBUG;
 import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.proto.ActivityRecordProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityRecordProto.FRONT_OF_TASK;
-import static com.android.server.am.proto.ActivityRecordProto.IDENTIFIER;
-import static com.android.server.am.proto.ActivityRecordProto.PROC_ID;
-import static com.android.server.am.proto.ActivityRecordProto.STATE;
-import static com.android.server.am.proto.ActivityRecordProto.VISIBLE;
+import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
+import static com.android.server.am.ActivityRecordProto.PROC_ID;
+import static com.android.server.am.ActivityRecordProto.STATE;
+import static com.android.server.am.ActivityRecordProto.VISIBLE;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
-import static com.android.server.wm.proto.IdentifierProto.TITLE;
-import static com.android.server.wm.proto.IdentifierProto.USER_ID;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -2738,11 +2738,6 @@
         } else {
             service.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this);
             setState(PAUSED, "relaunchActivityLocked");
-            // if the app is relaunched when it's stopped, and we're not resuming,
-            // put it back into stopped state.
-            if (stopped) {
-                getStack().addToStopping(this, true /* scheduleIdle */, false /* idleDelayed */);
-            }
         }
 
         configChangeFlags = 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1f5320a..20b938b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -82,13 +82,13 @@
 import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.am.proto.ActivityStackProto.BOUNDS;
-import static com.android.server.am.proto.ActivityStackProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityStackProto.DISPLAY_ID;
-import static com.android.server.am.proto.ActivityStackProto.FULLSCREEN;
-import static com.android.server.am.proto.ActivityStackProto.ID;
-import static com.android.server.am.proto.ActivityStackProto.RESUMED_ACTIVITY;
-import static com.android.server.am.proto.ActivityStackProto.TASKS;
+import static com.android.server.am.ActivityStackProto.BOUNDS;
+import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
+import static com.android.server.am.ActivityStackProto.FULLSCREEN;
+import static com.android.server.am.ActivityStackProto.ID;
+import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityStackProto.TASKS;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_NONE;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e4695b6..265e4fa 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -90,12 +90,12 @@
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
-import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS;
+import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
+import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
+import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
+import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 
 import static java.lang.Integer.MAX_VALUE;
@@ -1199,6 +1199,12 @@
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
             final ActivityDisplay display = mActivityDisplays.get(displayId);
+
+            // If WindowManagerService has encountered the display before we have, ignore as there
+            // will be no stacks present and therefore no activities.
+            if (display == null) {
+                continue;
+            }
             for (int j = display.getChildCount() - 1; j >= 0; --j) {
                 final ActivityStack stack = display.getChildAt(j);
                 if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) {
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 972a692..4eaebd0 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -19,8 +19,6 @@
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.AppBindRecordProto;
-
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index ed09879..b2872e4 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -22,7 +22,6 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.server.RescueParty;
 import com.android.server.Watchdog;
-import com.android.server.am.proto.AppErrorsProto;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
diff --git a/services/core/java/com/android/server/am/AppTimeTracker.java b/services/core/java/com/android/server/am/AppTimeTracker.java
index d96364a..772865d 100644
--- a/services/core/java/com/android/server/am/AppTimeTracker.java
+++ b/services/core/java/com/android/server/am/AppTimeTracker.java
@@ -28,8 +28,6 @@
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
 
-import com.android.server.am.proto.AppTimeTrackerProto;
-
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index f5e1a31..2291e44 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -283,30 +283,34 @@
                 mUseLatestStates = true;
             }
 
-            synchronized (mWorkerLock) {
-                if (DEBUG) {
-                    Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
-                }
-                try {
-                    updateExternalStatsLocked(reason, updateFlags, onBattery,
-                            onBatteryScreenOff, useLatestStates);
-                } finally {
+            try {
+                synchronized (mWorkerLock) {
                     if (DEBUG) {
-                        Slog.d(TAG, "end updateExternalStatsSync");
+                        Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
+                    }
+                    try {
+                        updateExternalStatsLocked(reason, updateFlags, onBattery,
+                                onBatteryScreenOff, useLatestStates);
+                    } finally {
+                        if (DEBUG) {
+                            Slog.d(TAG, "end updateExternalStatsSync");
+                        }
                     }
                 }
-            }
 
-            if ((updateFlags & UPDATE_CPU) != 0) {
-                mStats.copyFromAllUidsCpuTimes();
-            }
-
-            // Clean up any UIDs if necessary.
-            synchronized (mStats) {
-                for (int uid : uidsToRemove) {
-                    mStats.removeIsolatedUidLocked(uid);
+                if ((updateFlags & UPDATE_CPU) != 0) {
+                    mStats.copyFromAllUidsCpuTimes();
                 }
-                mStats.clearPendingRemovedUids();
+
+                // Clean up any UIDs if necessary.
+                synchronized (mStats) {
+                    for (int uid : uidsToRemove) {
+                        mStats.removeIsolatedUidLocked(uid);
+                    }
+                    mStats.clearPendingRemovedUids();
+                }
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Error updating external stats: ", e);
             }
         }
     };
@@ -398,7 +402,7 @@
                 if (bluetoothInfo.isValid()) {
                     mStats.updateBluetoothStateLocked(bluetoothInfo);
                 } else {
-                    Slog.e(TAG, "bluetooth info is invalid: " + bluetoothInfo);
+                    Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                 }
             }
         }
@@ -410,7 +414,7 @@
             if (wifiInfo.isValid()) {
                 mStats.updateWifiState(extractDeltaLocked(wifiInfo));
             } else {
-                Slog.e(TAG, "wifi info is invalid: " + wifiInfo);
+                Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
             }
         }
 
@@ -418,7 +422,7 @@
             if (modemInfo.isValid()) {
                 mStats.updateMobileRadioState(modemInfo);
             } else {
-                Slog.e(TAG, "modem info is invalid: " + modemInfo);
+                Slog.w(TAG, "modem info is invalid: " + modemInfo);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 7ff227f..8e2ca06 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -21,8 +21,6 @@
 import android.util.Printer;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.BroadcastFilterProto;
-
 import java.io.PrintWriter;
 
 final class BroadcastFilter extends IntentFilter {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 9a7634e..cc3a887 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -55,8 +55,6 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
-import com.android.server.am.proto.BroadcastQueueProto;
-
 /**
  * BROADCASTS
  *
@@ -1258,7 +1256,7 @@
             if (!skip) {
                 final int allowed = mService.getAppStartModeLocked(
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
-                        info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false);
+                        info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     // We won't allow this receiver to be launched if the app has been
                     // completely disabled from launches, or it was not explicitly sent
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 5b3b2a8..574ca4a 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -32,8 +32,6 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.BroadcastRecordProto;
-
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index a8e9ad9..679024ee 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -22,8 +22,6 @@
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
 
-import com.android.server.am.proto.ConnectionRecordProto;
-
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index 5bf5020..328426d 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -36,9 +36,11 @@
 
     private static final String TAG = "GlobalSettingsToPropertiesMapper";
 
+    // List mapping entries in the following format:
+    // {Settings.Global.SETTING_NAME, "system_property_name"}
+    // Important: Property being added should be whitelisted by SELinux policy or have one of the
+    // already whitelisted prefixes in system_server.te, e.g. sys.
     private static final String[][] sGlobalSettingsMapping = new String[][] {
-    //  List mapping entries in the following format:
-    //  {Settings.Global.SETTING_NAME, "system_property_name"},
         {Settings.Global.SYS_VDSO, "sys.vdso"},
         {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
         {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"},
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index 3457a80..839b6e1 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -23,9 +23,6 @@
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.AppBindRecordProto;
-import com.android.server.am.proto.IntentBindRecordProto;
-
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 0d7eab6..b67dd0d 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -25,8 +25,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_OCCLUDED;
-import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_SHOWING;
+import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
+import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
new file mode 100644
index 0000000..9964053
--- /dev/null
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -0,0 +1,4 @@
+per-file GlobalSettingsToPropertiesMapper.java=fkupolov@google.com
+per-file GlobalSettingsToPropertiesMapper.java=omakoto@google.com
+per-file GlobalSettingsToPropertiesMapper.java=svetoslavganov@google.com
+per-file GlobalSettingsToPropertiesMapper.java=yamasani@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0bf2691..e348bf4 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -27,7 +27,6 @@
 import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.app.procstats.ProcessState;
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.am.proto.ProcessRecordProto;
 
 import android.app.ActivityManager;
 import android.app.Dialog;
diff --git a/services/core/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
index eee924f..5e31b2e 100644
--- a/services/core/java/com/android/server/am/ReceiverList.java
+++ b/services/core/java/com/android/server/am/ReceiverList.java
@@ -25,7 +25,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.server.IntentResolver;
-import com.android.server.am.proto.ReceiverListProto;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index fc8b624..1335ced 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -508,6 +508,10 @@
                     && tr.userId == userId
                     && tr.realActivitySuspended != suspended) {
                tr.realActivitySuspended = suspended;
+               if (suspended) {
+                   mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+                           REMOVE_FROM_RECENTS, "suspended-package");
+               }
                notifyTaskPersisterLocked(tr, false);
             }
         }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 49a55cb..f296c60 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -19,7 +19,6 @@
 import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.LocalServices;
-import com.android.server.am.proto.ServiceRecordProto;
 import com.android.server.notification.NotificationManagerInternal;
 
 import android.app.INotificationManager;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c7b89d3..034cb2e 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -62,19 +62,19 @@
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.proto.TaskRecordProto.ACTIVITIES;
-import static com.android.server.am.proto.TaskRecordProto.BOUNDS;
-import static com.android.server.am.proto.TaskRecordProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.proto.TaskRecordProto.FULLSCREEN;
-import static com.android.server.am.proto.TaskRecordProto.ID;
-import static com.android.server.am.proto.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
-import static com.android.server.am.proto.TaskRecordProto.MIN_HEIGHT;
-import static com.android.server.am.proto.TaskRecordProto.MIN_WIDTH;
-import static com.android.server.am.proto.TaskRecordProto.ORIG_ACTIVITY;
-import static com.android.server.am.proto.TaskRecordProto.REAL_ACTIVITY;
-import static com.android.server.am.proto.TaskRecordProto.RESIZE_MODE;
-import static com.android.server.am.proto.TaskRecordProto.STACK_ID;
-import static com.android.server.am.proto.TaskRecordProto.ACTIVITY_TYPE;
+import static com.android.server.am.TaskRecordProto.ACTIVITIES;
+import static com.android.server.am.TaskRecordProto.BOUNDS;
+import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.TaskRecordProto.FULLSCREEN;
+import static com.android.server.am.TaskRecordProto.ID;
+import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
+import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
+import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
+import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
+import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
 
 import static java.lang.Integer.MAX_VALUE;
 
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index d49f3ba..3b859ed 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -28,7 +28,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.am.proto.UidRecordProto;
 
 /**
  * Overall information about a uid that has actively running processes.
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index fc07c1a..8eda38e 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -22,8 +22,6 @@
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.am.proto.UriPermissionOwnerProto;
-
 import com.google.android.collect.Sets;
 
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index af1ab83..0d125e0 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -95,7 +95,6 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
-import com.android.server.am.proto.UserControllerProto;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 00597e2..4f5c59c 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -27,7 +27,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ProgressReporter;
-import com.android.server.am.proto.UserStateProto;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index 9d34a80..45410d7 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -24,7 +24,6 @@
 import android.util.proto.ProtoUtils;
 
 import com.android.server.LocalServices;
-import com.android.server.am.proto.ActivityManagerServiceDumpProcessesProto.VrControllerProto;
 import com.android.server.vr.VrManagerInternal;
 
 /**
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c036549..5bb9f33 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -24,6 +24,9 @@
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.STREAM_SYSTEM;
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
+import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
+import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -108,6 +111,7 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -124,6 +128,7 @@
 import android.util.SparseIntArray;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Toast;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
@@ -440,6 +445,12 @@
 
     // Is there a vibrator
     private final boolean mHasVibrator;
+    // Used to play vibrations
+    private Vibrator mVibrator;
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
 
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
@@ -697,8 +708,8 @@
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
 
-        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
+        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
 
         // Initialize volume
         int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
@@ -1649,7 +1660,7 @@
 
             // Check if volume update should be send to Hearing Aid
             if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
-                setHearingAidVolume(newIndex);
+                setHearingAidVolume(newIndex, streamType);
             }
 
             // Check if volume update should be sent to Hdmi system audio.
@@ -1898,7 +1909,7 @@
             }
 
             if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
-                setHearingAidVolume(index);
+                setHearingAidVolume(index, streamType);
             }
 
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
@@ -2423,6 +2434,54 @@
         setRingerMode(ringerMode, caller, false /*external*/);
     }
 
+    public void silenceRingerModeInternal(String reason) {
+        VibrationEffect effect = null;
+        int ringerMode = AudioManager.RINGER_MODE_SILENT;
+        int toastText = 0;
+
+        int silenceRingerSetting = Settings.Secure.VOLUME_HUSH_OFF;
+        if (mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
+            silenceRingerSetting = Settings.Secure.getIntForUser(mContentResolver,
+                    Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
+                    UserHandle.USER_CURRENT);
+        }
+
+        switch(silenceRingerSetting) {
+            case VOLUME_HUSH_MUTE:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+                ringerMode = AudioManager.RINGER_MODE_SILENT;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
+                break;
+            case VOLUME_HUSH_VIBRATE:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+                ringerMode = AudioManager.RINGER_MODE_VIBRATE;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
+                break;
+        }
+        maybeVibrate(effect);
+        setRingerModeInternal(ringerMode, reason);
+        Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
+    }
+
+    private boolean maybeVibrate(VibrationEffect effect) {
+        if (!mHasVibrator) {
+            return false;
+        }
+        final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
+        if (hapticsDisabled) {
+            return false;
+        }
+
+        if (effect == null) {
+            return false;
+        }
+        mVibrator.vibrate(
+                Binder.getCallingUid(), mContext.getOpPackageName(), effect, VIBRATION_ATTRIBUTES);
+        return true;
+    }
+
     private void setRingerMode(int ringerMode, String caller, boolean external) {
         if (mUseFixedVolume || mIsSingleVolume) {
             return;
@@ -2484,14 +2543,24 @@
             mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         }
 
-        final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
-                || mRingerMode == AudioManager.RINGER_MODE_SILENT;
+        final int ringerMode = mRingerMode; // Read ringer mode as reading primitives is atomic
+        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
+                || ringerMode == AudioManager.RINGER_MODE_SILENT;
+        final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
+                && isBluetoothScoOn();
+        // Ask audio policy engine to force use Bluetooth SCO channel if needed
+        final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
+                + "/" + Binder.getCallingPid();
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING,
+                shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0);
 
         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
             final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType);
+            final boolean muteAllowedBySco =
+                    !(shouldRingSco && streamType == AudioSystem.STREAM_RING);
             final boolean shouldZenMute = shouldZenMuteStream(streamType);
             final boolean shouldMute = shouldZenMute || (ringerModeMute
-                    && isStreamAffectedByRingerMode(streamType));
+                    && isStreamAffectedByRingerMode(streamType) && muteAllowedBySco);
             if (isMuted == shouldMute) continue;
             if (!shouldMute) {
                 // unmute
@@ -3132,6 +3201,8 @@
                 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
                 AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource, 0);
+        // Un-mute ringtone stream volume
+        setRingerModeInt(getRingerModeInternal(), false);
     }
 
     /** @see AudioManager#isBluetoothScoOn() */
@@ -4724,7 +4795,7 @@
         }
 
         public boolean setIndex(int index, int device, String caller) {
-            boolean changed = false;
+            boolean changed;
             int oldIndex;
             synchronized (mSettingsLock) {
                 synchronized (VolumeStreamState.class) {
@@ -4741,7 +4812,7 @@
                     // - there is no volume index stored for this device on alias stream.
                     // If changing volume of current device, also change volume of current
                     // device on aliased stream
-                    final boolean currentDevice = (device == getDeviceForStream(mStreamType));
+                    final boolean isCurrentDevice = (device == getDeviceForStream(mStreamType));
                     final int numStreamTypes = AudioSystem.getNumStreamTypes();
                     for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
                         final VolumeStreamState aliasStreamState = mStreamStates[streamType];
@@ -4750,12 +4821,22 @@
                                 (changed || !aliasStreamState.hasIndexForDevice(device))) {
                             final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
                             aliasStreamState.setIndex(scaledIndex, device, caller);
-                            if (currentDevice) {
+                            if (isCurrentDevice) {
                                 aliasStreamState.setIndex(scaledIndex,
                                         getDeviceForStream(streamType), caller);
                             }
                         }
                     }
+                    // Mirror changes in SPEAKER ringtone volume on SCO when
+                    if (changed && mStreamType == AudioSystem.STREAM_RING
+                            && device == AudioSystem.DEVICE_OUT_SPEAKER) {
+                        for (int i = 0; i < mIndexMap.size(); i++) {
+                            int otherDevice = mIndexMap.keyAt(i);
+                            if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) {
+                                mIndexMap.put(otherDevice, index);
+                            }
+                        }
+                    }
                 }
             }
             if (changed) {
@@ -5606,11 +5687,11 @@
                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
     }
 
-    private void setHearingAidVolume(int index) {
+    private void setHearingAidVolume(int index, int streamType) {
         synchronized (mHearingAidLock) {
             if (mHearingAid != null) {
                 //hearing aid expect volume value in range -128dB to 0dB
-                int gainDB = (int)AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, index/10,
+                int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10,
                         AudioSystem.DEVICE_OUT_HEARING_AID);
                 if (gainDB < BT_HEARING_AID_GAIN_MIN)
                     gainDB = BT_HEARING_AID_GAIN_MIN;
@@ -5622,7 +5703,7 @@
     // must be called synchronized on mConnectedDevices
     private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
         int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(AudioSystem.DEVICE_OUT_HEARING_AID);
-        setHearingAidVolume(index);
+        setHearingAidVolume(index, AudioSystem.STREAM_MUSIC);
 
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
                 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
@@ -7246,6 +7327,11 @@
         }
 
         @Override
+        public void silenceRingerModeInternal(String caller) {
+            AudioService.this.silenceRingerModeInternal(caller);
+        }
+
+        @Override
         public void updateRingerModeAffectedStreamsInternal() {
             synchronized (mSettingsLock) {
                 if (updateRingerAndZenModeAffectedStreams()) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index e084ff8..d578e95 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_STACK;
 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
 import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -27,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,6 +41,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -150,7 +154,14 @@
         update(mUsers, mApps, true);
     }
 
-    private boolean hasPermission(PackageInfo app, String permission) {
+    @VisibleForTesting
+    boolean isPreinstalledSystemApp(PackageInfo app) {
+        int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
+        return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
+    }
+
+    @VisibleForTesting
+    boolean hasPermission(PackageInfo app, String permission) {
         if (app.requestedPermissions != null) {
             for (String p : app.requestedPermissions) {
                 if (permission.equals(p)) {
@@ -166,14 +177,40 @@
     }
 
     private boolean hasRestrictedNetworkPermission(PackageInfo app) {
-        int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
-        if ((flags & FLAG_SYSTEM) != 0 || (flags & FLAG_UPDATED_SYSTEM_APP) != 0) {
-            return true;
-        }
+        if (isPreinstalledSystemApp(app)) return true;
         return hasPermission(app, CONNECTIVITY_INTERNAL)
                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
     }
 
+    private boolean hasUseBackgroundNetworksPermission(PackageInfo app) {
+        // This function defines what it means to hold the permission to use
+        // background networks.
+        return hasPermission(app, CHANGE_NETWORK_STATE)
+                || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
+                || hasPermission(app, CONNECTIVITY_INTERNAL)
+                || hasPermission(app, NETWORK_STACK)
+                // TODO : remove this check (b/31479477). Not all preinstalled apps should
+                // have access to background networks, they should just request the appropriate
+                // permission for their use case from the list above.
+                || isPreinstalledSystemApp(app);
+    }
+
+    public boolean hasUseBackgroundNetworksPermission(int uid) {
+        final String[] names = mPackageManager.getPackagesForUid(uid);
+        if (null == names || names.length == 0) return false;
+        try {
+            // Only using the first package name. There may be multiple names if multiple
+            // apps share the same UID, but in that case they also share permissions so
+            // querying with any of the names will return the same results.
+            final PackageInfo app = mPackageManager.getPackageInfo(names[0], GET_PERMISSIONS);
+            return hasUseBackgroundNetworksPermission(app);
+        } catch (NameNotFoundException e) {
+            // App not found.
+            loge("NameNotFoundException " + names[0], e);
+            return false;
+        }
+    }
+
     private int[] toIntArray(List<Integer> list) {
         int[] array = new int[list.size()];
         for (int i = 0; i < list.size(); i++) {
@@ -308,4 +345,8 @@
     private static void loge(String s) {
         Log.e(TAG, s);
     }
+
+    private static void loge(String s, Throwable e) {
+        Log.e(TAG, s, e);
+    }
 }
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 171f40e..88df195 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -25,12 +25,14 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ParceledListSlice;
+import android.database.ContentObserver;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.display.AmbientBrightnessDayStats;
 import android.hardware.display.BrightnessChangeEvent;
+import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Environment;
 import android.os.Handler;
@@ -110,6 +112,8 @@
 
     private static final int MSG_BACKGROUND_START = 0;
     private static final int MSG_BRIGHTNESS_CHANGED = 1;
+    private static final int MSG_STOP_SENSOR_LISTENER = 2;
+    private static final int MSG_START_SENSOR_LISTENER = 3;
 
     // Lock held while accessing mEvents, is held while writing events to flash.
     private final Object mEventsLock = new Object();
@@ -127,9 +131,14 @@
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private Handler mBgHandler;
-    // mBroadcastReceiver and mSensorListener should only be used on the mBgHandler thread.
+
+    // mBroadcastReceiver,  mSensorListener, mSettingsObserver and mSensorRegistered
+    // should only be used on the mBgHandler thread.
     private BroadcastReceiver mBroadcastReceiver;
     private SensorListener mSensorListener;
+    private SettingsObserver mSettingsObserver;
+    private boolean mSensorRegistered;
+
     private @UserIdInt int mCurrentUserId = UserHandle.USER_NULL;
 
     // Lock held while collecting data related to brightness changes.
@@ -178,10 +187,9 @@
 
         mSensorListener = new SensorListener();
 
-
-        if (mInjector.isInteractive(mContext)) {
-            mInjector.registerSensorListener(mContext, mSensorListener, mBgHandler);
-        }
+        mSettingsObserver = new SettingsObserver(mBgHandler);
+        mInjector.registerBrightnessModeObserver(mContentResolver, mSettingsObserver);
+        startSensorListener();
 
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_SHUTDOWN);
@@ -205,10 +213,11 @@
             Slog.d(TAG, "Stop");
         }
         mBgHandler.removeMessages(MSG_BACKGROUND_START);
+        stopSensorListener();
         mInjector.unregisterSensorListener(mContext, mSensorListener);
+        mInjector.unregisterBrightnessModeObserver(mContext, mSettingsObserver);
         mInjector.unregisterReceiver(mContext, mBroadcastReceiver);
         mInjector.cancelIdleJob(mContext);
-        mAmbientBrightnessStatsTracker.stop();
 
         synchronized (mDataCollectionLock) {
             mStarted = false;
@@ -366,6 +375,25 @@
         }
     }
 
+    private void startSensorListener() {
+        if (!mSensorRegistered
+                && mInjector.isInteractive(mContext)
+                && mInjector.isBrightnessModeAutomatic(mContentResolver)) {
+            mAmbientBrightnessStatsTracker.start();
+            mSensorRegistered = true;
+            mInjector.registerSensorListener(mContext, mSensorListener,
+                    mInjector.getBackgroundHandler());
+        }
+    }
+
+    private void stopSensorListener() {
+        if (mSensorRegistered) {
+            mAmbientBrightnessStatsTracker.stop();
+            mInjector.unregisterSensorListener(mContext, mSensorListener);
+            mSensorRegistered = false;
+        }
+    }
+
     private void scheduleWriteBrightnessTrackerState() {
         if (!mWriteBrightnessTrackerStateScheduled) {
             mBgHandler.post(() -> {
@@ -724,6 +752,24 @@
         }
     }
 
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (DEBUG) {
+                Slog.v(TAG, "settings change " + uri);
+            }
+            if (mInjector.isBrightnessModeAutomatic(mContentResolver)) {
+                mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget();
+            } else {
+                mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget();
+            }
+        }
+    }
+
     private final class Receiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -741,12 +787,9 @@
                     batteryLevelChanged(level, scale);
                 }
             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                mAmbientBrightnessStatsTracker.stop();
-                mInjector.unregisterSensorListener(mContext, mSensorListener);
+                mBgHandler.obtainMessage(MSG_STOP_SENSOR_LISTENER).sendToTarget();
             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
-                mAmbientBrightnessStatsTracker.start();
-                mInjector.registerSensorListener(mContext, mSensorListener,
-                        mInjector.getBackgroundHandler());
+                mBgHandler.obtainMessage(MSG_START_SENSOR_LISTENER).sendToTarget();
             }
         }
     }
@@ -767,6 +810,12 @@
                             values.powerBrightnessFactor, values.isUserSetBrightness,
                             values.isDefaultBrightnessConfig);
                     break;
+                case MSG_START_SENSOR_LISTENER:
+                    startSensorListener();
+                    break;
+                case MSG_STOP_SENSOR_LISTENER:
+                    stopSensorListener();
+                    break;
             }
         }
     }
@@ -801,6 +850,18 @@
             sensorManager.unregisterListener(sensorListener);
         }
 
+        public void registerBrightnessModeObserver(ContentResolver resolver,
+                ContentObserver settingsObserver) {
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_BRIGHTNESS_MODE),
+                    false, settingsObserver, UserHandle.USER_ALL);
+        }
+
+        public void unregisterBrightnessModeObserver(Context context,
+                ContentObserver settingsObserver) {
+            context.getContentResolver().unregisterContentObserver(settingsObserver);
+        }
+
         public void registerReceiver(Context context,
                 BroadcastReceiver receiver, IntentFilter filter) {
             context.registerReceiver(receiver, filter);
@@ -815,6 +876,12 @@
             return BackgroundThread.getHandler();
         }
 
+        public boolean isBrightnessModeAutomatic(ContentResolver resolver) {
+            return Settings.System.getIntForUser(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE,
+                    Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT)
+                    == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
+        }
+
         public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
                 int userId) {
             return Settings.Secure.getIntForUser(resolver, setting, defaultValue, userId);
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 0b1f9a6..66817fa 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -29,6 +29,7 @@
 import android.app.job.IJobScheduler;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
+import android.app.job.JobProtoEnums;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
 import android.app.job.JobWorkItem;
@@ -880,7 +881,8 @@
             startTrackingJobLocked(jobStatus, toCancel);
             StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
                     uId, null, jobStatus.getBatteryName(),
-                    StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED);
+                    StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
+                    JobProtoEnums.STOP_REASON_CANCELLED);
 
             // If the job is immediately ready to run, then we can just immediately
             // put it in the pending list and try to schedule it.  This is especially
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 578a32c..a1e066e 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -95,11 +95,18 @@
     public static final long MIN_TRIGGER_MAX_DELAY = 1000;
 
     final JobInfo job;
-    /** Uid of the package requesting this job. */
+    /**
+     * Uid of the package requesting this job.  This can differ from the "source"
+     * uid when the job was scheduled on the app's behalf, such as with the jobs
+     * that underly Sync Manager operation.
+     */
     final int callingUid;
     final int targetSdkVersion;
     final String batteryName;
 
+    /**
+     * Identity of the app in which the job is hosted.
+     */
     final String sourcePackageName;
     final int sourceUserId;
     final int sourceUid;
@@ -263,6 +270,31 @@
         return callingUid;
     }
 
+    /**
+     * Core constructor for JobStatus instances.  All other ctors funnel down to this one.
+     *
+     * @param job The actual requested parameters for the job
+     * @param callingUid Identity of the app that is scheduling the job.  This may not be the
+     *     app in which the job is implemented; such as with sync jobs.
+     * @param targetSdkVersion The targetSdkVersion of the app in which the job will run.
+     * @param sourcePackageName The package name of the app in which the job will run.
+     * @param sourceUserId The user in which the job will run
+     * @param standbyBucket The standby bucket that the source package is currently assigned to,
+     *     cached here for speed of handling during runnability evaluations (and updated when bucket
+     *     assignments are changed)
+     * @param heartbeat Timestamp of when the job was created, in the standby-related
+     *     timebase.
+     * @param tag A string associated with the job for debugging/logging purposes.
+     * @param numFailures Count of how many times this job has requested a reschedule because
+     *     its work was not yet finished.
+     * @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
+     *     is to be considered runnable
+     * @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be
+     *     considered overdue
+     * @param lastSuccessfulRunTime When did we last run this job to completion?
+     * @param lastFailedRunTime When did we last run this job only to have it stop incomplete?
+     * @param internalFlags Non-API property flags about this job
+     */
     private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
             int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
             long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
@@ -399,8 +431,8 @@
     /**
      * Create a newly scheduled job.
      * @param callingUid Uid of the package that scheduled this job.
-     * @param sourcePkg Package name on whose behalf this job is scheduled. Null indicates
-     *                          the calling package is the source.
+     * @param sourcePkg Package name of the app that will actually run the job.  Null indicates
+     *     that the calling package is the source.
      * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
      *     caller.
      */
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
deleted file mode 100644
index 5c9b0ea..0000000
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import android.content.Context;
-import android.hardware.location.IFusedLocationHardware;
-import android.location.IFusedGeofenceHardware;
-import android.util.Log;
-
-/**
- * This class was an interop layer for JVM types and the JNI code that interacted
- * with the FLP HAL implementation.
- *
- * Now, after Treble FLP & GNSS HAL simplification, it is a thin shell that acts like the
- * pre-existing cases where there was no FLP Hardware support, to keep legacy users of this
- * class operating.
- *
- * {@hide}
- * {@Deprecated}
- */
-public class FlpHardwareProvider {
-    private static FlpHardwareProvider sSingletonInstance = null;
-
-    private final static String TAG = "FlpHardwareProvider";
-
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    public static FlpHardwareProvider getInstance(Context context) {
-        if (sSingletonInstance == null) {
-            sSingletonInstance = new FlpHardwareProvider();
-            if (DEBUG) Log.d(TAG, "getInstance() created empty provider");
-        }
-        return sSingletonInstance;
-    }
-
-    private FlpHardwareProvider() {
-    }
-
-    public static boolean isSupported() {
-        if (DEBUG) Log.d(TAG, "isSupported() returning false");
-        return false;
-    }
-
-    /**
-     * Interface implementations for services built on top of this functionality.
-     */
-    public static final String LOCATION = "Location";
-
-    public IFusedLocationHardware getLocationHardware() {
-        return null;
-    }
-
-    public IFusedGeofenceHardware getGeofenceHardware() {
-        return null;
-    }
-
-    public void cleanup() {
-        if (DEBUG) Log.d(TAG, "empty cleanup()");
-    }
-}
diff --git a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
deleted file mode 100644
index a08d326..0000000
--- a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import android.content.Context;
-import android.hardware.location.IFusedLocationHardware;
-import android.hardware.location.IFusedLocationHardwareSink;
-import android.location.FusedBatchOptions;
-import android.os.RemoteException;
-
-/**
- * FusedLocationHardware decorator that adds permission checking.
- * @hide
- */
-public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub {
-    private final IFusedLocationHardware mLocationHardware;
-    private final Context mContext;
-    private final String mPermissionId;
-
-    public FusedLocationHardwareSecure(
-            IFusedLocationHardware locationHardware,
-            Context context,
-            String permissionId) {
-        mLocationHardware = locationHardware;
-        mContext = context;
-        mPermissionId = permissionId;
-    }
-
-    private void checkPermissions() {
-        mContext.enforceCallingPermission(
-                mPermissionId,
-                String.format(
-                        "Permission '%s' not granted to access FusedLocationHardware",
-                        mPermissionId));
-    }
-
-    @Override
-    public void registerSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.registerSink(eventSink);
-    }
-
-    @Override
-    public void unregisterSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.unregisterSink(eventSink);
-    }
-
-    @Override
-    public int getSupportedBatchSize() throws RemoteException {
-        checkPermissions();
-        return mLocationHardware.getSupportedBatchSize();
-    }
-
-    @Override
-    public void startBatching(int id, FusedBatchOptions batchOptions) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.startBatching(id, batchOptions);
-    }
-
-    @Override
-    public void stopBatching(int id) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.stopBatching(id);
-    }
-
-    @Override
-    public void updateBatchingOptions(
-            int id,
-            FusedBatchOptions batchoOptions
-            ) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.updateBatchingOptions(id, batchoOptions);
-    }
-
-    @Override
-    public void requestBatchOfLocations(int batchSizeRequested) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.requestBatchOfLocations(batchSizeRequested);
-    }
-
-    @Override
-    public boolean supportsDiagnosticDataInjection() throws RemoteException {
-        checkPermissions();
-        return mLocationHardware.supportsDiagnosticDataInjection();
-    }
-
-    @Override
-    public void injectDiagnosticData(String data) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.injectDiagnosticData(data);
-    }
-
-    @Override
-    public boolean supportsDeviceContextInjection() throws RemoteException {
-        checkPermissions();
-        return mLocationHardware.supportsDeviceContextInjection();
-    }
-
-    @Override
-    public void injectDeviceContext(int deviceEnabledContext) throws RemoteException {
-        checkPermissions();
-        mLocationHardware.injectDeviceContext(deviceEnabledContext);
-    }
-
-    @Override
-    public void flushBatchedLocations() throws RemoteException {
-        checkPermissions();
-        mLocationHardware.flushBatchedLocations();
-    }
-
-    @Override
-    public int getVersion() throws RemoteException {
-        checkPermissions();
-        return mLocationHardware.getVersion();
-    }
-}
diff --git a/services/core/java/com/android/server/location/FusedProxy.java b/services/core/java/com/android/server/location/FusedProxy.java
deleted file mode 100644
index b90f037..0000000
--- a/services/core/java/com/android/server/location/FusedProxy.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (The "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import com.android.server.ServiceWatcher;
-
-import android.Manifest;
-import android.content.Context;
-import android.hardware.location.IFusedLocationHardware;
-import android.location.IFusedProvider;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * Proxy that helps bind GCore FusedProvider implementations to the Fused Hardware instances.
- *
- * @hide
- */
-public final class FusedProxy {
-    private final String TAG = "FusedProxy";
-    private final ServiceWatcher mServiceWatcher;
-    private final FusedLocationHardwareSecure mLocationHardware;
-
-    /**
-     * Constructor of the class.
-     * This is private as the class follows a factory pattern for construction.
-     *
-     * @param context           The context needed for construction.
-     * @param handler           The handler needed for construction.
-     * @param locationHardware  The instance of the Fused location hardware assigned to the proxy.
-     */
-    private FusedProxy(
-            Context context,
-            Handler handler,
-            IFusedLocationHardware locationHardware,
-            int overlaySwitchResId,
-            int defaultServicePackageNameResId,
-            int initialPackageNameResId) {
-        mLocationHardware = new FusedLocationHardwareSecure(
-                locationHardware,
-                context,
-                Manifest.permission.LOCATION_HARDWARE);
-        Runnable newServiceWork = new Runnable() {
-            @Override
-            public void run() {
-                bindProvider(mLocationHardware);
-            }
-        };
-
-        // prepare the connection to the provider
-        mServiceWatcher = new ServiceWatcher(
-                context,
-                TAG,
-                "com.android.location.service.FusedProvider",
-                overlaySwitchResId,
-                defaultServicePackageNameResId,
-                initialPackageNameResId,
-                newServiceWork,
-                handler);
-    }
-
-    /**
-     * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
-     *
-     * @param context           The context needed for construction.
-     * @param handler           The handler needed for construction.
-     * @param locationHardware  The instance of the Fused location hardware assigned to the proxy.
-     *
-     * @return An instance of the proxy if it could be bound, null otherwise.
-     */
-    public static FusedProxy createAndBind(
-            Context context,
-            Handler handler,
-            IFusedLocationHardware locationHardware,
-            int overlaySwitchResId,
-            int defaultServicePackageNameResId,
-            int initialPackageNameResId) {
-        FusedProxy fusedProxy = new FusedProxy(
-                context,
-                handler,
-                locationHardware,
-                overlaySwitchResId,
-                defaultServicePackageNameResId,
-                initialPackageNameResId);
-
-        // try to bind the Fused provider
-        if (!fusedProxy.mServiceWatcher.start()) {
-            return null;
-        }
-
-        return fusedProxy;
-    }
-
-    /**
-     * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
-     *
-     * @param locationHardware  The FusedLocationHardware instance to use for the binding operation.
-     */
-    private void bindProvider(IFusedLocationHardware locationHardware) {
-        if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
-            @Override
-            public void run(IBinder binder) {
-                IFusedProvider provider = IFusedProvider.Stub.asInterface(binder);
-                try {
-                    provider.onFusedLocationHardwareChange(locationHardware);
-                } catch (RemoteException e) {
-                    Log.e(TAG, e.toString());
-                }
-            }
-        })) {
-            Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e02feec..8f0e1da 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -470,7 +470,7 @@
 
     // Volatile for simple inter-thread sync on these values.
     private volatile int mHardwareYear = 0;
-    private volatile String mHardwareModelName = LocationManager.GNSS_HARDWARE_MODEL_NAME_UNKNOWN;
+    private volatile String mHardwareModelName;
 
     // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
     // stops output right at 600m/s, depriving this of the information of a device that reaches
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a87a113..b5eb8bf 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2033,13 +2033,7 @@
     public int[] getPendingRecoverySecretTypes() throws RemoteException {
         throw new SecurityException("Not implemented");
     }
-
-    @Override
-    public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
-            throws RemoteException {
-        mRecoverableKeyStoreManager.recoverySecretAvailable(recoverySecret);
-    }
-
+    
     @Override
     public byte[] startRecoverySession(@NonNull String sessionId,
             @NonNull byte[] verifierPublicKey, @NonNull byte[] vaultParams,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index f46657c..a87adbd 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -255,9 +255,6 @@
             }
         }
 
-        // TODO: make sure the same counter id is used during recovery and remove temporary fix.
-        counterId = 1L;
-
         byte[] vaultParams = KeySyncUtils.packVaultParams(
                 publicKey,
                 counterId,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 5b10add..429b4b5 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -62,6 +62,7 @@
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertPath;
 import java.security.cert.CertificateEncodingException;
@@ -221,6 +222,7 @@
             if (mDatabase.setRecoveryServiceCertPath(userId, uid, certPath) > 0) {
                 mDatabase.setRecoveryServiceCertSerial(userId, uid, newSerial);
                 mDatabase.setShouldCreateSnapshot(userId, uid, true);
+                mDatabase.setCounterId(userId, uid, new SecureRandom().nextLong());
             }
         } catch (CertificateEncodingException e) {
             Log.e(TAG, "Failed to encode CertPath", e);
@@ -416,8 +418,8 @@
      * @param vaultChallenge Challenge issued by vault service.
      * @param secrets Lock-screen hashes. For now only a single secret is supported.
      * @return Encrypted bytes of recovery claim. This can then be issued to the vault service.
-     * @deprecated Use {@link #startRecoverySessionWithCertPath(String, RecoveryCertPath, byte[],
-     *         byte[], List)} instead.
+     * @deprecated Use {@link #startRecoverySessionWithCertPath(String, String, RecoveryCertPath,
+     *         byte[], byte[], List)} instead.
      *
      * @hide
      */
@@ -457,6 +459,7 @@
                 uid,
                 new RecoverySessionStorage.Entry(sessionId, kfHash, keyClaimant, vaultParams));
 
+        Log.i(TAG, "Received VaultParams for recovery: " + HexDump.toHexString(vaultParams));
         try {
             byte[] thmKfHash = KeySyncUtils.calculateThmKfHash(kfHash);
             return KeySyncUtils.encryptRecoveryClaim(
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index bda2ed3..2c3d3ab 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -160,7 +160,6 @@
         /**
          * Type of secret used to generate recovery key. One of
          * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} or
-         * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_CUSTOM_PASSWORD}.
          */
         static final String COLUMN_NAME_SECRET_TYPE = "secret_type";
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 3b5b1bf..7348b84 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -608,7 +608,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
-        if (isCurrentVolumeController(uid, pid)) return;
+        if (isCurrentVolumeController(pid, uid)) return;
         if (getContext()
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                     != PackageManager.PERMISSION_GRANTED
@@ -618,13 +618,13 @@
         }
     }
 
-    private boolean isCurrentVolumeController(int uid, int pid) {
+    private boolean isCurrentVolumeController(int pid, int uid) {
         return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 pid, uid) == PackageManager.PERMISSION_GRANTED;
     }
 
     private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (!isCurrentVolumeController(uid, pid)) {
+        if (!isCurrentVolumeController(pid, uid)) {
             throw new SecurityException("Only system ui may " + action);
         }
     }
@@ -1501,53 +1501,21 @@
          * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
          * permission or an enabled notification listener)
          *
-         * @param uid uid of the controller app
-         * @param packageName package name of the controller app
+         * @param controllerPackageName package name of the controller app
+         * @param controllerPid pid of the controller app
+         * @param controllerUid uid of the controller app
          */
         @Override
-        public boolean isTrusted(int uid, String packageName) throws RemoteException {
+        public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
+                throws RemoteException {
+            final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                int userId = UserHandle.getUserId(uid);
-                // Sanity check whether uid and packageName matches
-                if (uid != mPackageManager.getPackageUid(packageName, 0, userId)) {
-                    throw new IllegalArgumentException("uid=" + uid + " and packageName="
-                            + packageName + " doesn't match");
-                }
-
-                // Check if it's system server or has MEDIA_CONTENT_CONTROL.
-                // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
-                // check here.
-                if (uid == Process.SYSTEM_UID || mPackageManager.checkPermission(
-                        android.Manifest.permission.MEDIA_CONTENT_CONTROL, packageName, uid)
-                        == PackageManager.PERMISSION_GRANTED) {
-                    return true;
-                }
-                if (DEBUG) {
-                    Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted"
-                            + " MEDIA_CONTENT_CONTROL");
-                }
-
-                // TODO(jaewan): Add hasEnabledNotificationListener(String pkgName) for
-                //               optimization (Post-P)
-                final List<ComponentName> enabledNotificationListeners =
-                        mNotificationManager.getEnabledNotificationListeners(userId);
-                if (enabledNotificationListeners != null) {
-                    for (int i = 0; i < enabledNotificationListeners.size(); i++) {
-                        if (TextUtils.equals(packageName,
-                                enabledNotificationListeners.get(i).getPackageName())) {
-                            return true;
-                        }
-                    }
-                }
+                return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
+                        controllerPid, controllerUid);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
-            if (DEBUG) {
-                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled notification"
-                        + " listener");
-            }
-            return false;
         }
 
         /**
@@ -1614,60 +1582,85 @@
             destroySession2Internal(token);
         }
 
-        // TODO(jaewan): Protect this API with permission (b/73226436)
+        // TODO(jaewan): Make this API take userId as an argument (b/73597722)
         @Override
         public List<Bundle> getSessionTokens(boolean activeSessionOnly,
-                boolean sessionServiceOnly) throws RemoteException {
+                boolean sessionServiceOnly, String packageName) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
             List<Bundle> tokens = new ArrayList<>();
-            synchronized (mLock) {
-                for (Map.Entry<SessionToken2, MediaController2> record
-                        : mSessionRecords.entrySet()) {
-                    boolean isSessionService = (record.getKey().getType() != TYPE_SESSION);
-                    boolean isActive = record.getValue() != null;
-                    if ((activeSessionOnly && !isActive)
-                            || (sessionServiceOnly && !isSessionService) ){
-                        continue;
+            try {
+                verifySessionsRequest2(UserHandle.getUserId(uid), packageName, pid, uid);
+                synchronized (mLock) {
+                    for (Map.Entry<SessionToken2, MediaController2> record
+                            : mSessionRecords.entrySet()) {
+                        boolean isSessionService = (record.getKey().getType() != TYPE_SESSION);
+                        boolean isActive = record.getValue() != null;
+                        if ((activeSessionOnly && !isActive)
+                                || (sessionServiceOnly && !isSessionService)) {
+                            continue;
+                        }
+                        tokens.add(record.getKey().toBundle());
                     }
-                    tokens.add(record.getKey().toBundle());
                 }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
             return tokens;
         }
 
-        // TODO(jaewan): Protect this API with permission (b/73226436)
-        // TODO(jaewan): "userId != calling user" needs extra protection (b/73226436)
         @Override
         public void addSessionTokensListener(ISessionTokensListener listener, int userId,
-                String packageName) {
-            synchronized (mLock) {
-                final SessionTokensListenerRecord record =
-                        new SessionTokensListenerRecord(listener, userId);
-                try {
-                    listener.asBinder().linkToDeath(record, 0);
-                } catch (RemoteException e) {
+                String packageName) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                int resolvedUserId = verifySessionsRequest2(userId, packageName, pid, uid);
+                synchronized (mLock) {
+                    final SessionTokensListenerRecord record =
+                            new SessionTokensListenerRecord(listener, resolvedUserId);
+                    try {
+                        listener.asBinder().linkToDeath(record, 0);
+                    } catch (RemoteException e) {
+                    }
+                    mSessionTokensListeners.add(record);
                 }
-                mSessionTokensListeners.add(record);
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
-        // TODO(jaewan): Protect this API with permission (b/73226436)
+        // TODO(jaewan): Make this API take userId as an argument (b/73597722)
         @Override
-        public void removeSessionTokensListener(ISessionTokensListener listener) {
-            synchronized (mLock) {
-                IBinder listenerBinder = listener.asBinder();
-                for (SessionTokensListenerRecord record : mSessionTokensListeners) {
-                    if (listenerBinder.equals(record.mListener.asBinder())) {
-                        try {
-                            listenerBinder.unlinkToDeath(record, 0);
-                        } catch (NoSuchElementException e) {
+        public void removeSessionTokensListener(ISessionTokensListener listener,
+                String packageName) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                verifySessionsRequest2(UserHandle.getUserId(uid), packageName, pid, uid);
+                synchronized (mLock) {
+                    IBinder listenerBinder = listener.asBinder();
+                    for (SessionTokensListenerRecord record : mSessionTokensListeners) {
+                        if (listenerBinder.equals(record.mListener.asBinder())) {
+                            try {
+                                listenerBinder.unlinkToDeath(record, 0);
+                            } catch (NoSuchElementException e) {
+                            }
+                            mSessionTokensListeners.remove(record);
+                            break;
                         }
-                        mSessionTokensListeners.remove(record);
-                        break;
                     }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
+        // For MediaSession
         private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
                 final int uid) {
             String packageName = null;
@@ -1687,6 +1680,66 @@
             return resolvedUserId;
         }
 
+        // For MediaSession2
+        private int verifySessionsRequest2(int targetUserId, String callerPackageName,
+                int callerPid, int callerUid) throws RemoteException {
+            // Check that they can make calls on behalf of the user and get the final user id.
+            int resolvedUserId = ActivityManager.handleIncomingUser(callerPid, callerUid,
+                    targetUserId, true /* allowAll */, true /* requireFull */, "getSessionTokens",
+                    callerPackageName);
+            // Check if they have the permissions or their component is
+            // enabled for the user they're calling from.
+            if (!hasMediaControlPermission(
+                    resolvedUserId, callerPackageName, callerPid, callerUid)) {
+                throw new SecurityException("Missing permission to control media.");
+            }
+            return resolvedUserId;
+        }
+
+        // For MediaSession2
+        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
+                int pid, int uid) throws RemoteException {
+            // Allow API calls from the System UI
+            if (isCurrentVolumeController(pid, uid)) {
+                return true;
+            }
+
+            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+            // check here.
+            if (uid == Process.SYSTEM_UID || getContext().checkPermission(
+                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            } else if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+            }
+
+            // You may not access another user's content as an enabled listener.
+            final int userId = UserHandle.getUserId(uid);
+            if (resolvedUserId != userId) {
+                return false;
+            }
+
+            // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
+            //               String pkgName) to notification team for optimization
+            final List<ComponentName> enabledNotificationListeners =
+                    mNotificationManager.getEnabledNotificationListeners(userId);
+            if (enabledNotificationListeners != null) {
+                for (int i = 0; i < enabledNotificationListeners.size(); i++) {
+                    if (TextUtils.equals(packageName,
+                            enabledNotificationListeners.get(i).getPackageName())) {
+                        return true;
+                    }
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+                        + "notification listener");
+            }
+            return false;
+        }
+
         private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags) {
             MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
                     : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 052f239..576d228 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,7 +23,6 @@
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -98,7 +97,6 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -214,6 +212,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.PatternMatcher;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -238,7 +237,6 @@
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.service.pm.PackageServiceDumpProto;
-import android.service.textclassifier.TextClassifierService;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -407,7 +405,7 @@
     static final boolean DEBUG_DOMAIN_VERIFICATION = false;
     private static final boolean DEBUG_BACKUP = false;
     public static final boolean DEBUG_INSTALL = false;
-    public static final boolean DEBUG_REMOVE = false;
+    public static final boolean DEBUG_REMOVE = true;
     private static final boolean DEBUG_BROADCASTS = false;
     private static final boolean DEBUG_SHOW_INFO = false;
     private static final boolean DEBUG_PACKAGE_INFO = false;
@@ -10355,7 +10353,7 @@
 
         if (Build.IS_DEBUGGABLE &&
                 pkg.isPrivileged() &&
-                !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+                !SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, true)) {
             PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
         }
 
@@ -13964,29 +13962,45 @@
 
     @Override
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String callingPackage,
             int userId) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        try {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
+        } catch (SecurityException e) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_USERS,
+                    "Callers need to have either " + Manifest.permission.SUSPEND_APPS + " or "
+                            + Manifest.permission.MANAGE_USERS);
+        }
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, true /* checkShell */,
                 "setPackagesSuspended for user " + userId);
+        if (callingUid != Process.ROOT_UID &&
+                !UserHandle.isSameApp(getPackageUid(callingPackage, 0, userId), callingUid)) {
+            throw new IllegalArgumentException("callingPackage " + callingPackage + " does not"
+                    + " belong to calling app id " + UserHandle.getAppId(callingUid));
+        }
 
         if (ArrayUtils.isEmpty(packageNames)) {
             return packageNames;
         }
 
         // List of package names for whom the suspended state has changed.
-        List<String> changedPackages = new ArrayList<>(packageNames.length);
+        final List<String> changedPackages = new ArrayList<>(packageNames.length);
         // List of package names for whom the suspended state is not set as requested in this
         // method.
-        List<String> unactionedPackages = new ArrayList<>(packageNames.length);
-        long callingId = Binder.clearCallingIdentity();
+        final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+        final long callingId = Binder.clearCallingIdentity();
         try {
-            for (int i = 0; i < packageNames.length; i++) {
-                String packageName = packageNames[i];
-                boolean changed = false;
-                final int appId;
-                synchronized (mPackages) {
+            synchronized (mPackages) {
+                for (int i = 0; i < packageNames.length; i++) {
+                    final String packageName = packageNames[i];
+                    if (packageName == callingPackage) {
+                        Slog.w(TAG, "Calling package: " + callingPackage + "trying to "
+                                + (suspended ? "" : "un") + "suspend itself. Ignoring");
+                        unactionedPackages.add(packageName);
+                        continue;
+                    }
                     final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
                     if (pkgSetting == null
                             || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
@@ -13995,42 +14009,75 @@
                         unactionedPackages.add(packageName);
                         continue;
                     }
-                    appId = pkgSetting.appId;
                     if (pkgSetting.getSuspended(userId) != suspended) {
                         if (!canSuspendPackageForUserLocked(packageName, userId)) {
                             unactionedPackages.add(packageName);
                             continue;
                         }
-                        pkgSetting.setSuspended(suspended, userId);
-                        mSettings.writePackageRestrictionsLPr(userId);
-                        changed = true;
+                        pkgSetting.setSuspended(suspended, callingPackage, appExtras,
+                                launcherExtras, userId);
                         changedPackages.add(packageName);
                     }
                 }
-
-                if (changed && suspended) {
-                    killApplication(packageName, UserHandle.getUid(userId, appId),
-                            "suspending package");
-                }
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
-
+        // TODO (b/75036698): Also send each package a broadcast when suspended state changed
         if (!changedPackages.isEmpty()) {
             sendPackagesSuspendedForUser(changedPackages.toArray(
                     new String[changedPackages.size()]), userId, suspended);
+            synchronized (mPackages) {
+                scheduleWritePackageRestrictionsLocked(userId);
+            }
         }
 
         return unactionedPackages.toArray(new String[unactionedPackages.size()]);
     }
 
     @Override
+    public PersistableBundle getPackageSuspendedAppExtras(String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (getPackageUid(packageName, 0, userId) != callingUid) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        }
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            final PackageUserState packageUserState = ps.readUserState(userId);
+            return packageUserState.suspended ? packageUserState.suspendedAppExtras : null;
+        }
+    }
+
+    @Override
+    public void setSuspendedPackageAppExtras(String packageName, PersistableBundle appExtras,
+            int userId) {
+        final int callingUid = Binder.getCallingUid();
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            final PackageUserState packageUserState = ps.readUserState(userId);
+            if (packageUserState.suspended) {
+                // TODO (b/75036698): Also send this package a broadcast with the new app extras
+                packageUserState.suspendedAppExtras = appExtras;
+            }
+        }
+    }
+
+    @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isPackageSuspendedForUser for user " + userId);
+        if (getPackageUid(packageName, 0, userId) != callingUid) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        }
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
@@ -14040,6 +14087,21 @@
         }
     }
 
+    void onSuspendingPackageRemoved(String packageName, int userId) {
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+                : new int[] {userId};
+        synchronized (mPackages) {
+            for (PackageSetting ps : mSettings.mPackages.values()) {
+                for (int user : userIds) {
+                    final PackageUserState pus = ps.readUserState(user);
+                    if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
+                        ps.setSuspended(false, null, null, null, user);
+                    }
+                }
+            }
+        }
+    }
+
     @GuardedBy("mPackages")
     private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
@@ -14096,6 +14158,11 @@
             return false;
         }
 
+        if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+            Slog.w(TAG, "Cannot suspend package: " + packageName);
+            return false;
+        }
+
         return true;
     }
 
@@ -18612,6 +18679,7 @@
                 }
                 final int removedUserId = (user != null) ? user.getIdentifier()
                         : UserHandle.USER_ALL;
+
                 if (!clearPackageStateForUserLIF(ps, removedUserId, outInfo)) {
                     return false;
                 }
@@ -18620,6 +18688,11 @@
                 return true;
             }
         }
+        if (ps.getPermissionsState().hasPermission(
+                Manifest.permission.SUSPEND_APPS, user.getIdentifier())) {
+            onSuspendingPackageRemoved(packageName, user.getIdentifier());
+        }
+
 
         if (((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
                 && user.getIdentifier() != UserHandle.USER_ALL)) {
@@ -18758,6 +18831,9 @@
                     true /*notLaunched*/,
                     false /*hidden*/,
                     false /*suspended*/,
+                    null, /*suspendingPackage*/
+                    null, /*suspendedAppExtras*/
+                    null, /*suspendedLauncherExtras*/
                     false /*instantApp*/,
                     false /*virtualPreload*/,
                     null /*lastDisableAppCaller*/,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d2ef67b..28e32a5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -57,12 +57,14 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1503,27 +1505,55 @@
     private int runSuspend(boolean suspendedState) {
         final PrintWriter pw = getOutPrintWriter();
         int userId = UserHandle.USER_SYSTEM;
+        final PersistableBundle appExtras = new PersistableBundle();
+        final PersistableBundle launcherExtras = new PersistableBundle();
         String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
                 case "--user":
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
+                case "--ael":
+                case "--aes":
+                case "--aed":
+                case "--lel":
+                case "--les":
+                case "--led":
+                    final String key = getNextArgRequired();
+                    final String val = getNextArgRequired();
+                    if (!suspendedState) {
+                        break;
+                    }
+                    final PersistableBundle bundleToInsert =
+                            opt.startsWith("--a") ? appExtras : launcherExtras;
+                    switch (opt.charAt(4)) {
+                        case 'l':
+                            bundleToInsert.putLong(key, Long.valueOf(val));
+                            break;
+                        case 'd':
+                            bundleToInsert.putDouble(key, Double.valueOf(val));
+                            break;
+                        case 's':
+                            bundleToInsert.putString(key, val);
+                            break;
+                    }
+                    break;
                 default:
                     pw.println("Error: Unknown option: " + opt);
                     return 1;
             }
         }
 
-        String packageName = getNextArg();
+        final String packageName = getNextArg();
         if (packageName == null) {
             pw.println("Error: package name not specified");
             return 1;
         }
-
+        final String callingPackage =
+                (Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
         try {
             mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
-                    userId);
+                    appExtras, launcherExtras, callingPackage, userId);
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a0ed126..008a81c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -20,12 +20,16 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.Signature;
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.service.pm.PackageProto;
 import android.util.ArraySet;
 import android.util.SparseArray;
@@ -394,8 +398,13 @@
         return readUserState(userId).suspended;
     }
 
-    void setSuspended(boolean suspended, int userId) {
-        modifyUserState(userId).suspended = suspended;
+    void setSuspended(boolean suspended, String suspendingPackage, PersistableBundle appExtras,
+            PersistableBundle launcherExtras, int userId) {
+        final PackageUserState existingUserState = modifyUserState(userId);
+        existingUserState.suspended = suspended;
+        existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
+        existingUserState.suspendedAppExtras = suspended ? appExtras : null;
+        existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
     }
 
     public boolean getInstantApp(int userId) {
@@ -415,7 +424,9 @@
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
+            boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
+            PersistableBundle suspendedAppExtras, PersistableBundle suspendedLauncherExtras,
+            boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
             int domainVerifState, int linkGeneration, int installReason,
@@ -428,6 +439,9 @@
         state.notLaunched = notLaunched;
         state.hidden = hidden;
         state.suspended = suspended;
+        state.suspendingPackage = suspendingPackage;
+        state.suspendedAppExtras = suspendedAppExtras;
+        state.suspendedLauncherExtras = suspendedLauncherExtras;
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
@@ -594,6 +608,9 @@
             proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
             proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
             proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
+            if (state.suspended) {
+                proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, state.suspendingPackage);
+            }
             proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
             proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
             proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a38cbda..d0e8544 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -31,6 +31,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -58,6 +59,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PatternMatcher;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -199,6 +201,8 @@
     private static final String TAG_DEFAULT_BROWSER = "default-browser";
     private static final String TAG_DEFAULT_DIALER = "default-dialer";
     private static final String TAG_VERSION = "version";
+    private static final String TAG_SUSPENDED_APP_EXTRAS = "suspended-app-extras";
+    private static final String TAG_SUSPENDED_LAUNCHER_EXTRAS = "suspended-launcher-extras";
 
     public static final String ATTR_NAME = "name";
     public static final String ATTR_PACKAGE = "package";
@@ -217,6 +221,7 @@
     // New name for the above attribute.
     private static final String ATTR_HIDDEN = "hidden";
     private static final String ATTR_SUSPENDED = "suspended";
+    private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
     // Legacy, uninstall blocks are stored separately.
     @Deprecated
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
@@ -728,6 +733,9 @@
                                 true /*notLaunched*/,
                                 false /*hidden*/,
                                 false /*suspended*/,
+                                null, /*suspendingPackage*/
+                                null, /*suspendedAppExtras*/
+                                null, /*suspendedLauncherExtras*/
                                 instantApp,
                                 virtualPreload,
                                 null /*lastDisableAppCaller*/,
@@ -1619,6 +1627,9 @@
                                 false /*notLaunched*/,
                                 false /*hidden*/,
                                 false /*suspended*/,
+                                null, /*suspendingPackage*/
+                                null, /*suspendedAppExtras*/
+                                null, /*suspendedLauncherExtras*/
                                 false /*instantApp*/,
                                 false /*virtualPreload*/,
                                 null /*lastDisableAppCaller*/,
@@ -1691,6 +1702,12 @@
 
                     final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
                             false);
+                    String suspendingPackage = parser.getAttributeValue(null,
+                            ATTR_SUSPENDING_PACKAGE);
+                    if (suspended && suspendingPackage == null) {
+                        suspendingPackage = PLATFORM_PACKAGE_NAME;
+                    }
+
                     final boolean blockUninstall = XmlUtils.readBooleanAttribute(parser,
                             ATTR_BLOCK_UNINSTALL, false);
                     final boolean instantApp = XmlUtils.readBooleanAttribute(parser,
@@ -1716,6 +1733,8 @@
 
                     ArraySet<String> enabledComponents = null;
                     ArraySet<String> disabledComponents = null;
+                    PersistableBundle suspendedAppExtras = null;
+                    PersistableBundle suspendedLauncherExtras = null;
 
                     int packageDepth = parser.getDepth();
                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1725,11 +1744,22 @@
                                 || type == XmlPullParser.TEXT) {
                             continue;
                         }
-                        tagName = parser.getName();
-                        if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
-                            enabledComponents = readComponentsLPr(parser);
-                        } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
-                            disabledComponents = readComponentsLPr(parser);
+                        switch (parser.getName()) {
+                            case TAG_ENABLED_COMPONENTS:
+                                enabledComponents = readComponentsLPr(parser);
+                                break;
+                            case TAG_DISABLED_COMPONENTS:
+                                disabledComponents = readComponentsLPr(parser);
+                                break;
+                            case TAG_SUSPENDED_APP_EXTRAS:
+                                suspendedAppExtras = PersistableBundle.restoreFromXml(parser);
+                                break;
+                            case TAG_SUSPENDED_LAUNCHER_EXTRAS:
+                                suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser);
+                                break;
+                            default:
+                                Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
+                                        + TAG_PACKAGE);
                         }
                     }
 
@@ -1737,7 +1767,8 @@
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, suspended, instantApp, virtualPreload, enabledCaller,
+                            hidden, suspended, suspendingPackage, suspendedAppExtras,
+                            suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
                             enabledComponents, disabledComponents, verifState, linkGeneration,
                             installReason, harmfulAppWarning);
                 } else if (tagName.equals("preferred-activities")) {
@@ -2046,6 +2077,27 @@
                 }
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
+                    serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, ustate.suspendingPackage);
+                    if (ustate.suspendedAppExtras != null) {
+                        serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
+                        try {
+                            ustate.suspendedAppExtras.saveToXml(serializer);
+                        } catch (XmlPullParserException xmle) {
+                            Slog.wtf(TAG, "Exception while trying to write suspendedAppExtras for "
+                                    + pkg + ". Will be lost on reboot", xmle);
+                        }
+                        serializer.endTag(null, TAG_SUSPENDED_APP_EXTRAS);
+                    }
+                    if (ustate.suspendedLauncherExtras != null) {
+                        serializer.startTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
+                        try {
+                            ustate.suspendedLauncherExtras.saveToXml(serializer);
+                        } catch (XmlPullParserException xmle) {
+                            Slog.wtf(TAG, "Exception while trying to write suspendedLauncherExtras"
+                                    + " for " + pkg + ". Will be lost on reboot", xmle);
+                        }
+                        serializer.endTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
+                    }
                 }
                 if (ustate.instantApp) {
                     serializer.attribute(null, ATTR_INSTANT_APP, "true");
@@ -4697,6 +4749,10 @@
             pw.print(ps.getHidden(user.id));
             pw.print(" suspended=");
             pw.print(ps.getSuspended(user.id));
+            if (ps.getSuspended(user.id)) {
+                pw.print(" suspendingPackage=");
+                pw.print(ps.readUserState(user.id).suspendingPackage);
+            }
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
             pw.print(" notLaunched=");
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 062a6b8..41ed6f2 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -198,7 +198,14 @@
         ParcelFileDescriptor fd = null;
         try {
             fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
-            postSuccess(packageName, fd, callback);
+            if (fd == null || !fd.getFileDescriptor().valid()) {
+                Slog.wtf(TAG,
+                        "ParcelFileDescriptor.open returned an invalid descriptor for "
+                                + packageName + ":" + snapshotProfile + ". isNull=" + (fd == null));
+                postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+            } else {
+                postSuccess(packageName, fd, callback);
+            }
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
                     + snapshotProfile, e);
@@ -264,7 +271,7 @@
         mHandler.post(() -> {
             try {
                 callback.onError(errCode);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
             }
         });
@@ -277,8 +284,17 @@
         }
         mHandler.post(() -> {
             try {
-                callback.onSuccess(fd);
-            } catch (RemoteException e) {
+                // Double check that the descriptor is still valid.
+                // We've seen production issues (b/76028139) where this can turn invalid (there are
+                // suspicions around the finalizer behaviour).
+                if (fd.getFileDescriptor().valid()) {
+                    callback.onSuccess(fd);
+                } else {
+                    Slog.wtf(TAG, "The snapshot FD became invalid before posting the result for "
+                            + packageName);
+                    callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+                }
+            } catch (Exception e) {
                 Slog.w(TAG,
                         "Failed to call onSuccess after profile snapshot for " + packageName, e);
             } finally {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index cf88bd5..eca6f9f 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -16,8 +16,8 @@
 
 package com.android.server.policy;
 
-import static com.android.server.wm.proto.BarControllerProto.STATE;
-import static com.android.server.wm.proto.BarControllerProto.TRANSIENT_STATE;
+import static com.android.server.wm.BarControllerProto.STATE;
+import static com.android.server.wm.BarControllerProto.TRANSIENT_STATE;
 
 import android.app.StatusBarManager;
 import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 61b1eb4..4dc68ac 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -39,6 +39,7 @@
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
 import static android.os.Build.VERSION_CODES.M;
 import static android.os.Build.VERSION_CODES.O;
+import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.STATE_OFF;
 import static android.view.WindowManager.DOCKED_LEFT;
@@ -71,6 +72,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
@@ -128,26 +130,26 @@
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.FOCUSED_APP_TOKEN;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.FOCUSED_WINDOW;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.FORCE_STATUS_BAR;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.FORCE_STATUS_BAR_FROM_KEYGUARD;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_DRAW_COMPLETE;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_CHANGED;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_PENDING;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.LAST_SYSTEM_UI_FLAGS;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.NAVIGATION_BAR;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.ORIENTATION;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.ORIENTATION_LISTENER;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.ROTATION;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.ROTATION_MODE;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.SCREEN_ON_FULLY;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.STATUS_BAR;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_WINDOW;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
+import static com.android.server.wm.WindowManagerPolicyProto.FOCUSED_APP_TOKEN;
+import static com.android.server.wm.WindowManagerPolicyProto.FOCUSED_WINDOW;
+import static com.android.server.wm.WindowManagerPolicyProto.FORCE_STATUS_BAR;
+import static com.android.server.wm.WindowManagerPolicyProto.FORCE_STATUS_BAR_FROM_KEYGUARD;
+import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
+import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DRAW_COMPLETE;
+import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED;
+import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_CHANGED;
+import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_PENDING;
+import static com.android.server.wm.WindowManagerPolicyProto.LAST_SYSTEM_UI_FLAGS;
+import static com.android.server.wm.WindowManagerPolicyProto.NAVIGATION_BAR;
+import static com.android.server.wm.WindowManagerPolicyProto.ORIENTATION;
+import static com.android.server.wm.WindowManagerPolicyProto.ORIENTATION_LISTENER;
+import static com.android.server.wm.WindowManagerPolicyProto.ROTATION;
+import static com.android.server.wm.WindowManagerPolicyProto.ROTATION_MODE;
+import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY;
+import static com.android.server.wm.WindowManagerPolicyProto.STATUS_BAR;
+import static com.android.server.wm.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW;
+import static com.android.server.wm.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_WINDOW;
+import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -187,6 +189,7 @@
 import android.hardware.power.V1_0.PowerHint;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.session.MediaSessionLegacyHelper;
@@ -455,6 +458,7 @@
     PowerManagerInternal mPowerManagerInternal;
     IStatusBarService mStatusBarService;
     StatusBarManagerInternal mStatusBarManagerInternal;
+    AudioManagerInternal mAudioManagerInternal;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -772,6 +776,9 @@
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
+    // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
+    private int mRingerToggleChord = VOLUME_HUSH_OFF;
+
     private static final long BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS = 1000;
 
     private boolean mBugreportTvKey1Pressed;
@@ -836,6 +843,7 @@
     private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
     private static final int MSG_POWER_VERY_LONG_PRESS = 28;
     private static final int MSG_NOTIFY_USER_ACTIVITY = 29;
+    private static final int MSG_RINGER_TOGGLE_CHORD = 30;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -943,6 +951,8 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                             android.Manifest.permission.USER_ACTIVITY);
+                case MSG_RINGER_TOGGLE_CHORD:
+                    handleRingerChordGesture();
                     break;
             }
         }
@@ -996,6 +1006,9 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.VOLUME_HUSH_GESTURE), false, this,
+                    UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POLICY_CONTROL), false, this,
                     UserHandle.USER_ALL);
@@ -1117,6 +1130,14 @@
     @VisibleForTesting
     SystemGesturesPointerEventListener mSystemGestures;
 
+    private void handleRingerChordGesture() {
+        if (mRingerToggleChord == VOLUME_HUSH_OFF) {
+            return;
+        }
+        getAudioManagerInternal();
+        mAudioManagerInternal.silenceRingerModeInternal("volume_hush");
+    }
+
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
             if (mStatusBarService == null) {
@@ -1137,6 +1158,15 @@
         }
     }
 
+    AudioManagerInternal getAudioManagerInternal() {
+        synchronized (mServiceAquireLock) {
+            if (mAudioManagerInternal == null) {
+                mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+            }
+            return mAudioManagerInternal;
+        }
+    }
+
     /*
      * We always let the sensor be switched on by default except when
      * the user has explicitly disabled sensor based rotation or when the
@@ -1306,6 +1336,7 @@
             mScreenshotChordPowerKeyTriggered = true;
             mScreenshotChordPowerKeyTime = event.getDownTime();
             interceptScreenshotChord();
+            interceptRingerToggleChord();
         }
 
         // Stop ringing or end call if configured to do so when power is pressed.
@@ -1701,6 +1732,22 @@
         }
     }
 
+    private void interceptRingerToggleChord() {
+        if (mRingerToggleChord != Settings.Secure.VOLUME_HUSH_OFF
+                && mScreenshotChordPowerKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered) {
+            final long now = SystemClock.uptimeMillis();
+            if (now <= mA11yShortcutChordVolumeUpKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mScreenshotChordPowerKeyTime
+                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mA11yShortcutChordVolumeUpKeyConsumed = true;
+                cancelPendingPowerKeyAction();
+
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RINGER_TOGGLE_CHORD),
+                        getRingerToggleChordDelay());
+            }
+        }
+    }
+
     private long getAccessibilityShortcutTimeout() {
         ViewConfiguration config = ViewConfiguration.get(mContext);
         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -1718,6 +1765,11 @@
         return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
     }
 
+    private long getRingerToggleChordDelay() {
+        // Always timeout like a tap
+        return ViewConfiguration.getTapTimeout();
+    }
+
     private void cancelPendingScreenshotChordAction() {
         mHandler.removeCallbacks(mScreenshotRunnable);
     }
@@ -1726,6 +1778,10 @@
         mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
     }
 
+    private void cancelPendingRingerToggleChordAction() {
+        mHandler.removeMessages(MSG_RINGER_TOGGLE_CHORD);
+    }
+
     private final Runnable mEndCallLongPress = new Runnable() {
         @Override
         public void run() {
@@ -2382,7 +2438,13 @@
             mSystemNavigationKeysEnabled = Settings.Secure.getIntForUser(resolver,
                     Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
                     0, UserHandle.USER_CURRENT) == 1;
-
+            mRingerToggleChord = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
+                    UserHandle.USER_CURRENT);
+            if (!mContext.getResources()
+                    .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
+                mRingerToggleChord = Settings.Secure.VOLUME_HUSH_OFF;
+            }
             // Configure rotation suggestions.
             int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
                     Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
@@ -2522,7 +2584,14 @@
     /** {@inheritDoc} */
     @Override
     public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
-        int type = attrs.type;
+        final int type = attrs.type;
+        final boolean isRoundedCornerOverlay =
+                (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
+
+        if (isRoundedCornerOverlay && mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW)
+                != PERMISSION_GRANTED) {
+            return ADD_PERMISSION_DENIED;
+        }
 
         outAppOp[0] = AppOpsManager.OP_NONE;
 
@@ -3531,6 +3600,25 @@
             }
         }
 
+        // If a ringer toggle chord could be on the way but we're not sure, then tell the dispatcher
+        // to wait a little while and try again later before dispatching.
+        if (mRingerToggleChord != VOLUME_HUSH_OFF && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            if (mA11yShortcutChordVolumeUpKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
+                final long now = SystemClock.uptimeMillis();
+                final long timeoutTime = mA11yShortcutChordVolumeUpKeyTime
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                if (now < timeoutTime) {
+                    return timeoutTime - now;
+                }
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
+                if (!down) {
+                    mA11yShortcutChordVolumeUpKeyConsumed = false;
+                }
+                return -1;
+            }
+        }
+
         // Cancel any pending meta actions if we see any other keys being pressed between the down
         // of the meta key and its corresponding up.
         if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
@@ -5997,6 +6085,9 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
+                        // Any activity on the vol down button stops the ringer toggle shortcut
+                        cancelPendingRingerToggleChordAction();
+
                         if (interactive && !mScreenshotChordVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mScreenshotChordVolumeDownKeyTriggered = true;
@@ -6020,12 +6111,16 @@
                             mA11yShortcutChordVolumeUpKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
+                            cancelPendingRingerToggleChordAction();
+
                             interceptAccessibilityShortcutChord();
+                            interceptRingerToggleChord();
                         }
                     } else {
                         mA11yShortcutChordVolumeUpKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
                         cancelPendingAccessibilityShortcutAction();
+                        cancelPendingRingerToggleChordAction();
                     }
                 }
                 if (down) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 6674e18..ec0521d 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -488,7 +488,7 @@
         boolean canAcquireSleepToken();
 
         /**
-         * Writes {@link com.android.server.wm.proto.IdentifierProto} to stream.
+         * Writes {@link com.android.server.wm.IdentifierProto} to stream.
          */
         void writeIdentifierToProto(ProtoOutputStream proto, long fieldId);
     }
@@ -1626,7 +1626,7 @@
 
     /**
      * Write the WindowManagerPolicy's state into the protocol buffer.
-     * The message is described in {@link com.android.server.wm.proto.WindowManagerPolicyProto}
+     * The message is described in {@link com.android.server.wm.WindowManagerPolicyProto}
      *
      * @param proto The protocol buffer output stream to write to.
      */
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 48a196d..1508c9e 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -16,8 +16,8 @@
 
 package com.android.server.policy;
 
-import static com.android.server.wm.proto.WindowOrientationListenerProto.ENABLED;
-import static com.android.server.wm.proto.WindowOrientationListenerProto.ROTATION;
+import static com.android.server.wm.WindowOrientationListenerProto.ENABLED;
+import static com.android.server.wm.WindowOrientationListenerProto.ROTATION;
 
 import android.content.Context;
 import android.hardware.Sensor;
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 58e8f77..062b154 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -1,11 +1,11 @@
 package com.android.server.policy.keyguard;
 
 import static android.view.Display.INVALID_DISPLAY;
-import static com.android.server.wm.proto.KeyguardServiceDelegateProto.INTERACTIVE_STATE;
-import static com.android.server.wm.proto.KeyguardServiceDelegateProto.OCCLUDED;
-import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SCREEN_STATE;
-import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SECURE;
-import static com.android.server.wm.proto.KeyguardServiceDelegateProto.SHOWING;
+import static com.android.server.wm.KeyguardServiceDelegateProto.INTERACTIVE_STATE;
+import static com.android.server.wm.KeyguardServiceDelegateProto.OCCLUDED;
+import static com.android.server.wm.KeyguardServiceDelegateProto.SCREEN_STATE;
+import static com.android.server.wm.KeyguardServiceDelegateProto.SECURE;
+import static com.android.server.wm.KeyguardServiceDelegateProto.SHOWING;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index adbf7ed..dd88cd1 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -896,7 +896,7 @@
         mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
                 com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
         mDozeAfterScreenOff = resources.getBoolean(
-                com.android.internal.R.bool.config_dozeAfterScreenOff);
+                com.android.internal.R.bool.config_dozeAfterScreenOffByDefault);
         mMinimumScreenOffTimeoutConfig = resources.getInteger(
                 com.android.internal.R.integer.config_minimumScreenOffTimeout);
         mMaximumScreenDimDurationConfig = resources.getInteger(
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 93ca4dc..41ae48a 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -70,8 +70,8 @@
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
-import static com.android.server.wm.proto.AppTransitionProto.APP_TRANSITION_STATE;
-import static com.android.server.wm.proto.AppTransitionProto.LAST_USED_APP_TRANSITION;
+import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
+import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
 
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 3cd3e8b..ad92f81 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -20,9 +20,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
-import static com.android.server.wm.proto.AppWindowThumbnailProto.HEIGHT;
-import static com.android.server.wm.proto.AppWindowThumbnailProto.SURFACE_ANIMATOR;
-import static com.android.server.wm.proto.AppWindowThumbnailProto.WIDTH;
+import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT;
+import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR;
+import static com.android.server.wm.AppWindowThumbnailProto.WIDTH;
 
 import android.graphics.GraphicBuffer;
 import android.graphics.PixelFormat;
@@ -119,7 +119,7 @@
 
     /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
-     * com.android.server.wm.proto.AppWindowThumbnailProto}.
+     * com.android.server.wm.AppWindowThumbnailProto}.
      *
      * @param proto Stream to write the AppWindowThumbnail object to.
      * @param fieldId Field Id of the AppWindowThumbnail as defined in the parent message.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f8a4540..85436da 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -51,29 +51,29 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.proto.AppWindowTokenProto.ALL_DRAWN;
-import static com.android.server.wm.proto.AppWindowTokenProto.APP_STOPPED;
-import static com.android.server.wm.proto.AppWindowTokenProto.CLIENT_HIDDEN;
-import static com.android.server.wm.proto.AppWindowTokenProto.DEFER_HIDING_CLIENT;
-import static com.android.server.wm.proto.AppWindowTokenProto.FILLS_PARENT;
-import static com.android.server.wm.proto.AppWindowTokenProto.FROZEN_BOUNDS;
-import static com.android.server.wm.proto.AppWindowTokenProto.HIDDEN_REQUESTED;
-import static com.android.server.wm.proto.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
-import static com.android.server.wm.proto.AppWindowTokenProto.IS_REALLY_ANIMATING;
-import static com.android.server.wm.proto.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
-import static com.android.server.wm.proto.AppWindowTokenProto.LAST_ALL_DRAWN;
-import static com.android.server.wm.proto.AppWindowTokenProto.LAST_SURFACE_SHOWING;
-import static com.android.server.wm.proto.AppWindowTokenProto.NAME;
-import static com.android.server.wm.proto.AppWindowTokenProto.NUM_DRAWN_WINDOWS;
-import static com.android.server.wm.proto.AppWindowTokenProto.NUM_INTERESTING_WINDOWS;
-import static com.android.server.wm.proto.AppWindowTokenProto.REMOVED;
-import static com.android.server.wm.proto.AppWindowTokenProto.REPORTED_DRAWN;
-import static com.android.server.wm.proto.AppWindowTokenProto.REPORTED_VISIBLE;
-import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_DISPLAYED;
-import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_MOVED;
-import static com.android.server.wm.proto.AppWindowTokenProto.STARTING_WINDOW;
-import static com.android.server.wm.proto.AppWindowTokenProto.THUMBNAIL;
-import static com.android.server.wm.proto.AppWindowTokenProto.WINDOW_TOKEN;
+import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN;
+import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED;
+import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN;
+import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT;
+import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT;
+import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
+import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
+import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
+import static com.android.server.wm.AppWindowTokenProto.IS_REALLY_ANIMATING;
+import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
+import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
+import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING;
+import static com.android.server.wm.AppWindowTokenProto.NAME;
+import static com.android.server.wm.AppWindowTokenProto.NUM_DRAWN_WINDOWS;
+import static com.android.server.wm.AppWindowTokenProto.NUM_INTERESTING_WINDOWS;
+import static com.android.server.wm.AppWindowTokenProto.REMOVED;
+import static com.android.server.wm.AppWindowTokenProto.REPORTED_DRAWN;
+import static com.android.server.wm.AppWindowTokenProto.REPORTED_VISIBLE;
+import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED;
+import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
+import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
+import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
+import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
 
 import android.annotation.CallSuper;
 import android.app.Activity;
@@ -1482,11 +1482,13 @@
 
     void layoutLetterbox(WindowState winHint) {
         final WindowState w = findMainWindow();
-        if (w != winHint && winHint != null && w != null) {
+        if (w == null || winHint != null && w != winHint) {
             return;
         }
-        final boolean needsLetterbox = w != null && w.isLetterboxedAppWindow()
-                && fillsParent() && w.hasDrawnLw();
+        final boolean surfaceReady = w.hasDrawnLw()  // Regular case
+                || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
+                || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
+        final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady;
         if (needsLetterbox) {
             if (mLetterbox == null) {
                 mLetterbox = new Letterbox(() -> makeChildSurface(null));
@@ -1696,7 +1698,10 @@
                 stack.getBounds(mTmpRect);
                 mTmpRect.offsetTo(0, 0);
             }
-            if (mService.mAppTransition.getRemoteAnimationController() != null) {
+
+            // Delaying animation start isn't compatible with remote animations at all.
+            if (mService.mAppTransition.getRemoteAnimationController() != null
+                    && !mSurfaceAnimator.isAnimationStartDelayed()) {
                 adapter = mService.mAppTransition.getRemoteAnimationController()
                         .createAnimationAdapter(this, mTmpPoint, mTmpRect);
             } else {
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 2c2389b..627c629 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -29,9 +29,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
 import static android.app.WindowConfiguration.windowingModeToString;
-import static com.android.server.wm.proto.ConfigurationContainerProto.FULL_CONFIGURATION;
-import static com.android.server.wm.proto.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
-import static com.android.server.wm.proto.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
+import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
+import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
+import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
 
 import android.annotation.CallSuper;
 import android.app.WindowConfiguration;
@@ -470,7 +470,7 @@
 
     /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at
-     * {@link com.android.server.wm.proto.ConfigurationContainerProto}.
+     * {@link com.android.server.wm.ConfigurationContainerProto}.
      *
      * @param proto    Stream to write the ConfigurationContainer object to.
      * @param fieldId  Field Id of the ConfigurationContainer as defined in the parent
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 5c62987..d000bb6 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -16,10 +16,10 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.proto.AlphaAnimationSpecProto.DURATION;
-import static com.android.server.wm.proto.AlphaAnimationSpecProto.FROM;
-import static com.android.server.wm.proto.AlphaAnimationSpecProto.TO;
-import static com.android.server.wm.proto.AnimationSpecProto.ALPHA;
+import static com.android.server.wm.AlphaAnimationSpecProto.DURATION;
+import static com.android.server.wm.AlphaAnimationSpecProto.FROM;
+import static com.android.server.wm.AlphaAnimationSpecProto.TO;
+import static com.android.server.wm.AnimationSpecProto.ALPHA;
 
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e2e1690..3e47ea6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -101,19 +101,19 @@
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.proto.DisplayProto.ABOVE_APP_WINDOWS;
-import static com.android.server.wm.proto.DisplayProto.BELOW_APP_WINDOWS;
-import static com.android.server.wm.proto.DisplayProto.DISPLAY_FRAMES;
-import static com.android.server.wm.proto.DisplayProto.DISPLAY_INFO;
-import static com.android.server.wm.proto.DisplayProto.DOCKED_STACK_DIVIDER_CONTROLLER;
-import static com.android.server.wm.proto.DisplayProto.DPI;
-import static com.android.server.wm.proto.DisplayProto.ID;
-import static com.android.server.wm.proto.DisplayProto.IME_WINDOWS;
-import static com.android.server.wm.proto.DisplayProto.PINNED_STACK_CONTROLLER;
-import static com.android.server.wm.proto.DisplayProto.ROTATION;
-import static com.android.server.wm.proto.DisplayProto.SCREEN_ROTATION_ANIMATION;
-import static com.android.server.wm.proto.DisplayProto.STACKS;
-import static com.android.server.wm.proto.DisplayProto.WINDOW_CONTAINER;
+import static com.android.server.wm.DisplayProto.ABOVE_APP_WINDOWS;
+import static com.android.server.wm.DisplayProto.BELOW_APP_WINDOWS;
+import static com.android.server.wm.DisplayProto.DISPLAY_FRAMES;
+import static com.android.server.wm.DisplayProto.DISPLAY_INFO;
+import static com.android.server.wm.DisplayProto.DOCKED_STACK_DIVIDER_CONTROLLER;
+import static com.android.server.wm.DisplayProto.DPI;
+import static com.android.server.wm.DisplayProto.ID;
+import static com.android.server.wm.DisplayProto.IME_WINDOWS;
+import static com.android.server.wm.DisplayProto.PINNED_STACK_CONTROLLER;
+import static com.android.server.wm.DisplayProto.ROTATION;
+import static com.android.server.wm.DisplayProto.SCREEN_ROTATION_ANIMATION;
+import static com.android.server.wm.DisplayProto.STACKS;
+import static com.android.server.wm.DisplayProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
@@ -3807,9 +3807,15 @@
         // we use relative layering of the IME targets child windows, and place the
         // IME in the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
         //
+        // In the case the IME target is animating, the animation Z order may be different
+        // than the WindowContainer Z order, so it's difficult to be sure we have the correct
+        // IME target. In this case we just layer the IME over all transitions by placing it in the
+        // above applications layer.
+        //
         // In the case where we have no IME target we assign it where it's base layer would
         // place it in the AboveAppWindowContainers.
-        if (imeTarget != null && !imeTarget.inSplitScreenWindowingMode()
+        if (imeTarget != null && !(imeTarget.inSplitScreenWindowingMode()
+                || imeTarget.mToken.isAppAnimating())
                 && (imeTarget.getSurfaceControl() != null)) {
             mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 57693ac..dc6b491 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -19,7 +19,7 @@
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
-import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
+import static com.android.server.wm.DisplayFramesProto.STABLE_BOUNDS;
 
 import android.annotation.NonNull;
 import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b99e85f..5e2bb10 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -34,7 +34,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
 import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
-import static com.android.server.wm.proto.DockedStackDividerControllerProto.MINIMIZED_DOCK;
+import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK;
 
 import android.content.Context;
 import android.content.res.Configuration;
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 3f1fde9..529aacc 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -16,8 +16,8 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.proto.AnimationAdapterProto.LOCAL;
-import static com.android.server.wm.proto.LocalAnimationAdapterProto.ANIMATION_SPEC;
+import static com.android.server.wm.AnimationAdapterProto.LOCAL;
+import static com.android.server.wm.LocalAnimationAdapterProto.ANIMATION_SPEC;
 
 import android.os.SystemClock;
 import android.util.proto.ProtoOutputStream;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 2293fb2..5f1916d 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -22,8 +22,8 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.PinnedStackControllerProto.DEFAULT_BOUNDS;
-import static com.android.server.wm.proto.PinnedStackControllerProto.MOVEMENT_BOUNDS;
+import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS;
+import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS;
 
 import android.app.RemoteAction;
 import android.content.pm.ParceledListSlice;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3e72a71..19d6691 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -26,8 +26,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
-import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.WindowConfiguration;
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index d645110..c590067 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -19,8 +19,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -99,6 +99,10 @@
         mFinishedCallback = new FinishedCallback(this);
 
         final RemoteAnimationTarget[] animations = createAnimations();
+        if (animations.length == 0) {
+            onAnimationFinished();
+            return;
+        }
         mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
             try {
                 mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
@@ -132,6 +136,8 @@
                     mPendingAnimations.get(i).createRemoteAppAnimation();
             if (target != null) {
                 targets.add(target);
+            } else {
+                mPendingAnimations.remove(i);
             }
         }
         return targets.toArray(new RemoteAnimationTarget[targets.size()]);
@@ -225,10 +231,8 @@
         RemoteAnimationTarget createRemoteAppAnimation() {
             final Task task = mAppWindowToken.getTask();
             final WindowState mainWindow = mAppWindowToken.findMainWindow();
-            if (task == null) {
-                return null;
-            }
-            if (mainWindow == null) {
+            if (task == null || mainWindow == null || mCapturedFinishCallback == null
+                    || mCapturedLeash == null) {
                 return null;
             }
             mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 32ae523..52d8177 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -84,9 +84,9 @@
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.proto.RootWindowContainerProto.DISPLAYS;
-import static com.android.server.wm.proto.RootWindowContainerProto.WINDOWS;
-import static com.android.server.wm.proto.RootWindowContainerProto.WINDOW_CONTAINER;
+import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
+import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
+import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
 
 /** Root {@link WindowContainer} for the device. */
 class RootWindowContainer extends WindowContainer<DisplayContent> {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 235f63e..fa8a5c6 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -23,8 +23,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
-import static com.android.server.wm.proto.ScreenRotationAnimationProto.ANIMATION_RUNNING;
-import static com.android.server.wm.proto.ScreenRotationAnimationProto.STARTED;
+import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
+import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
 
 import android.content.Context;
 import android.graphics.Matrix;
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index f10ff8c..ba3d091 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -19,9 +19,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.SurfaceAnimatorProto.ANIMATION_ADAPTER;
-import static com.android.server.wm.proto.SurfaceAnimatorProto.ANIMATION_START_DELAYED;
-import static com.android.server.wm.proto.SurfaceAnimatorProto.LEASH;
+import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_ADAPTER;
+import static com.android.server.wm.SurfaceAnimatorProto.ANIMATION_START_DELAYED;
+import static com.android.server.wm.SurfaceAnimatorProto.LEASH;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -234,6 +234,10 @@
         mService.mAnimationTransferMap.put(mAnimation, this);
     }
 
+    boolean isAnimationStartDelayed() {
+        return mAnimationStartDelayed;
+    }
+
     /**
      * Cancels the animation, and resets the leash.
      *
@@ -310,7 +314,7 @@
 
     /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
-     * com.android.server.wm.proto.SurfaceAnimatorProto}.
+     * com.android.server.wm.SurfaceAnimatorProto}.
      *
      * @param proto Stream to write the SurfaceAnimator object to.
      * @param fieldId Field Id of the SurfaceAnimator as defined in the parent message.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a403e6f2..e4722f9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -26,13 +26,13 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.TaskProto.APP_WINDOW_TOKENS;
-import static com.android.server.wm.proto.TaskProto.BOUNDS;
-import static com.android.server.wm.proto.TaskProto.DEFER_REMOVAL;
-import static com.android.server.wm.proto.TaskProto.FILLS_PARENT;
-import static com.android.server.wm.proto.TaskProto.ID;
-import static com.android.server.wm.proto.TaskProto.TEMP_INSET_BOUNDS;
-import static com.android.server.wm.proto.TaskProto.WINDOW_CONTAINER;
+import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
+import static com.android.server.wm.TaskProto.BOUNDS;
+import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
+import static com.android.server.wm.TaskProto.FILLS_PARENT;
+import static com.android.server.wm.TaskProto.ID;
+import static com.android.server.wm.TaskProto.TEMP_INSET_BOUNDS;
+import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
 import android.app.ActivityManager.TaskDescription;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 460edec..900e2df 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -35,18 +35,18 @@
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.StackProto.ADJUSTED_BOUNDS;
-import static com.android.server.wm.proto.StackProto.ADJUSTED_FOR_IME;
-import static com.android.server.wm.proto.StackProto.ADJUST_DIVIDER_AMOUNT;
-import static com.android.server.wm.proto.StackProto.ADJUST_IME_AMOUNT;
-import static com.android.server.wm.proto.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING;
-import static com.android.server.wm.proto.StackProto.BOUNDS;
-import static com.android.server.wm.proto.StackProto.DEFER_REMOVAL;
-import static com.android.server.wm.proto.StackProto.FILLS_PARENT;
-import static com.android.server.wm.proto.StackProto.ID;
-import static com.android.server.wm.proto.StackProto.MINIMIZE_AMOUNT;
-import static com.android.server.wm.proto.StackProto.TASKS;
-import static com.android.server.wm.proto.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
+import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
+import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
+import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT;
+import static com.android.server.wm.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING;
+import static com.android.server.wm.StackProto.BOUNDS;
+import static com.android.server.wm.StackProto.DEFER_REMOVAL;
+import static com.android.server.wm.StackProto.FILLS_PARENT;
+import static com.android.server.wm.StackProto.ID;
+import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
+import static com.android.server.wm.StackProto.TASKS;
+import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
 import android.content.res.Configuration;
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index a41eba8..7b7cb30 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -19,8 +19,8 @@
 import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
-import static com.android.server.wm.proto.AnimationSpecProto.WINDOW;
-import static com.android.server.wm.proto.WindowAnimationSpecProto.ANIMATION;
+import static com.android.server.wm.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
 
 import android.graphics.Point;
 import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5ae4dc5..28fdaae 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -23,10 +23,10 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
-import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
-import static com.android.server.wm.proto.WindowContainerProto.SURFACE_ANIMATOR;
-import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
+import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
+import static com.android.server.wm.WindowContainerProto.ORIENTATION;
+import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
+import static com.android.server.wm.WindowContainerProto.VISIBLE;
 
 import android.annotation.CallSuper;
 import android.content.res.Configuration;
@@ -285,7 +285,14 @@
         }
 
         if (mSurfaceControl != null) {
-            getPendingTransaction().destroy(mSurfaceControl);
+            mPendingTransaction.destroy(mSurfaceControl);
+
+            // Merge to parent transaction to ensure the transactions on this WindowContainer are
+            // applied in native even if WindowContainer is removed.
+            if (mParent != null) {
+                mParent.getPendingTransaction().merge(mPendingTransaction);
+            }
+
             mSurfaceControl = null;
             scheduleAnimation();
         }
@@ -980,7 +987,7 @@
 
     /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at
-     * {@link com.android.server.wm.proto.WindowContainerProto}.
+     * {@link com.android.server.wm.WindowContainerProto}.
      *
      * @param proto     Stream to write the WindowContainer object to.
      * @param fieldId   Field Id of the WindowContainer as defined in the parent message.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5f0769d..56b314f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -48,6 +48,7 @@
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -97,15 +98,15 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.APP_TRANSITION;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.DISPLAY_FROZEN;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.FOCUSED_APP;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.FOCUSED_WINDOW;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.INPUT_METHOD_WINDOW;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.LAST_ORIENTATION;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.POLICY;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
-import static com.android.server.wm.proto.WindowManagerServiceDumpProto.ROTATION;
+import static com.android.server.wm.WindowManagerServiceDumpProto.APP_TRANSITION;
+import static com.android.server.wm.WindowManagerServiceDumpProto.DISPLAY_FROZEN;
+import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_APP;
+import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_WINDOW;
+import static com.android.server.wm.WindowManagerServiceDumpProto.INPUT_METHOD_WINDOW;
+import static com.android.server.wm.WindowManagerServiceDumpProto.LAST_ORIENTATION;
+import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
+import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerServiceDumpProto.ROTATION;
 
 import android.Manifest;
 import android.Manifest.permission;
@@ -1214,8 +1215,10 @@
                     }
                 }
                 final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
+                final boolean isRoundedCornerOverlay =
+                        (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
                 token = new WindowToken(this, binder, type, false, displayContent,
-                        session.mCanAddInternalSystemWindow);
+                        session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
                 if (atoken == null) {
@@ -6179,7 +6182,7 @@
 
     /**
      * Write to a protocol buffer output stream. Protocol buffer message definition is at
-     * {@link com.android.server.wm.proto.WindowManagerServiceDumpProto}.
+     * {@link com.android.server.wm.WindowManagerServiceDumpProto}.
      *
      * @param proto     Stream to write the WindowContainer object to.
      * @param trim      If true, reduce the amount of data written.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index eebf2fd..993556f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -107,50 +107,50 @@
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
-import static com.android.server.wm.proto.IdentifierProto.TITLE;
-import static com.android.server.wm.proto.IdentifierProto.USER_ID;
-import static com.android.server.wm.proto.AnimationSpecProto.MOVE;
-import static com.android.server.wm.proto.MoveAnimationSpecProto.DURATION;
-import static com.android.server.wm.proto.MoveAnimationSpecProto.FROM;
-import static com.android.server.wm.proto.MoveAnimationSpecProto.TO;
-import static com.android.server.wm.proto.WindowStateProto.ANIMATING_EXIT;
-import static com.android.server.wm.proto.WindowStateProto.ANIMATOR;
-import static com.android.server.wm.proto.WindowStateProto.ATTRIBUTES;
-import static com.android.server.wm.proto.WindowStateProto.CHILD_WINDOWS;
-import static com.android.server.wm.proto.WindowStateProto.CONTAINING_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.CONTENT_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.CONTENT_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.CUTOUT;
-import static com.android.server.wm.proto.WindowStateProto.DECOR_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.DESTROYING;
-import static com.android.server.wm.proto.WindowStateProto.DISPLAY_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.DISPLAY_ID;
-import static com.android.server.wm.proto.WindowStateProto.FRAME;
-import static com.android.server.wm.proto.WindowStateProto.GIVEN_CONTENT_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.HAS_SURFACE;
-import static com.android.server.wm.proto.WindowStateProto.IDENTIFIER;
-import static com.android.server.wm.proto.WindowStateProto.IS_ON_SCREEN;
-import static com.android.server.wm.proto.WindowStateProto.IS_READY_FOR_DISPLAY;
-import static com.android.server.wm.proto.WindowStateProto.IS_VISIBLE;
-import static com.android.server.wm.proto.WindowStateProto.OUTSETS;
-import static com.android.server.wm.proto.WindowStateProto.OUTSET_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.OVERSCAN_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.OVERSCAN_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.PARENT_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.REMOVED;
-import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
-import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
-import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
-import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
-import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.SURFACE_POSITION;
-import static com.android.server.wm.proto.WindowStateProto.SYSTEM_UI_VISIBILITY;
-import static com.android.server.wm.proto.WindowStateProto.VIEW_VISIBILITY;
-import static com.android.server.wm.proto.WindowStateProto.VISIBLE_FRAME;
-import static com.android.server.wm.proto.WindowStateProto.VISIBLE_INSETS;
-import static com.android.server.wm.proto.WindowStateProto.WINDOW_CONTAINER;
+import static com.android.server.wm.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.IdentifierProto.TITLE;
+import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.AnimationSpecProto.MOVE;
+import static com.android.server.wm.MoveAnimationSpecProto.DURATION;
+import static com.android.server.wm.MoveAnimationSpecProto.FROM;
+import static com.android.server.wm.MoveAnimationSpecProto.TO;
+import static com.android.server.wm.WindowStateProto.ANIMATING_EXIT;
+import static com.android.server.wm.WindowStateProto.ANIMATOR;
+import static com.android.server.wm.WindowStateProto.ATTRIBUTES;
+import static com.android.server.wm.WindowStateProto.CHILD_WINDOWS;
+import static com.android.server.wm.WindowStateProto.CONTAINING_FRAME;
+import static com.android.server.wm.WindowStateProto.CONTENT_FRAME;
+import static com.android.server.wm.WindowStateProto.CONTENT_INSETS;
+import static com.android.server.wm.WindowStateProto.CUTOUT;
+import static com.android.server.wm.WindowStateProto.DECOR_FRAME;
+import static com.android.server.wm.WindowStateProto.DESTROYING;
+import static com.android.server.wm.WindowStateProto.DISPLAY_FRAME;
+import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
+import static com.android.server.wm.WindowStateProto.FRAME;
+import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
+import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
+import static com.android.server.wm.WindowStateProto.IDENTIFIER;
+import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN;
+import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
+import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
+import static com.android.server.wm.WindowStateProto.OUTSETS;
+import static com.android.server.wm.WindowStateProto.OUTSET_FRAME;
+import static com.android.server.wm.WindowStateProto.OVERSCAN_FRAME;
+import static com.android.server.wm.WindowStateProto.OVERSCAN_INSETS;
+import static com.android.server.wm.WindowStateProto.PARENT_FRAME;
+import static com.android.server.wm.WindowStateProto.REMOVED;
+import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT;
+import static com.android.server.wm.WindowStateProto.REQUESTED_HEIGHT;
+import static com.android.server.wm.WindowStateProto.REQUESTED_WIDTH;
+import static com.android.server.wm.WindowStateProto.STABLE_INSETS;
+import static com.android.server.wm.WindowStateProto.STACK_ID;
+import static com.android.server.wm.WindowStateProto.SURFACE_INSETS;
+import static com.android.server.wm.WindowStateProto.SURFACE_POSITION;
+import static com.android.server.wm.WindowStateProto.SYSTEM_UI_VISIBILITY;
+import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
+import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME;
+import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS;
+import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
 import android.app.AppOpsManager;
@@ -859,10 +859,12 @@
         // If the task has temp inset bounds set, we have to make sure all its windows uses
         // the temp inset frame. Otherwise different display frames get applied to the main
         // window and the child window, making them misaligned.
-        if (inFullscreenContainer || isLetterboxedAppWindow()) {
-            mInsetFrame.setEmpty();
-        } else if (task != null && isInMultiWindowMode()) {
+        // Otherwise we need to clear the inset frame, to avoid using a stale frame after leaving
+        // multi window mode.
+        if (task != null && isInMultiWindowMode()) {
             task.getTempInsetBounds(mInsetFrame);
+        } else {
+            mInsetFrame.setEmpty();
         }
 
         // Denotes the actual frame used to calculate the insets and to perform the layout. When
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0c2b075..e92d460 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -41,10 +41,10 @@
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.proto.WindowStateAnimatorProto.DRAW_STATE;
-import static com.android.server.wm.proto.WindowStateAnimatorProto.LAST_CLIP_RECT;
-import static com.android.server.wm.proto.WindowStateAnimatorProto.SURFACE;
-import static com.android.server.wm.proto.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
+import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
+import static com.android.server.wm.WindowStateAnimatorProto.LAST_CLIP_RECT;
+import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
+import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
 
 import android.content.Context;
 import android.graphics.Matrix;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f6c0a54..66c8cca 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -25,8 +25,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.proto.WindowSurfaceControllerProto.LAYER;
-import static com.android.server.wm.proto.WindowSurfaceControllerProto.SHOWN;
+import static com.android.server.wm.WindowSurfaceControllerProto.LAYER;
+import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN;
 
 import android.graphics.Point;
 import android.graphics.PointF;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 172efdc..14680d9 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,18 +17,19 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-import static com.android.server.wm.proto.WindowTokenProto.HASH_CODE;
-import static com.android.server.wm.proto.WindowTokenProto.HIDDEN;
-import static com.android.server.wm.proto.WindowTokenProto.PAUSED;
-import static com.android.server.wm.proto.WindowTokenProto.WAITING_TO_SHOW;
-import static com.android.server.wm.proto.WindowTokenProto.WINDOWS;
-import static com.android.server.wm.proto.WindowTokenProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowTokenProto.HASH_CODE;
+import static com.android.server.wm.WindowTokenProto.HIDDEN;
+import static com.android.server.wm.WindowTokenProto.PAUSED;
+import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
+import static com.android.server.wm.WindowTokenProto.WINDOWS;
+import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
 import android.os.Debug;
@@ -53,6 +54,9 @@
     // The type of window this token is for, as per WindowManager.LayoutParams.
     final int windowType;
 
+    /** {@code true} if this holds the rounded corner overlay */
+    final boolean mRoundedCornerOverlay;
+
     // Set if this token was explicitly added by a client, so should
     // persist (not be removed) when all windows are removed.
     boolean mPersistOnEmpty;
@@ -105,11 +109,18 @@
 
     WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
             DisplayContent dc, boolean ownerCanManageAppTokens) {
+        this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
+                false /* roundedCornersOverlay */);
+    }
+
+    WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
+            DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
         super(service);
         token = _token;
         windowType = type;
         mPersistOnEmpty = persistOnEmpty;
         mOwnerCanManageAppTokens = ownerCanManageAppTokens;
+        mRoundedCornerOverlay = roundedCornerOverlay;
         onDisplayChanged(dc);
     }
 
@@ -259,6 +270,12 @@
         dc.reParentWindowToken(this);
         mDisplayContent = dc;
 
+        // The rounded corner overlay should not be rotated. We ensure that by moving it outside
+        // the windowing layer.
+        if (mRoundedCornerOverlay) {
+            mDisplayContent.reparentToOverlay(mPendingTransaction, mSurfaceControl);
+        }
+
         // TODO(b/36740756): One day this should perhaps be hooked
         // up with goodToGo, so we don't move a window
         // to another display before the window behind
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index a299781..8fa56bb 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -17,13 +17,13 @@
 package com.android.server.wm;
 
 import static android.os.Build.IS_USER;
-import static com.android.server.wm.proto.WindowManagerTraceFileProto.ENTRY;
-import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER;
-import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
-import static com.android.server.wm.proto.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
-import static com.android.server.wm.proto.WindowManagerTraceProto.WHERE;
-import static com.android.server.wm.proto.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
+import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+import static com.android.server.wm.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
+import static com.android.server.wm.WindowManagerTraceProto.WHERE;
+import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
 
 import android.content.Context;
 import android.os.ShellCommand;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index cf42c0c..dcee151 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -125,6 +125,9 @@
     }
 };
 
+// Must match the value from GnssMeasurement.java
+static const uint32_t ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
+
 sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
 sp<IGnss_V1_0> gnssHal = nullptr;
 sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
@@ -807,7 +810,8 @@
     SET(PseudorangeRateUncertaintyMetersPerSecond,
         measurement->pseudorangeRateUncertaintyMps);
     SET(AccumulatedDeltaRangeState,
-        (static_cast<int32_t>(measurement->accumulatedDeltaRangeState)));
+        (static_cast<int32_t>(measurement->accumulatedDeltaRangeState) &
+        !ADR_STATE_HALF_CYCLE_REPORTED)); // Half Cycle state not reported from Hardware in V1_0
     SET(AccumulatedDeltaRangeMeters, measurement->accumulatedDeltaRangeM);
     SET(AccumulatedDeltaRangeUncertaintyMeters,
         measurement->accumulatedDeltaRangeUncertaintyM);
@@ -888,9 +892,10 @@
         if (measurements_v1_1 != NULL) {
             translateGnssMeasurement_V1_0(env, &(measurements_v1_1[i].v1_0), object);
 
-            // Set the V1_1 flag
+            // Set the V1_1 flag, and mark that new field has valid information for Java Layer
             SET(AccumulatedDeltaRangeState,
-                    static_cast<int32_t>(measurements_v1_1[i].accumulatedDeltaRangeState));
+                    (static_cast<int32_t>(measurements_v1_1[i].accumulatedDeltaRangeState) |
+                    ADR_STATE_HALF_CYCLE_REPORTED));
         } else {
             translateGnssMeasurement_V1_0(env, &(measurements_v1_0[i]), object);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6a9b862..2e07703 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -107,7 +107,9 @@
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
+import android.app.backup.BackupManager;
 import android.app.backup.IBackupManager;
+import android.app.backup.ISelectBackupTransportCallback;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
@@ -252,6 +254,7 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
@@ -9249,7 +9252,7 @@
             long id = mInjector.binderClearCallingIdentity();
             try {
                 return mIPackageManager.setPackagesSuspendedAsUser(
-                        packageNames, suspended, callingUserId);
+                        packageNames, suspended, null, null, "android", callingUserId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed talking to the package manager", re);
@@ -11997,20 +12000,32 @@
     }
 
     @Override
-    public void setMandatoryBackupTransport(
-            ComponentName admin, ComponentName backupTransportComponent) {
+    public boolean setMandatoryBackupTransport(
+            ComponentName admin,
+            ComponentName backupTransportComponent) {
         if (!mHasFeature) {
-            return;
+            return false;
         }
         Preconditions.checkNotNull(admin);
         synchronized (this) {
-            ActiveAdmin activeAdmin =
-                    getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-            if (!Objects.equals(backupTransportComponent, activeAdmin.mandatoryBackupTransport)) {
-                activeAdmin.mandatoryBackupTransport = backupTransportComponent;
-                saveSettingsLocked(UserHandle.USER_SYSTEM);
-            }
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
+
+        final int callingUid = mInjector.binderGetCallingUid();
+        final AtomicBoolean success = new AtomicBoolean(false);
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        final ISelectBackupTransportCallback selectBackupTransportCallbackInternal =
+                new ISelectBackupTransportCallback.Stub() {
+                    public void onSuccess(String transportName) {
+                        saveMandatoryBackupTransport(admin, callingUid, backupTransportComponent);
+                        success.set(true);
+                        countDownLatch.countDown();
+                    }
+
+                    public void onFailure(int reason) {
+                        countDownLatch.countDown();
+                    }
+                };
         final long identity = mInjector.binderClearCallingIdentity();
         try {
             IBackupManager ibm = mInjector.getIBackupManager();
@@ -12018,14 +12033,39 @@
                 if (!ibm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
                     ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
                 }
-                ibm.selectBackupTransportAsync(backupTransportComponent, null);
-                ibm.setBackupEnabled(true);
+                ibm.selectBackupTransportAsync(
+                        backupTransportComponent, selectBackupTransportCallbackInternal);
+                countDownLatch.await();
+                if (success.get()) {
+                    ibm.setBackupEnabled(true);
+                }
+            } else if (backupTransportComponent == null) {
+                saveMandatoryBackupTransport(admin, callingUid, backupTransportComponent);
+                success.set(true);
             }
         } catch (RemoteException e) {
             throw new IllegalStateException("Failed to set mandatory backup transport.", e);
+        } catch (InterruptedException e) {
+            throw new IllegalStateException("Failed to set mandatory backup transport.", e);
         } finally {
             mInjector.binderRestoreCallingIdentity(identity);
         }
+        return success.get();
+    }
+
+    synchronized private void saveMandatoryBackupTransport(
+            ComponentName admin, int callingUid, ComponentName backupTransportComponent) {
+        ActiveAdmin activeAdmin =
+                getActiveAdminWithPolicyForUidLocked(
+                        admin,
+                        DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
+                        callingUid);
+        if (!Objects.equals(backupTransportComponent,
+                activeAdmin.mandatoryBackupTransport)) {
+            activeAdmin.mandatoryBackupTransport =
+                    backupTransportComponent;
+            saveSettingsLocked(UserHandle.USER_SYSTEM);
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d165a45..6f50ee2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -705,6 +705,11 @@
             mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
             traceEnd();
         }
+
+        // Tracks cpu time spent in binder calls
+        traceBeginAndSlog("StartBinderCallsStatsService");
+        BinderCallsStatsService.start();
+        traceEnd();
     }
 
     /**
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index d0398ad..f603a09 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -148,22 +148,16 @@
         Looper backupLooper = startBackupThreadAndGetLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
         mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper);
-        Handler mainHandler = new Handler(Looper.getMainLooper());
 
         mBackupManager = spy(FakeIBackupManager.class);
 
-        BackupAgentTimeoutParameters agentTimeoutParameters =
-                new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver());
-        agentTimeoutParameters.start();
-
         setUpBackupManagerServiceBasics(
                 mBackupManagerService,
                 application,
                 mTransportManager,
                 packageManager,
                 mBackupHandler,
-                mWakeLock,
-                agentTimeoutParameters);
+                mWakeLock);
         when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
         when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
         when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 869c50b..03792b1 100644
--- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -41,14 +41,12 @@
 import android.app.backup.RestoreSet;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.EventLogTags;
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.internal.BackupHandler;
@@ -117,15 +115,6 @@
 
         Looper backupLooper = startBackupThreadAndGetLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
-
-        Handler mainHandler = new Handler(Looper.getMainLooper());
-        BackupAgentTimeoutParameters agentTimeoutParameters =
-                new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver());
-        agentTimeoutParameters.start();
-
-        // We need to mock BMS timeout parameters before initializing the BackupHandler since
-        // the constructor of BackupHandler relies on the timeout parameters.
-        when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
         BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
 
         mWakeLock = createBackupWakeLock(application);
@@ -136,8 +125,7 @@
                 mTransportManager,
                 application.getPackageManager(),
                 backupHandler,
-                mWakeLock,
-                agentTimeoutParameters);
+                mWakeLock);
         when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>());
     }
 
diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index 5a886e3..c210fde 100644
--- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -28,7 +28,6 @@
 import android.os.PowerManager;
 import android.util.SparseArray;
 
-import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.internal.BackupHandler;
@@ -44,8 +43,7 @@
             TransportManager transportManager,
             PackageManager packageManager,
             BackupHandler backupHandler,
-            PowerManager.WakeLock wakeLock,
-            BackupAgentTimeoutParameters agentTimeoutParameters) {
+            PowerManager.WakeLock wakeLock) {
         when(backupManagerService.getContext()).thenReturn(context);
         when(backupManagerService.getTransportManager()).thenReturn(transportManager);
         when(backupManagerService.getPackageManager()).thenReturn(packageManager);
@@ -55,7 +53,6 @@
         when(backupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
         when(backupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class));
         when(backupManagerService.getWakelock()).thenReturn(wakeLock);
-        when(backupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
     }
 
     public static PowerManager.WakeLock createBackupWakeLock(Application application) {
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 0ca0a1a..cdb339a 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -36,6 +36,7 @@
 LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl \
     aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
 LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src)
+LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/SuspendTestApp/src)
 
 LOCAL_JAVA_LIBRARIES := \
     android.hidl.manager-V1.0-java \
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 372b8cc..ce98d65 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -62,6 +62,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WATCH_APPOPS" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.SUSPEND_APPS"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 23e5072..082827c 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -15,9 +15,11 @@
 -->
 <configuration description="Runs Frameworks Services Tests.">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="JobTestApp.apk" />
         <option name="test-file-name" value="ConnTestApp.apk" />
+        <option name="test-file-name" value="SuspendTestApp.apk" />
     </target_preparer>
 
     <option name="test-suite-tag" value="apct" />
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 8721d9c..b452ea5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -22,6 +22,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -33,18 +34,27 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+
 import android.app.ActivityManager;
 import android.app.WaitResult;
 import android.content.ComponentName;
+import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseIntArray;
 
 import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.mockito.invocation.InvocationOnMock;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -238,4 +248,21 @@
         verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
                 null /* target */, null /* targetOptions */);
     }
+
+    @Test
+    public void testTopRunningActivityLockedWithNonExistentDisplay() throws Exception {
+        // Create display that ActivityManagerService does not know about
+        final int unknownDisplayId = 100;
+
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0);
+            displayIds.put(0, unknownDisplayId);
+            return null;
+        }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any());
+
+        mSupervisor.mFocusedStack = mock(ActivityStack.class);
+
+        // Supervisor should skip over the non-existent display.
+        assertEquals(null, mSupervisor.topRunningActivityLocked());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
index c348e70..d5a28f6 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -27,8 +27,6 @@
 
 @RunWith(JUnit4.class)
 public class AutofillManagerServiceTest {
-    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
-    private static final boolean ADDS_DEFAULT_BUTTON = true;
 
     @Test
     public void testGetWhitelistedCompatModePackages_null() {
@@ -42,16 +40,8 @@
 
     @Test
     public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
-        if (ADDS_DEFAULT_BUTTON) {
-            final Map<String, String[]> result =
-                    getWhitelistedCompatModePackages("one_is_the_loniest_package");
-            assertThat(result).hasSize(1);
-            assertThat(result.get("one_is_the_loniest_package")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
-                    .containsExactly("one_is_the_loniest_package", null);
-        }
+        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+                .containsExactly("one_is_the_loniest_package", null);
     }
 
     @Test
@@ -80,12 +70,7 @@
     public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
         final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
         assertThat(result).hasSize(1);
-        if (ADDS_DEFAULT_BUTTON) {
-            assertThat(result.get("one")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(result.get("one")).isNull();
-        }
+        assertThat(result.get("one")).isNull();
     }
 
     @Test
@@ -94,12 +79,7 @@
                 getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
         assertThat(result).hasSize(3);
         assertThat(result.get("p1")).asList().containsExactly("p1u1");
-        if (ADDS_DEFAULT_BUTTON) {
-            assertThat(result.get("p2")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(result.get("p2")).isNull();
-        }
+        assertThat(result.get("p2")).isNull();
         assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index 10a21fd..2d5afad 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -32,6 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 
@@ -874,8 +875,8 @@
     }
 
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-            int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage) {
         return new String[0];
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d2fb1ca..43490d3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -57,6 +57,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.PasswordMetrics;
+import android.app.backup.ISelectBackupTransportCallback;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -2264,6 +2265,21 @@
         assertEquals(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE,
                 intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
 
+        // Make the backup transport selection succeed
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                ISelectBackupTransportCallback callback =
+                    (ISelectBackupTransportCallback) invocation.getArguments()[1];
+                if (callback != null) {
+                    callback.onSuccess("");
+                }
+                return null;
+            }
+        }).when(getServices().ibackupManager).selectBackupTransportAsync(
+                any(ComponentName.class), any(ISelectBackupTransportCallback.class));
+
+
         // Backups are not mandatory
         intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_MANDATORY_BACKUPS);
         assertNull(intent);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index b4f8474..92cc537 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.display.BrightnessChangeEvent;
@@ -101,20 +102,24 @@
         assertNull(mInjector.mSensorListener);
         assertNotNull(mInjector.mBroadcastReceiver);
         assertTrue(mInjector.mIdleScheduled);
-        Intent onIntent = new Intent();
-        onIntent.setAction(Intent.ACTION_SCREEN_ON);
-        mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
-                onIntent);
+        mInjector.sendScreenChange(/*screen on */ true);
         assertNotNull(mInjector.mSensorListener);
 
-        Intent offIntent = new Intent();
-        offIntent.setAction(Intent.ACTION_SCREEN_OFF);
-        mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
-                offIntent);
+        mInjector.sendScreenChange(/*screen on */ false);
         assertNull(mInjector.mSensorListener);
 
-        mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
-                onIntent);
+        // Turn screen on while brightness mode is manual
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic */ false);
+        mInjector.sendScreenChange(/*screen on */ true);
+        assertNull(mInjector.mSensorListener);
+
+        // Set brightness mode to automatic while screen is off.
+        mInjector.sendScreenChange(/*screen on */ false);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic */ true);
+        assertNull(mInjector.mSensorListener);
+
+        // Turn on screen while brightness mode is automatic.
+        mInjector.sendScreenChange(/*screen on */ true);
         assertNotNull(mInjector.mSensorListener);
 
         mTracker.stop();
@@ -124,6 +129,37 @@
     }
 
     @Test
+    public void testAdaptiveOnOff() {
+        mInjector.mInteractive = true;
+        mInjector.mIsBrightnessModeAutomatic = false;
+        startTracker(mTracker);
+        assertNull(mInjector.mSensorListener);
+        assertNotNull(mInjector.mBroadcastReceiver);
+        assertNotNull(mInjector.mContentObserver);
+        assertTrue(mInjector.mIdleScheduled);
+
+        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ true);
+        assertNotNull(mInjector.mSensorListener);
+
+        SensorEventListener listener = mInjector.mSensorListener;
+        mInjector.mSensorListener = null;
+        // Duplicate notification
+        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ true);
+        // Sensor shouldn't have been registered as it was already registered.
+        assertNull(mInjector.mSensorListener);
+        mInjector.mSensorListener = listener;
+
+        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ false);
+        assertNull(mInjector.mSensorListener);
+
+        mTracker.stop();
+        assertNull(mInjector.mSensorListener);
+        assertNull(mInjector.mBroadcastReceiver);
+        assertNull(mInjector.mContentObserver);
+        assertFalse(mInjector.mIdleScheduled);
+    }
+
+    @Test
     public void testBrightnessEvent() {
         final int brightness = 20;
 
@@ -618,16 +654,39 @@
         boolean mIdleScheduled;
         boolean mInteractive = true;
         int[] mProfiles;
+        ContentObserver mContentObserver;
+        boolean mIsBrightnessModeAutomatic = true;
 
         public TestInjector(Handler handler) {
             mHandler = handler;
         }
 
-        public void incrementTime(long timeMillis) {
+        void incrementTime(long timeMillis) {
             mCurrentTimeMillis += timeMillis;
             mElapsedRealtimeNanos += TimeUnit.MILLISECONDS.toNanos(timeMillis);
         }
 
+        void setBrightnessMode(boolean isBrightnessModeAutomatic) {
+          mIsBrightnessModeAutomatic = isBrightnessModeAutomatic;
+          mContentObserver.dispatchChange(false, null);
+          waitForHandler();
+        }
+
+        void sendScreenChange(boolean screenOn) {
+            mInteractive = screenOn;
+            Intent intent = new Intent();
+            intent.setAction(screenOn ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF);
+            mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(), intent);
+            waitForHandler();
+        }
+
+        void waitForHandler() {
+            Idle idle = new Idle();
+            mHandler.getLooper().getQueue().addIdleHandler(idle);
+            mHandler.post(() -> {});
+            idle.waitForIdle();
+        }
+
         @Override
         public void registerSensorListener(Context context,
                 SensorEventListener sensorListener, Handler handler) {
@@ -641,6 +700,18 @@
         }
 
         @Override
+        public void registerBrightnessModeObserver(ContentResolver resolver,
+                ContentObserver settingsObserver) {
+            mContentObserver = settingsObserver;
+        }
+
+        @Override
+        public void unregisterBrightnessModeObserver(Context context,
+                ContentObserver settingsObserver) {
+            mContentObserver = null;
+        }
+
+        @Override
         public void registerReceiver(Context context,
                 BroadcastReceiver shutdownReceiver, IntentFilter shutdownFilter) {
             mBroadcastReceiver = shutdownReceiver;
@@ -658,11 +729,9 @@
             return mHandler;
         }
 
-        public void waitForHandler() {
-            Idle idle = new Idle();
-            mHandler.getLooper().getQueue().addIdleHandler(idle);
-            mHandler.post(() -> {});
-            idle.waitForIdle();
+        @Override
+        public boolean isBrightnessModeAutomatic(ContentResolver resolver) {
+            return mIsBrightnessModeAutomatic;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 69796b3..25747b8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -296,7 +296,6 @@
                 keyDerivationParams.getSalt(),
                 TEST_CREDENTIAL);
         Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
-        counterId = 1L; // TODO: use value from the database.
         assertThat(counterId).isNotNull();
         byte[] recoveryKey = decryptThmEncryptedKey(
                 lockScreenHash,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 260bb0a..4664cad 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -300,6 +300,23 @@
     }
 
     @Test
+    public void initRecoveryService_regeneratesCounterId() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+
+        Long counterId0 = mRecoverableKeyStoreDb.getCounterId(userId, uid);
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+        Long counterId1 = mRecoverableKeyStoreDb.getCounterId(userId, uid);
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial + 1));
+        Long counterId2 = mRecoverableKeyStoreDb.getCounterId(userId, uid);
+
+        assertThat(!counterId1.equals(counterId0) || !counterId2.equals(counterId1)).isTrue();
+    }
+
+    @Test
     public void initRecoveryService_throwsIfInvalidCert() throws Exception {
         byte[] modifiedCertXml = TestData.getCertXml();
         modifiedCertXml[modifiedCertXml.length - 50] ^= 1;  // Flip a bit in the certificate
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 53d97e7..ebb4248 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -21,13 +21,12 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -39,12 +38,13 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.UserInfo;
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
-import android.security.keystore.ArrayUtils;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -54,8 +54,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.permission.PermissionManagerInternal;
 import com.android.server.pm.permission.PermissionManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -71,9 +71,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerSettingsTests {
-    private static final String PACKAGE_NAME_2 = "com.google.app2";
+    private static final String PACKAGE_NAME_2 = "com.android.app2";
     private static final String PACKAGE_NAME_3 = "com.android.app3";
-    private static final String PACKAGE_NAME_1 = "com.google.app1";
+    private static final String PACKAGE_NAME_1 = "com.android.app1";
     public static final String TAG = "PackageManagerSettingsTests";
     protected final String PREFIX = "android.content.pm";
 
@@ -156,6 +156,92 @@
         assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
     }
 
+    private PersistableBundle getPersistableBundle(String packageName, long longVal,
+            double doubleVal, boolean boolVal, String textVal) {
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(packageName + ".TEXT_VALUE", textVal);
+        bundle.putLong(packageName + ".LONG_VALUE", longVal);
+        bundle.putBoolean(packageName + ".BOOL_VALUE", boolVal);
+        bundle.putDouble(packageName + ".DOUBLE_VALUE", doubleVal);
+        return bundle;
+    }
+
+    @Test
+    public void testReadPackageRestrictions_oldSuspendInfo() {
+        writePackageRestrictions_oldSuspendInfoXml(0);
+        final Object lock = new Object();
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+
+        final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+        final PackageUserState packageUserState1 = ps1.readUserState(0);
+        assertThat(packageUserState1.suspended, is(true));
+        assertThat("android".equals(packageUserState1.suspendingPackage), is(true));
+
+        final PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
+        final PackageUserState packageUserState2 = ps2.readUserState(0);
+        assertThat(packageUserState2.suspended, is(false));
+        assertThat(packageUserState2.suspendingPackage, is(nullValue()));
+    }
+
+    @Test
+    public void testReadWritePackageRestrictions_newSuspendInfo() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+        final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+        final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+        final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
+
+        final PersistableBundle appExtras1 = getPersistableBundle(
+                PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
+        final PersistableBundle launcherExtras1 = getPersistableBundle(
+                PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
+        ps1.setSuspended(true, "suspendingPackage1", appExtras1, launcherExtras1, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+
+        ps2.setSuspended(true, "suspendingPackage2", null, null, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+
+        ps3.setSuspended(false, "irrelevant", null, null, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+
+        settingsUnderTest.writePackageRestrictionsLPr(0);
+
+        settingsUnderTest.mPackages.clear();
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+        // now read and verify
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+        final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1).
+                readUserState(0);
+        assertThat(readPus1.suspended, is(true));
+        assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
+        assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
+        assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
+                is(true));
+
+        final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2).
+                readUserState(0);
+        assertThat(readPus2.suspended, is(true));
+        assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
+        assertThat(readPus2.suspendedAppExtras, is(nullValue()));
+        assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
+
+        final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
+                readUserState(0);
+        assertThat(readPus3.suspended, is(false));
+    }
+
+    @Test
+    public void testPackageRestrictionsSuspendedDefault() {
+        final PackageSetting defaultSetting =  createPackageSetting(PACKAGE_NAME_1);
+        assertThat(defaultSetting.getSuspended(0), is(false));
+    }
+
     @Test
     public void testEnableDisable() {
         // Write the package files and make sure they're parsed properly the first time
@@ -686,6 +772,26 @@
                 null /*usesStaticLibrariesVersions*/);
     }
 
+    private PackageSetting createPackageSetting(String packageName) {
+        return new PackageSetting(
+                packageName,
+                packageName,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPathString*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                null /*cpuAbiOverrideString*/,
+                INITIAL_VERSION_CODE,
+                0,
+                0 /*privateFlags*/,
+                null /*parentPackageName*/,
+                null /*childPackageNames*/,
+                0,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
+    }
+
     private @NonNull List<UserInfo> createFakeUsers() {
         ArrayList<UserInfo> users = new ArrayList<>();
         users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
@@ -718,13 +824,13 @@
                 + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />"
                 + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />"
                 + "</permissions>"
-                + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
+                + "<package name=\"com.android.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.android.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
                 + "<sigs count=\"1\">"
                 + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />"
                 + "</sigs>"
                 + "<proper-signing-keyset identifier=\"1\" />"
                 + "</package>"
-                + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
+                + "<package name=\"com.android.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.android.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
                 + "<sigs count=\"1\">"
                 + "<cert index=\"0\" />"
                 + "</sigs>"
@@ -774,11 +880,26 @@
                 + "</packages>").getBytes());
     }
 
+    private void writePackageRestrictions_oldSuspendInfoXml(final int userId) {
+        writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/"
+                        + userId + "/package-restrictions.xml"),
+                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                        + "<package-restrictions>\n"
+                        + "    <pkg name=\"" + PACKAGE_NAME_1 + "\" suspended=\"true\" />"
+                        + "    <pkg name=\"" + PACKAGE_NAME_2 + "\" suspended=\"false\" />"
+                        + "    <preferred-activities />\n"
+                        + "    <persistent-preferred-activities />\n"
+                        + "    <crossProfile-intent-filters />\n"
+                        + "    <default-apps />\n"
+                        + "</package-restrictions>\n")
+                        .getBytes());
+    }
+
     private void writeStoppedPackagesXml() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"),
                 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
                 + "<stopped-packages>"
-                + "<pkg name=\"com.google.app1\" nl=\"1\" />"
+                + "<pkg name=\"com.android.app1\" nl=\"1\" />"
                 + "<pkg name=\"com.android.app3\" nl=\"1\" />"
                 + "</stopped-packages>")
                 .getBytes());
@@ -786,8 +907,8 @@
 
     private void writePackagesList() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.list"),
-                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
-                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
+                ( "com.android.app1 11000 0 /data/data/com.android.app1 seinfo1"
+                + "com.android.app2 11001 0 /data/data/com.android.app2 seinfo2"
                 + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
                 .getBytes());
     }
@@ -828,6 +949,11 @@
         });
     }
 
+    @After
+    public void tearDown() throws Exception {
+        deleteFolder(InstrumentationRegistry.getTargetContext().getFilesDir());
+    }
+
     private void verifyKeySetMetaData(Settings settings)
             throws ReflectiveOperationException, IllegalAccessException {
         ArrayMap<String, PackageSetting> packages = settings.mPackages;
@@ -871,9 +997,9 @@
         assertThat(KeySetUtils.getLastIssuedKeySetId(ksms), is(4L));
 
         /* verify packages have been given the appropriate information */
-        PackageSetting ps = packages.get("com.google.app1");
+        PackageSetting ps = packages.get("com.android.app1");
         assertThat(ps.keySetData.getProperSigningKeySet(), is(1L));
-        ps = packages.get("com.google.app2");
+        ps = packages.get("com.android.app2");
         assertThat(ps.keySetData.getProperSigningKeySet(), is(1L));
         assertThat(ps.keySetData.getAliases().get("AB"), is(4L));
         ps = packages.get("com.android.app3");
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 50be8db..4e1418c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.assertThat;
 
 import android.content.pm.PackageUserState;
+import android.os.PersistableBundle;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
 import org.junit.Test;
@@ -170,4 +171,44 @@
         testUserState03.enabledComponents.add("com.android.unit_test_04");
         assertThat(testUserState03.equals(oldUserState), is(false));
     }
+
+    @Test
+    public void testPackageUserState05() {
+        PersistableBundle appExtras1 = new PersistableBundle();
+        PersistableBundle appExtras2 = new PersistableBundle();
+        appExtras1.putInt("appExtraId", 1);
+        appExtras2.putInt("appExtraId", 2);
+        PersistableBundle launcherExtras1 = new PersistableBundle();
+        PersistableBundle launcherExtras2 = new PersistableBundle();
+        launcherExtras1.putString("name", "launcherExtras1");
+        launcherExtras2.putString("name", "launcherExtras2");
+        final String suspendingPackage1 = "package1";
+        final String suspendingPackage2 = "package2";
+
+        final PackageUserState testUserState1 = new PackageUserState();
+        testUserState1.suspended = true;
+        testUserState1.suspendedAppExtras = appExtras1;
+        testUserState1.suspendedLauncherExtras = launcherExtras1;
+        testUserState1.suspendingPackage = suspendingPackage1;
+
+        final PackageUserState testUserState2 = new PackageUserState(testUserState1);
+        assertThat(testUserState1.equals(testUserState2), is(true));
+        testUserState2.suspendingPackage = suspendingPackage2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        testUserState2.suspendingPackage = testUserState1.suspendingPackage;
+        testUserState2.suspendedAppExtras = appExtras2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        testUserState2.suspendedAppExtras = testUserState1.suspendedAppExtras;
+        testUserState2.suspendedLauncherExtras = launcherExtras2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        // Everything is different but irrelevant if suspended is false
+        testUserState2.suspended = testUserState1.suspended = false;
+        testUserState2.suspendedAppExtras = appExtras2;
+        testUserState2.suspendingPackage = suspendingPackage2;
+        assertThat(testUserState1.equals(testUserState2), is(true));
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
new file mode 100644
index 0000000..d702318
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class SuspendPackagesTest {
+    private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
+    private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private Handler mReceiverHandler;
+    private ComponentName mTestReceiverComponent;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mPackageManager = mContext.getPackageManager();
+        mPackageManager.setPackagesSuspended(PACKAGES_TO_SUSPEND, false, null, null, null);
+        mReceiverHandler = new Handler(Looper.getMainLooper());
+        mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
+                SuspendTestReceiver.class.getCanonicalName());
+    }
+
+    private Bundle requestAppAction(String action) throws InterruptedException {
+        final AtomicReference<Bundle> result = new AtomicReference<>();
+        final CountDownLatch receiverLatch = new CountDownLatch(1);
+
+        final Intent broadcastIntent = new Intent(action)
+                .setComponent(mTestReceiverComponent)
+                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                result.set(getResultExtras(true));
+                receiverLatch.countDown();
+            }
+        }, mReceiverHandler, 0, null, null);
+
+        assertTrue("Test receiver timed out ", receiverLatch.await(5, TimeUnit.SECONDS));
+        return result.get();
+    }
+
+    private PersistableBundle getExtras(String keyPrefix, long lval, String sval, double dval) {
+        final PersistableBundle extras = new PersistableBundle(3);
+        extras.putLong(keyPrefix + ".LONG_VALUE", lval);
+        extras.putDouble(keyPrefix + ".DOUBLE_VALUE", dval);
+        extras.putString(keyPrefix + ".STRING_VALUE", sval);
+        return extras;
+    }
+
+    private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras) {
+        final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
+                PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, null);
+        assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
+    }
+
+    @Test
+    public void testIsPackageSuspended() {
+        suspendTestPackage(null, null);
+        assertTrue("isPackageSuspended is false",
+                mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
+    }
+
+    @Test
+    public void testSuspendedStateFromApp() throws Exception {
+        Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
+        assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
+        assertNull(resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+
+        final PersistableBundle appExtras = getExtras("appExtras", 20, "20", 0.2);
+        suspendTestPackage(appExtras, null);
+
+        resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
+        assertTrue("resultFromApp:suspended is false",
+                resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
+        final PersistableBundle receivedAppExtras =
+                resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
+        receivedAppExtras.get(""); // hack to unparcel the bundles
+        appExtras.get("");
+        assertTrue("Received app extras " + receivedAppExtras + " different to the ones supplied",
+                BaseBundle.kindofEquals(appExtras, receivedAppExtras));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 26a7313..64501e4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -68,6 +68,7 @@
         super.setUp();
         MockitoAnnotations.initMocks(this);
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
+        mAdapter.setCallingPid(123);
         sWm.mH.runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
@@ -83,7 +84,7 @@
                     new Point(50, 100), new Rect(50, 100, 150, 150));
             adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
             mController.goodToGo();
-
+            sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
             final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                     ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
             final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
@@ -167,4 +168,33 @@
         mController.goodToGo();
         verifyZeroInteractions(mMockRunner);
     }
+
+    @Test
+    public void testNotReallyStarted() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mController.createAnimationAdapter(win.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150));
+        mController.goodToGo();
+        verifyZeroInteractions(mMockRunner);
+    }
+
+    @Test
+    public void testOneNotStarted() throws Exception {
+        final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
+        final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
+        mController.createAnimationAdapter(win1.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150));
+        final AnimationAdapter adapter = mController.createAnimationAdapter(win2.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150));
+        adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+        mController.goodToGo();
+        sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+        final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+        verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
+        assertEquals(1, appsCaptor.getValue().length);
+        assertEquals(mMockLeash, appsCaptor.getValue()[0].leash);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 6506872..16b8458 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -134,6 +134,7 @@
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         verifyZeroInteractions(mSpec);
         assertAnimating(mAnimatable);
+        assertTrue(mAnimatable.mSurfaceAnimator.isAnimationStartDelayed());
         mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
         verify(mSpec).startAnimation(any(), any(), any());
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
index a3ade1e..5085254 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
@@ -36,7 +36,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.Preconditions;
-import com.android.server.wm.proto.WindowManagerTraceProto;
+import com.android.server.wm.WindowManagerTraceProto;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
new file mode 100644
index 0000000..40a34b9
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SuspendTestApp
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..70a1fd0
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.suspendtestapp">
+
+    <application>
+        <activity android:name=".SuspendTestActivity"
+                  android:exported="true" />
+        <receiver android:name=".SuspendTestReceiver"
+                  android:exported="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
new file mode 100644
index 0000000..fa5fc58
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.servicestests.apps.suspendtestapp;
+
+import android.app.Activity;
+
+public class SuspendTestActivity extends Activity {
+    private static final String TAG = SuspendTestActivity.class.getSimpleName();
+
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
new file mode 100644
index 0000000..6f353a0
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.servicestests.apps.suspendtestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+public class SuspendTestReceiver extends BroadcastReceiver {
+    private static final String TAG = SuspendTestReceiver.class.getSimpleName();
+
+    public static final String PACKAGE_NAME = "com.android.servicestests.apps.suspendtestapp";
+    public static final String ACTION_GET_SUSPENDED_STATE =
+            PACKAGE_NAME + ".action.GET_SUSPENDED_STATE";
+    public static final String EXTRA_SUSPENDED = PACKAGE_NAME + ".extra.SUSPENDED";
+    public static final String EXTRA_SUSPENDED_APP_EXTRAS =
+            PACKAGE_NAME + ".extra.SUSPENDED_APP_EXTRAS";
+
+    private PackageManager mPm;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mPm = context.getPackageManager();
+        Log.d(TAG, "Received request action " + intent.getAction());
+        switch (intent.getAction()) {
+            case ACTION_GET_SUSPENDED_STATE:
+                final Bundle result = new Bundle();
+                final boolean suspended = mPm.isPackageSuspended();
+                final PersistableBundle appExtras = mPm.getSuspendedPackageAppExtras();
+                result.putBoolean(EXTRA_SUSPENDED, suspended);
+                result.putParcelable(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
+                setResult(0, null, result);
+                break;
+            default:
+                Log.e(TAG, "Unknown action: " + intent.getAction());
+        }
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index c4a688b..0f2e56b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -367,6 +367,28 @@
     }
 
     @Test
+    public void testActionsMoreOptionsThanChoices() {
+        PendingIntent intent1 = mock(PendingIntent.class);
+        PendingIntent intent2 = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+
+        Notification n1 = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build())
+                .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1)
+                        .addRemoteInput(new RemoteInput.Builder("a")
+                                .setChoices(new CharSequence[] {"i", "m"})
+                                .build())
+                        .build())
+                .build();
+        Notification n2 = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build())
+                .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1).build())
+                .build();
+
+        assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
+    }
+
+    @Test
     public void testActionsDifferentRemoteInputs() {
         PendingIntent intent = mock(PendingIntent.class);
         Icon icon = mock(Icon.class);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 73243d2..1c0e260 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -881,7 +881,7 @@
          */
         @IntDef(prefix = { "HANDOVER_" },
                 value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED,
-                HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERG_CALL,
+                HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL,
                 HANDOVER_FAILURE_UNKNOWN})
         @Retention(RetentionPolicy.SOURCE)
         public @interface HandoverFailureErrors {}
@@ -939,7 +939,7 @@
          * For more information on call handovers, see
          * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}.
          */
-        public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 4;
+        public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4;
 
         /**
          * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index eebe2a1..c79eec0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2227,7 +2227,9 @@
     /**
      * Gets the configuration values for a particular subscription, which is associated with a
      * specific SIM card. If an invalid subId is used, the returned config will contain default
-     * values.
+     * values. After using this method to get the configuration bundle,
+     * {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether
+     * any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2254,7 +2256,9 @@
     }
 
     /**
-     * Gets the configuration values for the default subscription.
+     * Gets the configuration values for the default subscription. After using this method to get
+     * the configuration bundle, {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be
+     * called to confirm whether any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2283,6 +2287,9 @@
      * <p>
      * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
      * use this method to confirm whether any carrier specific configuration has been applied.
+     * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
+     * still needs to get the current configuration, it must use this method to verify whether the
+     * configuration is default or carrier overridden.
      * </p>
      *
      * @param bundle the configuration bundle to be checked.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0b15191..c5386ef 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -111,6 +111,13 @@
             BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY;
 
     /**
+     * The process name of the Phone app as well as many other apps that use this process name, such
+     * as settings and vendor components.
+     * @hide
+     */
+    public static final String PHONE_PROCESS_NAME = "com.android.phone";
+
+    /**
      * The allowed states of Wi-Fi calling.
      *
      * @hide
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index c073d1a..aaf1a1cf8 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -139,34 +139,44 @@
 
         @Override
         public int queryCapabilityStatus() throws RemoteException {
-            return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+            synchronized (mLock) {
+                return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+            }
         }
 
         @Override
         public void addCapabilityCallback(IImsCapabilityCallback c) {
+            // no need to lock, structure already handles multithreading.
             MmTelFeature.this.addCapabilityCallback(c);
         }
 
         @Override
         public void removeCapabilityCallback(IImsCapabilityCallback c) {
+            // no need to lock, structure already handles multithreading.
             MmTelFeature.this.removeCapabilityCallback(c);
         }
 
         @Override
         public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
                 IImsCapabilityCallback c) throws RemoteException {
-            MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+            synchronized (mLock) {
+                MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+            }
         }
 
         @Override
         public void queryCapabilityConfiguration(int capability, int radioTech,
                 IImsCapabilityCallback c) {
-            queryCapabilityConfigurationInternal(capability, radioTech, c);
+            synchronized (mLock) {
+                queryCapabilityConfigurationInternal(capability, radioTech, c);
+            }
         }
 
         @Override
         public void setSmsListener(IImsSmsListener l) throws RemoteException {
-            MmTelFeature.this.setSmsListener(l);
+            synchronized (mLock) {
+                MmTelFeature.this.setSmsListener(l);
+            }
         }
 
         @Override
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 8ebb77d..c2aca6b 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -54,6 +54,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 
@@ -951,7 +952,8 @@
 
     /** @hide */
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean hidden, int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean hidden,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index cc3366f..0ca20de 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -50,13 +50,18 @@
 
     private static final int TEST_UDP_ENCAP_PORT = 34567;
     private static final int DROID_SPI = 0xD1201D;
+    private static final int DUMMY_RESOURCE_ID = 0x1234;
 
     private static final InetAddress GOOGLE_DNS_4;
+    private static final String VTI_INTF_NAME = "ipsec_test";
+    private static final InetAddress VTI_LOCAL_ADDRESS;
+    private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
 
     static {
         try {
             // Google Public DNS Addresses;
             GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
+            VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
         } catch (UnknownHostException e) {
             throw new RuntimeException("Could not resolve DNS Addresses", e);
         }
@@ -77,9 +82,8 @@
      */
     @Test
     public void testAllocSpi() throws Exception {
-        int resourceId = 1;
         IpSecSpiResponse spiResp =
-                new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
+                new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
         when(mMockIpSecService.allocateSecurityParameterIndex(
                         eq(GOOGLE_DNS_4.getHostAddress()),
                         eq(DROID_SPI),
@@ -92,14 +96,13 @@
 
         droidSpi.close();
 
-        verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
+        verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
     }
 
     @Test
     public void testAllocRandomSpi() throws Exception {
-        int resourceId = 1;
         IpSecSpiResponse spiResp =
-                new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
+                new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
         when(mMockIpSecService.allocateSecurityParameterIndex(
                         eq(GOOGLE_DNS_4.getHostAddress()),
                         eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
@@ -113,7 +116,7 @@
 
         randomSpi.close();
 
-        verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
+        verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
     }
 
     /*
@@ -165,11 +168,10 @@
 
     @Test
     public void testOpenEncapsulationSocket() throws Exception {
-        int resourceId = 1;
         IpSecUdpEncapResponse udpEncapResp =
                 new IpSecUdpEncapResponse(
                         IpSecManager.Status.OK,
-                        resourceId,
+                        DUMMY_RESOURCE_ID,
                         TEST_UDP_ENCAP_PORT,
                         Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
         when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
@@ -182,16 +184,15 @@
 
         encapSocket.close();
 
-        verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
+        verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
     }
 
     @Test
     public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
-        int resourceId = 1;
         IpSecUdpEncapResponse udpEncapResp =
                 new IpSecUdpEncapResponse(
                         IpSecManager.Status.OK,
-                        resourceId,
+                        DUMMY_RESOURCE_ID,
                         TEST_UDP_ENCAP_PORT,
                         Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
 
@@ -206,7 +207,7 @@
 
         encapSocket.close();
 
-        verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
+        verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
     }
 
     @Test
@@ -219,4 +220,45 @@
     }
 
     // TODO: add test when applicable transform builder interface is available
-}
+
+    private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
+            throws Exception {
+        IpSecTunnelInterfaceResponse dummyResponse =
+                new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
+        when(mMockIpSecService.createTunnelInterface(
+                eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
+                anyObject(), anyObject()))
+                        .thenReturn(dummyResponse);
+
+        IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
+                VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
+
+        assertNotNull(tunnelIntf);
+        return tunnelIntf;
+    }
+
+    @Test
+    public void testCreateVti() throws Exception {
+        IpSecManager.IpSecTunnelInterface tunnelIntf =
+                createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
+
+        assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
+
+        tunnelIntf.close();
+        verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+    }
+
+    @Test
+    public void testAddRemoveAddressesFromVti() throws Exception {
+        IpSecManager.IpSecTunnelInterface tunnelIntf =
+                createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
+
+        tunnelIntf.addAddress(VTI_INNER_ADDRESS);
+        verify(mMockIpSecService)
+                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+
+        tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
+        verify(mMockIpSecService)
+                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+    }
+}
\ No newline at end of file
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 3e1ff6d..410f754 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -17,11 +17,13 @@
 package com.android.server;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -32,6 +34,9 @@
 import android.net.IpSecManager;
 import android.net.IpSecSpiResponse;
 import android.net.IpSecTransformResponse;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
+import android.net.Network;
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
@@ -56,10 +61,15 @@
 
     private final String mDestinationAddr;
     private final String mSourceAddr;
+    private final LinkAddress mLocalInnerAddress;
 
     @Parameterized.Parameters
     public static Collection ipSecConfigs() {
-        return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}});
+        return Arrays.asList(
+                new Object[][] {
+                {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
+                {"2601::2", "2601::10", "2001:db8::1/64"}
+        });
     }
 
     private static final byte[] AEAD_KEY = {
@@ -86,6 +96,7 @@
     INetd mMockNetd;
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
+    Network fakeNetwork = new Network(0xAB);
 
     private static final IpSecAlgorithm AUTH_ALGO =
             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
@@ -94,9 +105,11 @@
     private static final IpSecAlgorithm AEAD_ALGO =
             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
 
-    public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) {
+    public IpSecServiceParameterizedTest(
+            String sourceAddr, String destAddr, String localInnerAddr) {
         mSourceAddr = sourceAddr;
         mDestinationAddr = destAddr;
+        mLocalInnerAddress = new LinkAddress(localInnerAddr);
     }
 
     @Before
@@ -308,6 +321,30 @@
     }
 
     @Test
+    public void testReleaseOwnedSpi() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+        IpSecTransformResponse createTransformResp =
+                mIpSecService.createTransform(ipSecConfig, new Binder());
+        IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+        verify(mMockNetd, times(0))
+                .ipSecDeleteSecurityAssociation(
+                        eq(createTransformResp.resourceId),
+                        anyString(),
+                        anyString(),
+                        eq(TEST_SPI),
+                        anyInt(),
+                        anyInt());
+        // quota is not released until the SPI is released by the Transform
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+    }
+
+    @Test
     public void testDeleteTransform() throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -317,7 +354,7 @@
                 mIpSecService.createTransform(ipSecConfig, new Binder());
         mIpSecService.deleteTransform(createTransformResp.resourceId);
 
-        verify(mMockNetd)
+        verify(mMockNetd, times(1))
                 .ipSecDeleteSecurityAssociation(
                         eq(createTransformResp.resourceId),
                         anyString(),
@@ -330,6 +367,21 @@
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
+        assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
+
+        mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
+        // Verify that ipSecDeleteSa was not called when the SPI was released because the
+        // ownedByTransform property should prevent it; (note, the called count is cumulative).
+        verify(mMockNetd, times(1))
+                .ipSecDeleteSecurityAssociation(
+                        anyInt(),
+                        anyString(),
+                        anyString(),
+                        anyInt(),
+                        anyInt(),
+                        anyInt());
+        assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
+
         try {
             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
                     createTransformResp.resourceId);
@@ -406,4 +458,103 @@
 
         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
     }
+
+    private IpSecTunnelInterfaceResponse createAndValidateTunnel(
+            String localAddr, String remoteAddr) {
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                mIpSecService.createTunnelInterface(
+                        mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+
+        assertNotNull(createTunnelResp);
+        assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
+        return createTunnelResp;
+    }
+
+    @Test
+    public void testCreateTunnelInterface() throws Exception {
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+        // Check that we have stored the tracking object, and retrieve it
+        IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.RefcountedResource refcountedRecord =
+                userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+                        createTunnelResp.resourceId);
+
+        assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
+        verify(mMockNetd)
+                .addVirtualTunnelInterface(
+                        eq(createTunnelResp.interfaceName),
+                        eq(mSourceAddr),
+                        eq(mDestinationAddr),
+                        anyInt(),
+                        anyInt());
+    }
+
+    @Test
+    public void testDeleteTunnelInterface() throws Exception {
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+        IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+
+        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+
+        // Verify quota and RefcountedResource objects cleaned up
+        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
+        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+        try {
+            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+                    createTunnelResp.resourceId);
+            fail("Expected IllegalArgumentException on attempt to access deleted resource");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testTunnelInterfaceBinderDeath() throws Exception {
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+        IpSecService.UserRecord userRecord =
+                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.RefcountedResource refcountedRecord =
+                userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+                        createTunnelResp.resourceId);
+
+        refcountedRecord.binderDied();
+
+        // Verify quota and RefcountedResource objects cleaned up
+        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
+        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+        try {
+            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
+                    createTunnelResp.resourceId);
+            fail("Expected IllegalArgumentException on attempt to access deleted resource");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testAddRemoveAddressFromTunnelInterface() throws Exception {
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+
+        mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
+        verify(mMockNetd)
+                .interfaceAddAddress(
+                        eq(createTunnelResp.interfaceName),
+                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
+                        eq(mLocalInnerAddress.getPrefixLength()));
+
+        mIpSecService.removeAddressFromTunnelInterface(
+                createTunnelResp.resourceId, mLocalInnerAddress);
+        verify(mMockNetd)
+                .interfaceDelAddress(
+                        eq(createTunnelResp.interfaceName),
+                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
+                        eq(mLocalInnerAddress.getPrefixLength()));
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
new file mode 100644
index 0000000..4a83d1b
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.connectivity;
+
+import static android.Manifest.permission.CHANGE_NETWORK_STATE;
+import static android.Manifest.permission.CHANGE_WIFI_STATE;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PermissionMonitorTest {
+    private static final int MOCK_UID = 10001;
+    private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" };
+
+    @Mock private Context mContext;
+    @Mock private PackageManager mPackageManager;
+
+    private PermissionMonitor mPermissionMonitor;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.getPackagesForUid(MOCK_UID)).thenReturn(MOCK_PACKAGE_NAMES);
+        mPermissionMonitor = new PermissionMonitor(mContext, null);
+    }
+
+    private void expectPermission(String[] permissions, boolean preinstalled) throws Exception {
+        final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled);
+        when(mPackageManager.getPackageInfo(MOCK_PACKAGE_NAMES[0], GET_PERMISSIONS))
+                .thenReturn(packageInfo);
+    }
+
+    private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) {
+        final PackageInfo packageInfo = new PackageInfo();
+        packageInfo.requestedPermissions = permissions;
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.flags = preinstalled ? FLAG_SYSTEM : 0;
+        return packageInfo;
+    }
+
+    @Test
+    public void testHasPermission() {
+        PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
+        assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+        assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+        assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+        app = packageInfoWithPermissions(new String[] {
+                CHANGE_NETWORK_STATE, NETWORK_STACK
+            }, false);
+        assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+        assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+        assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+
+        app = packageInfoWithPermissions(new String[] {
+                CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
+            }, false);
+        assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+        assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
+        assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+        assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+    }
+
+    @Test
+    public void testIsPreinstalledSystemApp() {
+        PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
+        assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app));
+
+        app = packageInfoWithPermissions(new String[] {}, true);
+        assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app));
+    }
+
+    @Test
+    public void testHasUseBackgroundNetworksPermission() throws Exception {
+        expectPermission(new String[] { CHANGE_NETWORK_STATE }, false);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+        expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, false);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+        // TODO : make this false when b/31479477 is fixed
+        expectPermission(new String[] {}, true);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+        expectPermission(new String[] { CHANGE_WIFI_STATE }, true);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+        expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, true);
+        assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+        expectPermission(new String[] {}, false);
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+
+        expectPermission(new String[] { CHANGE_WIFI_STATE }, false);
+        assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
+    }
+}
diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk
index 3b0221c..79469e3 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -41,5 +41,7 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
 include $(BUILD_PACKAGE)