Merge "Remove all the implementation for keep eSIM profile during FDR"
diff --git a/Android.bp b/Android.bp
index 641ce5f..d1332bb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -230,6 +230,7 @@
         "core/java/android/os/ISchedulingPolicyService.aidl",
         "core/java/android/os/IStatsCompanionService.aidl",
         "core/java/android/os/IStatsManager.aidl",
+        "core/java/android/os/ISystemUpdateManager.aidl",
         "core/java/android/os/IThermalEventListener.aidl",
         "core/java/android/os/IThermalService.aidl",
         "core/java/android/os/IUpdateLock.aidl",
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 6975609..682885b 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -25,9 +25,12 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import android.content.res.ColorStateList;
+import android.graphics.Canvas;
 import android.graphics.Typeface;
 import android.text.Layout;
 import android.text.style.TextAppearanceSpan;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -285,4 +288,157 @@
                     .build();
         }
     }
+
+    @Test
+    public void testDraw_FixedText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_Styled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_Styled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_RandomText_NoStyled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_Styled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_NoStyled() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_Styled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
+    @Test
+    public void testDraw_MeasuredText_NoStyled_WithoutCache() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final MeasuredText text = new MeasuredText.Builder(
+                    generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build();
+            final StaticLayout layout =
+                    StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
+            final DisplayListCanvas c = node.start(1200, 200);
+            Canvas.freeTextLayoutCaches();
+            state.resumeTiming();
+
+            layout.draw(c);
+        }
+    }
+
 }
diff --git a/api/current.txt b/api/current.txt
index 3d8c5a6..8d26717 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6474,6 +6474,7 @@
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
     method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isPrintingEnabled();
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
@@ -6543,6 +6544,7 @@
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedCrossProfileNotificationListeners(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
+    method public void setPrintingEnabled(android.content.ComponentName, boolean);
     method public void setProfileEnabled(android.content.ComponentName);
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
@@ -15573,8 +15575,10 @@
     method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
+    method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
     method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
+    method public java.util.List<java.lang.String> getPhysicalCameraIds();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
@@ -15613,6 +15617,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
@@ -15653,6 +15658,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
@@ -15673,6 +15679,7 @@
   public abstract class CameraDevice implements java.lang.AutoCloseable {
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
+    method public android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int, java.util.Set<java.lang.String>) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public void createCaptureSession(android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSessionByOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
@@ -15843,6 +15850,7 @@
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4; // 0x4
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -15858,6 +15866,8 @@
     field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0
     field public static final int LENS_STATE_MOVING = 1; // 0x1
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
+    field public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0; // 0x0
+    field public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int NOISE_REDUCTION_MODE_MINIMAL = 3; // 0x3
@@ -15867,6 +15877,7 @@
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9; // 0x9
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11; // 0xb
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10; // 0xa
@@ -15916,6 +15927,8 @@
     field public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1; // 0x1
     field public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0; // 0x0
     field public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1; // 0x1
+    field public static final int STATISTICS_OIS_DATA_MODE_OFF = 0; // 0x0
+    field public static final int STATISTICS_OIS_DATA_MODE_ON = 1; // 0x1
     field public static final int STATISTICS_SCENE_FLICKER_50HZ = 1; // 0x1
     field public static final int STATISTICS_SCENE_FLICKER_60HZ = 2; // 0x2
     field public static final int STATISTICS_SCENE_FLICKER_NONE = 0; // 0x0
@@ -15998,6 +16011,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_FACE_DETECT_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_OIS_DATA_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE;
@@ -16008,8 +16022,10 @@
     method public void addTarget(android.view.Surface);
     method public android.hardware.camera2.CaptureRequest build();
     method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method public <T> T getPhysicalCameraKey(android.hardware.camera2.CaptureRequest.Key<T>, java.lang.String);
     method public void removeTarget(android.view.Surface);
     method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
+    method public <T> android.hardware.camera2.CaptureRequest.Builder setPhysicalCameraKey(android.hardware.camera2.CaptureRequest.Key<T>, T, java.lang.String);
     method public void setTag(java.lang.Object);
   }
 
@@ -16097,6 +16113,10 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_OIS_DATA_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<long[]> STATISTICS_OIS_TIMESTAMPS;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> STATISTICS_OIS_X_SHIFTS;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> STATISTICS_OIS_Y_SHIFTS;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
@@ -16205,6 +16225,7 @@
     method public int getSurfaceGroupId();
     method public java.util.List<android.view.Surface> getSurfaces();
     method public void removeSurface(android.view.Surface);
+    method public void setPhysicalCameraId(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -27376,7 +27397,7 @@
     method public int addNetwork(android.net.wifi.WifiConfiguration);
     method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
-    method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
+    method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
     method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
@@ -27409,7 +27430,7 @@
     method public boolean setWifiEnabled(boolean);
     method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
     method public deprecated boolean startScan();
-    method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
+    method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
     method public int updateNetwork(android.net.wifi.WifiConfiguration);
     field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
     field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
@@ -27439,11 +27460,11 @@
     field public static final int WIFI_STATE_ENABLED = 3; // 0x3
     field public static final int WIFI_STATE_ENABLING = 2; // 0x2
     field public static final int WIFI_STATE_UNKNOWN = 4; // 0x4
-    field public static final int WPS_AUTH_FAILURE = 6; // 0x6
-    field public static final int WPS_OVERLAP_ERROR = 3; // 0x3
-    field public static final int WPS_TIMED_OUT = 7; // 0x7
-    field public static final int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
-    field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
+    field public static final deprecated int WPS_AUTH_FAILURE = 6; // 0x6
+    field public static final deprecated int WPS_OVERLAP_ERROR = 3; // 0x3
+    field public static final deprecated int WPS_TIMED_OUT = 7; // 0x7
+    field public static final deprecated int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
+    field public static final deprecated int WPS_WEP_PROHIBITED = 4; // 0x4
   }
 
   public static class WifiManager.LocalOnlyHotspotCallback {
@@ -27477,11 +27498,11 @@
     method public void setWorkSource(android.os.WorkSource);
   }
 
-  public static abstract class WifiManager.WpsCallback {
+  public static abstract deprecated class WifiManager.WpsCallback {
     ctor public WifiManager.WpsCallback();
-    method public abstract void onFailed(int);
-    method public abstract void onStarted(java.lang.String);
-    method public abstract void onSucceeded();
+    method public abstract deprecated void onFailed(int);
+    method public abstract deprecated void onStarted(java.lang.String);
+    method public abstract deprecated void onSucceeded();
   }
 
   public class WpsInfo implements android.os.Parcelable {
@@ -27923,6 +27944,29 @@
 
 package android.net.wifi.rtt {
 
+  public final class LocationCivic implements android.os.Parcelable {
+    method public int describeContents();
+    method public byte[] getData();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.LocationCivic> CREATOR;
+  }
+
+  public final class LocationConfigurationInformation implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getAltitude();
+    method public int getAltitudeType();
+    method public double getAltitudeUncertainty();
+    method public double getLatitude();
+    method public double getLatitudeUncertainty();
+    method public double getLongitude();
+    method public double getLongitudeUncertainty();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ALTITUDE_IN_FLOORS = 2; // 0x2
+    field public static final int ALTITUDE_IN_METERS = 1; // 0x1
+    field public static final int ALTITUDE_UNKNOWN = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.LocationConfigurationInformation> CREATOR;
+  }
+
   public final class RangingRequest implements android.os.Parcelable {
     method public int describeContents();
     method public static int getMaxPeers();
@@ -27946,6 +27990,8 @@
     method public android.net.MacAddress getMacAddress();
     method public android.net.wifi.aware.PeerHandle getPeerHandle();
     method public long getRangingTimestampUs();
+    method public android.net.wifi.rtt.LocationCivic getReportedLocationCivic();
+    method public android.net.wifi.rtt.LocationConfigurationInformation getReportedLocationConfigurationInformation();
     method public int getRssi();
     method public int getStatus();
     method public void writeToParcel(android.os.Parcel, int);
@@ -31547,7 +31593,7 @@
   }
 
   public final class Debug {
-    method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
+    method public static void attachJvmtiAgent(java.lang.String, java.lang.String, java.lang.ClassLoader) throws java.io.IOException;
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
     method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -34024,9 +34070,10 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_ASSISTED_DIALING_USED = 16; // 0x10
     field public static final int FEATURES_HD_CALL = 4; // 0x4
     field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
-    field public static final int FEATURES_RTT = 16; // 0x10
+    field public static final int FEATURES_RTT = 32; // 0x20
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final int FEATURES_WIFI = 8; // 0x8
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
@@ -39874,6 +39921,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
     field public static final int PROPERTY_CONFERENCE = 1; // 0x1
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -40094,6 +40142,7 @@
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int PROPERTY_IS_RTT = 256; // 0x100
@@ -40516,6 +40565,7 @@
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+    field public static final java.lang.String EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO = "android.telecom.extra.ASSISTED_DIALING_TRANSFORMATION_INFO";
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
@@ -40531,6 +40581,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
+    field public static final java.lang.String EXTRA_USE_ASSISTED_DIALING = "android.telecom.extra.USE_ASSISTED_DIALING";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
     field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
@@ -40543,6 +40594,18 @@
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
   }
 
+  public final class TransformationInfo implements android.os.Parcelable {
+    ctor public TransformationInfo(java.lang.String, java.lang.String, java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getOriginalNumber();
+    method public java.lang.String getTransformedNumber();
+    method public int getTransformedNumberCountryCallingCode();
+    method public java.lang.String getUserHomeCountryCode();
+    method public java.lang.String getUserRoamingCountryCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.TransformationInfo> CREATOR;
+  }
+
   public class VideoProfile implements android.os.Parcelable {
     ctor public VideoProfile(int);
     ctor public VideoProfile(int, int);
@@ -40706,6 +40769,7 @@
     field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
     field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
+    field public static final java.lang.String KEY_ASSISTED_DIALING_ENABLED_BOOL = "assisted_dialing_enabled_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
@@ -41451,6 +41515,8 @@
     method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method public int getAndroidCarrierIdForSubscription();
+    method public java.lang.CharSequence getAndroidCarrierNameForSubscription();
     method public int getCallState();
     method public android.os.PersistableBundle getCarrierConfig();
     method public deprecated android.telephony.CellLocation getCellLocation();
@@ -41488,8 +41554,6 @@
     method public int getSimState();
     method public int getSimState(int);
     method public java.lang.String getSubscriberId();
-    method public int getSubscriptionCarrierId();
-    method public java.lang.String getSubscriptionCarrierName();
     method public java.lang.String getVisualVoicemailPackageName();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
@@ -41707,6 +41771,7 @@
     method public java.net.InetAddress getMmsProxy();
     method public java.net.URL getMmsc();
     method public java.lang.String getMvnoType();
+    method public int getNetworkTypeBitmask();
     method public java.lang.String getOperatorNumeric();
     method public java.lang.String getPassword();
     method public int getPort();
@@ -41750,11 +41815,11 @@
     method public android.telephony.data.ApnSetting.Builder setAuthType(int);
     method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setId(int);
     method public android.telephony.data.ApnSetting.Builder setMmsPort(int);
     method public android.telephony.data.ApnSetting.Builder setMmsProxy(java.net.InetAddress);
     method public android.telephony.data.ApnSetting.Builder setMmsc(java.net.URL);
     method public android.telephony.data.ApnSetting.Builder setMvnoType(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
     method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String);
     method public android.telephony.data.ApnSetting.Builder setPort(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 66b6d99..ba9f2ac 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -75,6 +75,7 @@
     field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
     field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+    field public static final java.lang.String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
     field public static final java.lang.String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
     field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
     field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
@@ -131,6 +132,7 @@
     field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
     field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
     field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
+    field public static final java.lang.String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
     field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
     field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
     field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
@@ -380,6 +382,7 @@
     method public java.lang.CharSequence getDeviceOwnerOrganizationName();
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+    method public java.lang.CharSequence getPrintingDisabledReason();
     method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method public int getUserProvisioningState();
@@ -760,6 +763,7 @@
     field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
     field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
     field public static final java.lang.String STATS_MANAGER = "stats";
+    field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final java.lang.String VR_SERVICE = "vrmanager";
     field public static final java.lang.String WIFI_RTT_SERVICE = "rttmanager";
     field public static final java.lang.String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -3502,6 +3506,22 @@
     method public abstract void onResult(android.os.Bundle);
   }
 
+  public class SystemUpdateManager {
+    method public android.os.Bundle retrieveSystemUpdateInfo();
+    method public void updateSystemUpdateInfo(android.os.PersistableBundle);
+    field public static final java.lang.String KEY_IS_SECURITY_UPDATE = "is_security_update";
+    field public static final java.lang.String KEY_STATUS = "status";
+    field public static final java.lang.String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
+    field public static final java.lang.String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
+    field public static final java.lang.String KEY_TITLE = "title";
+    field public static final int STATUS_IDLE = 1; // 0x1
+    field public static final int STATUS_IN_PROGRESS = 3; // 0x3
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int STATUS_WAITING_DOWNLOAD = 2; // 0x2
+    field public static final int STATUS_WAITING_INSTALL = 4; // 0x4
+    field public static final int STATUS_WAITING_REBOOT = 5; // 0x5
+  }
+
   public class UpdateEngine {
     ctor public UpdateEngine();
     method public void applyPayload(java.lang.String, long, long, java.lang.String[]);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 9d6d8a1..7a7a2f6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -127,6 +127,10 @@
     StatsdStats::getInstance().noteAtomLogged(
         event->GetTagId(), event->GetTimestampNs() / NS_PER_SEC);
 
+    if (mMetricsManagers.empty()) {
+        return;
+    }
+
     // Hard-coded logic to update the isolated uid's in the uid-map.
     // The field numbers need to be currently updated by hand with atoms.proto
     if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ef99c9f..a07bd2f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -327,8 +327,9 @@
     optional string name = 2;
 
     enum State {
-        OFF = 0;
-        ON = 1;
+        FINISHED = 0;
+        STARTED = 1;
+        SCHEDULED = 2;
     }
     optional State state = 3;
 
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 6782f3f..34fa3c4 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -36,13 +36,13 @@
 using android::util::ProtoOutputStream;
 
 LogEvent::LogEvent(log_msg& msg) {
-    android_log_context context =
+    mContext =
             create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
     mTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
     mLogUid = msg.entry_v4.uid;
-    init(context);
-    if (context) {
-        android_log_destroy(&context);
+    init(mContext);
+    if (mContext) {
+        android_log_destroy(&mContext);
     }
 }
 
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index ccb54f9..da9f728 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -339,4 +339,9 @@
      * Returns maximum number of users that can run simultaneously.
      */
     public abstract int getMaxRunningUsers();
+
+    /**
+     * Returns is the caller has the same uid as the Recents component
+     */
+    public abstract boolean isCallerRecents(int callingUid);
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 33277ea..fb8d101 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -112,6 +112,7 @@
 import android.os.IHardwarePropertiesManager;
 import android.os.IPowerManager;
 import android.os.IRecoverySystem;
+import android.os.ISystemUpdateManager;
 import android.os.IUserManager;
 import android.os.IncidentManager;
 import android.os.PowerManager;
@@ -119,6 +120,7 @@
 import android.os.RecoverySystem;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemUpdateManager;
 import android.os.SystemVibrator;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -485,6 +487,17 @@
                 return new StorageStatsManager(ctx, service);
             }});
 
+        registerService(Context.SYSTEM_UPDATE_SERVICE, SystemUpdateManager.class,
+                new CachedServiceFetcher<SystemUpdateManager>() {
+                    @Override
+                    public SystemUpdateManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.SYSTEM_UPDATE_SERVICE);
+                        ISystemUpdateManager service = ISystemUpdateManager.Stub.asInterface(b);
+                        return new SystemUpdateManager(service);
+                    }});
+
         registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
                 new CachedServiceFetcher<TelephonyManager>() {
             @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d465e0d..7fccda8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9210,10 +9210,13 @@
     /**
      * Allows/disallows printing.
      *
+     * Called by a device owner or a profile owner.
+     * Device owner changes policy for all users. Profile owner can override it if present.
+     * Printing is enabled by default. If {@code FEATURE_PRINTING} is absent, the call is ignored.
+     *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @param enabled whether printing should be allowed or not.
      * @throws SecurityException if {@code admin} is neither device, nor profile owner.
-     * @hide
      */
     public void setPrintingEnabled(@NonNull ComponentName admin, boolean enabled) {
         try {
@@ -9224,10 +9227,12 @@
     }
 
     /**
-     * Returns whether printing is enabled for current user.
+     * Returns whether printing is enabled for this user.
+     *
+     * Always {@code false} if {@code FEATURE_PRINTING} is absent.
+     * Otherwise, {@code true} by default.
      *
      * @return {@code true} iff printing is enabled.
-     * @hide
      */
     public boolean isPrintingEnabled() {
         try {
@@ -9242,9 +9247,9 @@
      *
      * Used only by PrintService.
      * @return Localized error message.
-     * @throws SecurityException if caller is not system.
      * @hide
      */
+    @SystemApi
     public CharSequence getPrintingDisabledReason() {
         try {
             return mService.getPrintingDisabledReason();
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 8ffacf5..c4316a0 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -299,7 +299,7 @@
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         if (method.equals(METHOD_SLICE)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
             List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
 
             String callingPackage = getCallingPackage();
@@ -327,19 +327,19 @@
             }
             return b;
         } else if (method.equals(METHOD_PIN)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handlePinSlice(uri);
         } else if (method.equals(METHOD_UNPIN)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can pin/unpin slices");
             }
             handleUnpinSlice(uri);
         } else if (method.equals(METHOD_GET_DESCENDANTS)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            Uri uri = getUriWithoutUserId(extras.getParcelable(EXTRA_BIND_URI));
             Bundle b = new Bundle();
             b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
                     new ArrayList<>(handleGetDescendants(uri)));
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 265f7c7..f69aab01 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3024,7 +3024,8 @@
             //@hide: INCIDENT_SERVICE,
             //@hide: STATS_COMPANION_SERVICE,
             COMPANION_DEVICE_SERVICE,
-            CROSS_PROFILE_APPS_SERVICE
+            CROSS_PROFILE_APPS_SERVICE,
+            //@hide: SYSTEM_UPDATE_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -3242,6 +3243,17 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.os.SystemUpdateManager} for accessing the system update
+     * manager service.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    @SystemApi
+    public static final String SYSTEM_UPDATE_SERVICE = "system_update";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.WindowManager} for accessing the system's window
      * manager.
      *
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1201ef4..96d043c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -22,9 +22,11 @@
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
 import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.utils.ArrayUtils;
 import android.hardware.camera2.utils.TypeReference;
 import android.util.Rational;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -171,6 +173,7 @@
     private List<CameraCharacteristics.Key<?>> mKeys;
     private List<CaptureRequest.Key<?>> mAvailableRequestKeys;
     private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
+    private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
     private List<CaptureResult.Key<?>> mAvailableResultKeys;
 
     /**
@@ -314,6 +317,45 @@
     }
 
     /**
+     * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that can
+     * be overriden for physical devices backing a logical multi-camera.</p>
+     *
+     * <p>This is a subset of android.request.availableRequestKeys which contains a list
+     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * The respective value of such request key can be obtained by calling
+     * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
+     * individual physical device requests must be built via
+     * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.
+     * Such extended capture requests can be passed only to
+     * {@link CameraCaptureSession#capture } or {@link CameraCaptureSession#captureBurst } and
+     * not to {@link CameraCaptureSession#setRepeatingRequest } or
+     * {@link CameraCaptureSession#setRepeatingBurst }.</p>
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * @return List of keys that can be overriden in individual physical device requests.
+     * In case the camera device doesn't support such keys the list can be null.
+     */
+    @SuppressWarnings({"unchecked"})
+    public List<CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys() {
+        if (mAvailableSessionKeys == null) {
+            Object crKey = CaptureRequest.Key.class;
+            Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
+
+            int[] filterTags = get(REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
+            if (filterTags == null) {
+                return null;
+            }
+            mAvailablePhysicalRequestKeys =
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+        }
+        return mAvailablePhysicalRequestKeys;
+    }
+
+    /**
      * Returns the list of keys supported by this {@link CameraDevice} for querying
      * with a {@link CaptureRequest}.
      *
@@ -407,6 +449,47 @@
         return Collections.unmodifiableList(staticKeyList);
     }
 
+    /**
+     * Returns the list of physical camera ids that this logical {@link CameraDevice} is
+     * made up of.
+     *
+     * <p>A camera device is a logical camera if it has
+     * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device
+     * doesn't have the capability, the return value will be an empty list. </p>
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each physical camera id is only listed once in the list. The order of the keys
+     * is undefined.</p>
+     *
+     * @return List of physical camera ids for this logical camera device.
+     */
+    @NonNull
+    public List<String> getPhysicalCameraIds() {
+        int[] availableCapabilities = get(REQUEST_AVAILABLE_CAPABILITIES);
+        if (availableCapabilities == null) {
+            throw new AssertionError("android.request.availableCapabilities must be non-null "
+                        + "in the characteristics");
+        }
+
+        if (!ArrayUtils.contains(availableCapabilities,
+                REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
+            return Collections.emptyList();
+        }
+        byte[] physicalCamIds = get(LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+
+        String physicalCamIdString = null;
+        try {
+            physicalCamIdString = new String(physicalCamIds, "UTF-8");
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
+        }
+        String[] physicalCameraIdList = physicalCamIdString.split("\0");
+
+        return Collections.unmodifiableList(Arrays.asList(physicalCameraIdList));
+    }
+
     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * The key entries below this point are generated from metadata
      * definitions in /system/media/camera/docs. Do not modify by hand or
@@ -1579,6 +1662,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO CONSTRAINED_HIGH_SPEED_VIDEO}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA LOGICAL_MULTI_CAMERA}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1594,6 +1678,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT
      * @see #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -1701,6 +1786,30 @@
             new Key<int[]>("android.request.availableSessionKeys", int[].class);
 
     /**
+     * <p>A subset of the available request keys that can be overriden for
+     * physical devices backing a logical multi-camera.</p>
+     * <p>This is a subset of android.request.availableRequestKeys which contains a list
+     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * The respective value of such request key can be obtained by calling
+     * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
+     * individual physical device requests must be built via
+     * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.
+     * Such extended capture requests can be passed only to
+     * {@link CameraCaptureSession#capture } or {@link CameraCaptureSession#captureBurst } and
+     * not to {@link CameraCaptureSession#setRepeatingRequest } or
+     * {@link CameraCaptureSession#setRepeatingBurst }.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS =
+            new Key<int[]>("android.request.availablePhysicalCameraRequestKeys", int[].class);
+
+    /**
      * <p>The list of image formats that are supported by this
      * camera device for output streams.</p>
      * <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
@@ -2870,6 +2979,21 @@
             new Key<int[]>("android.statistics.info.availableLensShadingMapModes", int[].class);
 
     /**
+     * <p>List of OIS data output modes for {@link CaptureRequest#STATISTICS_OIS_DATA_MODE android.statistics.oisDataMode} that
+     * are supported by this camera device.</p>
+     * <p>If no OIS data output is available for this camera device, this key will
+     * contain only OFF.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#STATISTICS_OIS_DATA_MODE android.statistics.oisDataMode}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#STATISTICS_OIS_DATA_MODE
+     */
+    @PublicKey
+    public static final Key<int[]> STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES =
+            new Key<int[]>("android.statistics.info.availableOisDataModes", int[].class);
+
+    /**
      * <p>Maximum number of supported points in the
      * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
      * <p>If the actual number of points provided by the application (in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}*) is
@@ -2978,6 +3102,7 @@
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
+     *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -2991,6 +3116,7 @@
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_3
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
      */
     @PublicKey
     public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
@@ -3167,6 +3293,54 @@
     public static final Key<Boolean> DEPTH_DEPTH_IS_EXCLUSIVE =
             new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
 
+    /**
+     * <p>String containing the ids of the underlying physical cameras.</p>
+     * <p>For a logical camera, this is concatenation of all underlying physical camera ids.
+     * The null terminator for physical camera id must be preserved so that the whole string
+     * can be tokenized using '\0' to generate list of physical camera ids.</p>
+     * <p>For example, if the physical camera ids of the logical camera are "2" and "3", the
+     * value of this tag will be ['2', '\0', '3', '\0'].</p>
+     * <p>The number of physical camera ids must be no less than 2.</p>
+     * <p><b>Units</b>: UTF-8 null-terminated string</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<byte[]> LOGICAL_MULTI_CAMERA_PHYSICAL_IDS =
+            new Key<byte[]>("android.logicalMultiCamera.physicalIds", byte[].class);
+
+    /**
+     * <p>The accuracy of frame timestamp synchronization between physical cameras</p>
+     * <p>The accuracy of the frame timestamp synchronization determines the physical cameras'
+     * ability to start exposure at the same time. If the sensorSyncType is CALIBRATED,
+     * the physical camera sensors usually run in master-slave mode so that their shutter
+     * time is synchronized. For APPROXIMATE sensorSyncType, the camera sensors usually run in
+     * master-master mode, and there could be offset between their start of exposure.</p>
+     * <p>In both cases, all images generated for a particular capture request still carry the same
+     * timestamps, so that they can be used to look up the matching frame number and
+     * onCaptureStarted callback.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE APPROXIMATE}</li>
+     *   <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED CALIBRATED}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE
+     * @see #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED
+     */
+    @PublicKey
+    public static final Key<Integer> LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE =
+            new Key<Integer>("android.logicalMultiCamera.sensorSyncType", int.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 639795a..40ee834 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -31,6 +31,7 @@
 import android.view.Surface;
 
 import java.util.List;
+import java.util.Set;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -910,6 +911,47 @@
             throws CameraAccessException;
 
     /**
+     * <p>Create a {@link CaptureRequest.Builder} for new capture requests,
+     * initialized with template for a target use case. This methods allows
+     * clients to pass physical camera ids which can be used to customize the
+     * request for a specific physical camera. The settings are chosen
+     * to be the best options for the specific logical camera device. If
+     * additional physical camera ids are passed, then they will also use the
+     * same settings template. Requests containing individual physical camera
+     * settings can be passed only to {@link CameraCaptureSession#capture} or
+     * {@link CameraCaptureSession#captureBurst} and not to
+     * {@link CameraCaptureSession#setRepeatingRequest} or
+     * {@link CameraCaptureSession#setRepeatingBurst}</p>
+     *
+     * @param templateType An enumeration selecting the use case for this request. Not all template
+     * types are supported on every device. See the documentation for each template type for
+     * details.
+     * @param physicalCameraIdSet A set of physical camera ids that can be used to customize
+     *                            the request for a specific physical camera.
+     * @return a builder for a capture request, initialized with default
+     * settings for that template, and no output streams
+     *
+     * @throws IllegalArgumentException if the templateType is not supported by
+     * this device, or one of the physical id arguments matches with logical camera id.
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if the camera device has been closed
+     *
+     * @see #TEMPLATE_PREVIEW
+     * @see #TEMPLATE_RECORD
+     * @see #TEMPLATE_STILL_CAPTURE
+     * @see #TEMPLATE_VIDEO_SNAPSHOT
+     * @see #TEMPLATE_MANUAL
+     * @see CaptureRequest.Builder#setKey
+     * @see CaptureRequest.Builder#getKey
+     */
+    @NonNull
+    public CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType,
+            Set<String> physicalCameraIdSet) throws CameraAccessException {
+        throw new UnsupportedOperationException("Subclasses must override this method");
+    }
+
+    /**
      * <p>Create a {@link CaptureRequest.Builder} for a new reprocess {@link CaptureRequest} from a
      * {@link TotalCaptureResult}.
      *
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 90bf896..a2bc91e 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -996,7 +996,12 @@
                 return;
             }
 
-            Integer oldStatus = mDeviceStatus.put(id, status);
+            Integer oldStatus;
+            if (status == ICameraServiceListener.STATUS_NOT_PRESENT) {
+                oldStatus = mDeviceStatus.remove(id);
+            } else {
+                oldStatus = mDeviceStatus.put(id, status);
+            }
 
             if (oldStatus != null && oldStatus == status) {
                 if (DEBUG) {
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 2294ec5..e7c8961 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -845,6 +845,53 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
 
+    /**
+     * <p>The camera device is a logical camera backed by two or more physical cameras that are
+     * also exposed to the application.</p>
+     * <p>This capability requires the camera device to support the following:</p>
+     * <ul>
+     * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
+     * <li>android.logicalMultiCamera.physicalIds</li>
+     * <li>{@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType}</li>
+     * </ul>
+     * </li>
+     * <li>The underlying physical cameras' static metadata must list the following entries,
+     *   so that the application can correlate pixels from the physical streams:<ul>
+     * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+     * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
+     * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
+     * </ul>
+     * </li>
+     * <li>The logical camera device must be LIMITED or higher device.</li>
+     * </ul>
+     * <p>Both the logical camera device and its underlying physical devices support the
+     * mandatory stream combinations required for their device levels.</p>
+     * <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
+     * <ul>
+     * <li>Replacing one logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
+     *   or raw stream with two physical streams of the same size and format, each from a
+     *   separate physical camera, given that the size and format are supported by both
+     *   physical cameras.</li>
+     * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
+     *   advertise RAW capability, but the underlying physical cameras do. This is usually
+     *   the case when the physical cameras have different sensor sizes.</li>
+     * </ul>
+     * <p>Using physical streams in place of a logical stream of the same size and format will
+     * not slow down the frame rate of the capture, as long as the minimum frame duration
+     * of the physical and logical streams are the same.</p>
+     *
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
+     * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
@@ -1134,6 +1181,38 @@
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3;
 
+    /**
+     * <p>This camera device is backed by an external camera connected to this Android device.</p>
+     * <p>The device has capability identical to a LIMITED level device, with the following
+     * exceptions:</p>
+     * <ul>
+     * <li>The device may not report lens/sensor related information such as<ul>
+     * <li>{@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}</li>
+     * <li>{@link CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW android.sensor.rollingShutterSkew}</li>
+     * </ul>
+     * </li>
+     * <li>The device will report 0 for {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}</li>
+     * <li>The device has less guarantee on stable framerate, as the framerate partly depends
+     *   on the external camera being used.</li>
+     * </ul>
+     *
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+     * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
+     * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+     * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
+     * @see CameraCharacteristics#SENSOR_ORIENTATION
+     * @see CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL = 4;
+
     //
     // Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
     //
@@ -1160,6 +1239,26 @@
     public static final int SYNC_MAX_LATENCY_UNKNOWN = -1;
 
     //
+    // Enumeration values for CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+    //
+
+    /**
+     * <p>A software mechanism is used to synchronize between the physical cameras. As a result,
+     * the timestamp of an image from a physical stream is only an approximation of the
+     * image sensor start-of-exposure time.</p>
+     * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+     */
+    public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0;
+
+    /**
+     * <p>The camera device supports frame timestamp synchronization at the hardware level,
+     * and the timestamp of a physical stream image accurately reflects its
+     * start-of-exposure time.</p>
+     * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+     */
+    public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED = 1;
+
+    //
     // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE
     //
 
@@ -2566,6 +2665,22 @@
     public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
 
     //
+    // Enumeration values for CaptureRequest#STATISTICS_OIS_DATA_MODE
+    //
+
+    /**
+     * <p>Do not include OIS data in the capture result.</p>
+     * @see CaptureRequest#STATISTICS_OIS_DATA_MODE
+     */
+    public static final int STATISTICS_OIS_DATA_MODE_OFF = 0;
+
+    /**
+     * <p>Include OIS data in the capture result.</p>
+     * @see CaptureRequest#STATISTICS_OIS_DATA_MODE
+     */
+    public static final int STATISTICS_OIS_DATA_MODE_ON = 1;
+
+    //
     // Enumeration values for CaptureRequest#TONEMAP_MODE
     //
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index ce75fa52..481b764 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -33,9 +33,11 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
-
+import java.util.Set;
 
 /**
  * <p>An immutable package of settings and outputs needed to capture a single
@@ -219,7 +221,11 @@
 
     private static final ArraySet<Surface> mEmptySurfaceSet = new ArraySet<Surface>();
 
-    private final CameraMetadataNative mSettings;
+    private String mLogicalCameraId;
+    private CameraMetadataNative mLogicalCameraSettings;
+    private final HashMap<String, CameraMetadataNative> mPhysicalCameraSettings =
+            new HashMap<String, CameraMetadataNative>();
+
     private boolean mIsReprocess;
     // If this request is part of constrained high speed request list that was created by
     // {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
@@ -236,8 +242,6 @@
      * Used by Binder to unparcel this object only.
      */
     private CaptureRequest() {
-        mSettings = new CameraMetadataNative();
-        setNativeInstance(mSettings);
         mIsReprocess = false;
         mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE;
     }
@@ -249,8 +253,14 @@
      */
     @SuppressWarnings("unchecked")
     private CaptureRequest(CaptureRequest source) {
-        mSettings = new CameraMetadataNative(source.mSettings);
-        setNativeInstance(mSettings);
+        mLogicalCameraId = new String(source.mLogicalCameraId);
+        for (Map.Entry<String, CameraMetadataNative> entry :
+                source.mPhysicalCameraSettings.entrySet()) {
+            mPhysicalCameraSettings.put(new String(entry.getKey()),
+                    new CameraMetadataNative(entry.getValue()));
+        }
+        mLogicalCameraSettings = mPhysicalCameraSettings.get(mLogicalCameraId);
+        setNativeInstance(mLogicalCameraSettings);
         mSurfaceSet.addAll(source.mSurfaceSet);
         mIsReprocess = source.mIsReprocess;
         mIsPartOfCHSRequestList = source.mIsPartOfCHSRequestList;
@@ -272,16 +282,35 @@
      *                               reprocess capture request to the same session where
      *                               the {@link TotalCaptureResult}, used to create the reprocess
      *                               capture, came from.
+     * @param logicalCameraId Camera Id of the actively open camera that instantiates the
+     *                        Builder.
+     *
+     * @param physicalCameraIdSet A set of physical camera ids that can be used to customize
+     *                            the request for a specific physical camera.
      *
      * @throws IllegalArgumentException If creating a reprocess capture request with an invalid
-     *                                  reprocessableSessionId.
+     *                                  reprocessableSessionId, or multiple physical cameras.
      *
      * @see CameraDevice#createReprocessCaptureRequest
      */
     private CaptureRequest(CameraMetadataNative settings, boolean isReprocess,
-            int reprocessableSessionId) {
-        mSettings = CameraMetadataNative.move(settings);
-        setNativeInstance(mSettings);
+            int reprocessableSessionId, String logicalCameraId, Set<String> physicalCameraIdSet) {
+        if ((physicalCameraIdSet != null) && isReprocess) {
+            throw new IllegalArgumentException("Create a reprocess capture request with " +
+                    "with more than one physical camera is not supported!");
+        }
+
+        mLogicalCameraId = logicalCameraId;
+        mLogicalCameraSettings = CameraMetadataNative.move(settings);
+        mPhysicalCameraSettings.put(mLogicalCameraId, mLogicalCameraSettings);
+        if (physicalCameraIdSet != null) {
+            for (String physicalId : physicalCameraIdSet) {
+                mPhysicalCameraSettings.put(physicalId, new CameraMetadataNative(
+                            mLogicalCameraSettings));
+            }
+        }
+
+        setNativeInstance(mLogicalCameraSettings);
         mIsReprocess = isReprocess;
         if (isReprocess) {
             if (reprocessableSessionId == CameraCaptureSession.SESSION_ID_NONE) {
@@ -309,7 +338,7 @@
      */
     @Nullable
     public <T> T get(Key<T> key) {
-        return mSettings.get(key);
+        return mLogicalCameraSettings.get(key);
     }
 
     /**
@@ -319,7 +348,7 @@
     @SuppressWarnings("unchecked")
     @Override
     protected <T> T getProtected(Key<?> key) {
-        return (T) mSettings.get(key);
+        return (T) mLogicalCameraSettings.get(key);
     }
 
     /**
@@ -403,7 +432,7 @@
      * @hide
      */
     public CameraMetadataNative getNativeCopy() {
-        return new CameraMetadataNative(mSettings);
+        return new CameraMetadataNative(mLogicalCameraSettings);
     }
 
     /**
@@ -444,14 +473,16 @@
         return other != null
                 && Objects.equals(mUserTag, other.mUserTag)
                 && mSurfaceSet.equals(other.mSurfaceSet)
-                && mSettings.equals(other.mSettings)
+                && mPhysicalCameraSettings.equals(other.mPhysicalCameraSettings)
+                && mLogicalCameraId.equals(other.mLogicalCameraId)
+                && mLogicalCameraSettings.equals(other.mLogicalCameraSettings)
                 && mIsReprocess == other.mIsReprocess
                 && mReprocessableSessionId == other.mReprocessableSessionId;
     }
 
     @Override
     public int hashCode() {
-        return HashCodeHelpers.hashCodeGeneric(mSettings, mSurfaceSet, mUserTag);
+        return HashCodeHelpers.hashCodeGeneric(mPhysicalCameraSettings, mSurfaceSet, mUserTag);
     }
 
     public static final Parcelable.Creator<CaptureRequest> CREATOR =
@@ -479,8 +510,25 @@
      * @hide
      */
     private void readFromParcel(Parcel in) {
-        mSettings.readFromParcel(in);
-        setNativeInstance(mSettings);
+        int physicalCameraCount = in.readInt();
+        if (physicalCameraCount <= 0) {
+            throw new RuntimeException("Physical camera count" + physicalCameraCount +
+                    " should always be positive");
+        }
+
+        //Always start with the logical camera id
+        mLogicalCameraId = in.readString();
+        mLogicalCameraSettings = new CameraMetadataNative();
+        mLogicalCameraSettings.readFromParcel(in);
+        setNativeInstance(mLogicalCameraSettings);
+        mPhysicalCameraSettings.put(mLogicalCameraId, mLogicalCameraSettings);
+        for (int i = 1; i < physicalCameraCount; i++) {
+            String physicalId = in.readString();
+            CameraMetadataNative physicalCameraSettings = new CameraMetadataNative();
+            physicalCameraSettings.readFromParcel(in);
+            mPhysicalCameraSettings.put(physicalId, physicalCameraSettings);
+        }
+
         mIsReprocess = (in.readInt() == 0) ? false : true;
         mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE;
 
@@ -509,7 +557,19 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        mSettings.writeToParcel(dest, flags);
+        int physicalCameraCount = mPhysicalCameraSettings.size();
+        dest.writeInt(physicalCameraCount);
+        //Logical camera id and settings always come first.
+        dest.writeString(mLogicalCameraId);
+        mLogicalCameraSettings.writeToParcel(dest, flags);
+        for (Map.Entry<String, CameraMetadataNative> entry : mPhysicalCameraSettings.entrySet()) {
+            if (entry.getKey().equals(mLogicalCameraId)) {
+                continue;
+            }
+            dest.writeString(entry.getKey());
+            entry.getValue().writeToParcel(dest, flags);
+        }
+
         dest.writeInt(mIsReprocess ? 1 : 0);
 
         synchronized (mSurfacesLock) {
@@ -542,6 +602,14 @@
     }
 
     /**
+     * Retrieves the logical camera id.
+     * @hide
+     */
+    public String getLogicalCameraId() {
+        return mLogicalCameraId;
+    }
+
+    /**
      * @hide
      */
     public void convertSurfaceToStreamId(
@@ -633,14 +701,20 @@
          *                               submits a reprocess capture request to the same session
          *                               where the {@link TotalCaptureResult}, used to create the
          *                               reprocess capture, came from.
+         * @param logicalCameraId Camera Id of the actively open camera that instantiates the
+         *                        Builder.
+         * @param physicalCameraIdSet A set of physical camera ids that can be used to customize
+         *                            the request for a specific physical camera.
          *
          * @throws IllegalArgumentException If creating a reprocess capture request with an invalid
          *                                  reprocessableSessionId.
          * @hide
          */
         public Builder(CameraMetadataNative template, boolean reprocess,
-                int reprocessableSessionId) {
-            mRequest = new CaptureRequest(template, reprocess, reprocessableSessionId);
+                int reprocessableSessionId, String logicalCameraId,
+                Set<String> physicalCameraIdSet) {
+            mRequest = new CaptureRequest(template, reprocess, reprocessableSessionId,
+                    logicalCameraId, physicalCameraIdSet);
         }
 
         /**
@@ -682,7 +756,7 @@
          * type to the key.
          */
         public <T> void set(@NonNull Key<T> key, T value) {
-            mRequest.mSettings.set(key, value);
+            mRequest.mLogicalCameraSettings.set(key, value);
         }
 
         /**
@@ -696,7 +770,71 @@
          */
         @Nullable
         public <T> T get(Key<T> key) {
-            return mRequest.mSettings.get(key);
+            return mRequest.mLogicalCameraSettings.get(key);
+        }
+
+        /**
+         * Set a capture request field to a value. The field definitions can be
+         * found in {@link CaptureRequest}.
+         *
+         * <p>Setting a field to {@code null} will remove that field from the capture request.
+         * Unless the field is optional, removing it will likely produce an error from the camera
+         * device when the request is submitted.</p>
+         *
+         *<p>This method can be called for logical camera devices, which are devices that have
+         * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability and calls to
+         * {@link CameraCharacteristics#getPhysicalCameraIds} return a non-empty list of
+         * physical devices that are backing the logical camera. The camera Id included in the
+         * 'physicalCameraId' argument selects an individual physical device that will receive
+         * the customized capture request field.</p>
+         *
+         * @throws IllegalArgumentException if the physical camera id is not valid
+         *
+         * @param key The metadata field to write.
+         * @param value The value to set the field to, which must be of a matching
+         * @param physicalCameraId A valid physical camera Id. The valid camera Ids can be obtained
+         *                         via calls to {@link CameraCharacteristics#getPhysicalCameraIds}.
+         * @return The builder object.
+         * type to the key.
+         */
+        public <T> Builder setPhysicalCameraKey(@NonNull Key<T> key, T value,
+                @NonNull String physicalCameraId) {
+            if (!mRequest.mPhysicalCameraSettings.containsKey(physicalCameraId)) {
+                throw new IllegalArgumentException("Physical camera id: " + physicalCameraId +
+                        " is not valid!");
+            }
+
+            mRequest.mPhysicalCameraSettings.get(physicalCameraId).set(key, value);
+
+            return this;
+        }
+
+        /**
+         * Get a capture request field value for a specific physical camera Id. The field
+         * definitions can be found in {@link CaptureRequest}.
+         *
+         *<p>This method can be called for logical camera devices, which are devices that have
+         * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability and calls to
+         * {@link CameraCharacteristics#getPhysicalCameraIds} return a non-empty list of
+         * physical devices that are backing the logical camera. The camera Id included in the
+         * 'physicalCameraId' argument selects an individual physical device and returns
+         * its specific capture request field.</p>
+         *
+         * @throws IllegalArgumentException if the key or physical camera id were not valid
+         *
+         * @param key The metadata field to read.
+         * @param physicalCameraId A valid physical camera Id. The valid camera Ids can be obtained
+         *                         via calls to {@link CameraCharacteristics#getPhysicalCameraIds}.
+         * @return The value of that key, or {@code null} if the field is not set.
+         */
+        @Nullable
+        public <T> T getPhysicalCameraKey(Key<T> key,@NonNull String physicalCameraId) {
+            if (!mRequest.mPhysicalCameraSettings.containsKey(physicalCameraId)) {
+                throw new IllegalArgumentException("Physical camera id: " + physicalCameraId +
+                        " is not valid!");
+            }
+
+            return mRequest.mPhysicalCameraSettings.get(physicalCameraId).get(key);
         }
 
         /**
@@ -748,7 +886,7 @@
          * @hide
          */
         public boolean isEmpty() {
-            return mRequest.mSettings.isEmpty();
+            return mRequest.mLogicalCameraSettings.isEmpty();
         }
 
     }
@@ -2619,6 +2757,29 @@
             new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
 
     /**
+     * <p>Whether the camera device outputs the OIS data in output
+     * result metadata.</p>
+     * <p>When set to ON,
+     * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
+     * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
+     *   <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
+     * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * android.Statistics.info.availableOisDataModes</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+     * @see #STATISTICS_OIS_DATA_MODE_OFF
+     * @see #STATISTICS_OIS_DATA_MODE_ON
+     */
+    @PublicKey
+    public static final Key<Integer> STATISTICS_OIS_DATA_MODE =
+            new Key<Integer>("android.statistics.oisDataMode", int.class);
+
+    /**
      * <p>Tonemapping / contrast / gamma curve for the blue
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 237a92d..d730fa8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2203,8 +2203,6 @@
      * significant illumination change, this value will be set to DETECTED for a single capture
      * result. Otherwise the value will be NOT_DETECTED. The threshold for detection is similar
      * to what would trigger a new passive focus scan to begin in CONTINUOUS autofocus modes.</p>
-     * <p>afSceneChange may be DETECTED only if afMode is AF_MODE_CONTINUOUS_VIDEO or
-     * AF_MODE_CONTINUOUS_PICTURE. In other AF modes, afSceneChange must be NOT_DETECTED.</p>
      * <p>This key will be available if the camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -3911,6 +3909,76 @@
             new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
 
     /**
+     * <p>Whether the camera device outputs the OIS data in output
+     * result metadata.</p>
+     * <p>When set to ON,
+     * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
+     * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
+     *   <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
+     * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * android.Statistics.info.availableOisDataModes</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+     * @see #STATISTICS_OIS_DATA_MODE_OFF
+     * @see #STATISTICS_OIS_DATA_MODE_ON
+     */
+    @PublicKey
+    public static final Key<Integer> STATISTICS_OIS_DATA_MODE =
+            new Key<Integer>("android.statistics.oisDataMode", int.class);
+
+    /**
+     * <p>An array of timestamps of OIS samples, in nanoseconds.</p>
+     * <p>The array contains the timestamps of OIS samples. The timestamps are in the same
+     * timebase as and comparable to {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp}.</p>
+     * <p><b>Units</b>: nanoseconds</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#SENSOR_TIMESTAMP
+     */
+    @PublicKey
+    public static final Key<long[]> STATISTICS_OIS_TIMESTAMPS =
+            new Key<long[]>("android.statistics.oisTimestamps", long[].class);
+
+    /**
+     * <p>An array of shifts of OIS samples, in x direction.</p>
+     * <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
+     * A positive value is a shift from left to right in active array coordinate system. For
+     * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+     * (3, 0) puts the new optical center at (1003, 500).</p>
+     * <p>The number of shifts must match the number of timestamps in
+     * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}.</p>
+     * <p><b>Units</b>: Pixels in active array.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+     */
+    @PublicKey
+    public static final Key<float[]> STATISTICS_OIS_X_SHIFTS =
+            new Key<float[]>("android.statistics.oisXShifts", float[].class);
+
+    /**
+     * <p>An array of shifts of OIS samples, in y direction.</p>
+     * <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
+     * A positive value is a shift from top to bottom in active array coordinate system. For
+     * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+     * (0, 5) puts the new optical center at (1000, 505).</p>
+     * <p>The number of shifts must match the number of timestamps in
+     * {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}.</p>
+     * <p><b>Units</b>: Pixels in active array.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureResult#STATISTICS_OIS_TIMESTAMPS
+     */
+    @PublicKey
+    public static final Key<float[]> STATISTICS_OIS_Y_SHIFTS =
+            new Key<float[]>("android.statistics.oisYShifts", float[].class);
+
+    /**
      * <p>Tonemapping / contrast / gamma curve for the blue
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 8c4dbfa..06c2c25 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -94,8 +94,8 @@
         // Note that after this step, the requestMetadata is mutated (swapped) and can not be used
         // for next request builder creation.
         CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder(
-                requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
-
+                requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
+                request.getLogicalCameraId(), /*physicalCameraIdSet*/ null);
         // Carry over userTag, as native metadata doesn't have this field.
         singleTargetRequestBuilder.setTag(request.getTag());
 
@@ -120,7 +120,8 @@
             // CaptureRequest.Builder creation.
             requestMetadata = new CameraMetadataNative(request.getNativeCopy());
             doubleTargetRequestBuilder = new CaptureRequest.Builder(
-                    requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
+                    requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
+                    request.getLogicalCameraId(), /*physicalCameraIdSet*/null);
             doubleTargetRequestBuilder.setTag(request.getTag());
             doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
                     CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 4455d45..cab9d70 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -18,13 +18,14 @@
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
 
+import android.hardware.ICameraService;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.TotalCaptureResult;
@@ -34,7 +35,6 @@
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SurfaceUtils;
-import android.hardware.ICameraService;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -49,16 +49,15 @@
 
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -713,6 +712,38 @@
     }
 
     @Override
+    public CaptureRequest.Builder createCaptureRequest(int templateType,
+            Set<String> physicalCameraIdSet)
+            throws CameraAccessException {
+        synchronized(mInterfaceLock) {
+            checkIfCameraClosedOrInError();
+
+            for (String physicalId : physicalCameraIdSet) {
+                if (physicalId == getId()) {
+                    throw new IllegalStateException("Physical id matches the logical id!");
+                }
+            }
+
+            CameraMetadataNative templatedRequest = null;
+
+            templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
+
+            // If app target SDK is older than O, or it's not a still capture template, enableZsl
+            // must be false in the default request.
+            if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
+                    templateType != TEMPLATE_STILL_CAPTURE) {
+                overrideEnableZsl(templatedRequest, false);
+            }
+
+            CaptureRequest.Builder builder = new CaptureRequest.Builder(
+                    templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
+                    getId(), physicalCameraIdSet);
+
+            return builder;
+        }
+    }
+
+    @Override
     public CaptureRequest.Builder createCaptureRequest(int templateType)
             throws CameraAccessException {
         synchronized(mInterfaceLock) {
@@ -730,7 +761,8 @@
             }
 
             CaptureRequest.Builder builder = new CaptureRequest.Builder(
-                    templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
+                    templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
+                    getId(), /*physicalCameraIdSet*/ null);
 
             return builder;
         }
@@ -746,7 +778,7 @@
                     CameraMetadataNative(inputResult.getNativeCopy());
 
             return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true,
-                    inputResult.getSessionId());
+                    inputResult.getSessionId(), getId(), /*physicalCameraIdSet*/ null);
         }
     }
 
@@ -956,7 +988,8 @@
         // callback is valid
         handler = checkHandler(handler, callback);
 
-        // Make sure that there all requests have at least 1 surface; all surfaces are non-null
+        // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
+        // the surface isn't a physical stream surface for reprocessing request
         for (CaptureRequest request : requestList) {
             if (request.getTargets().isEmpty()) {
                 throw new IllegalArgumentException(
@@ -967,7 +1000,20 @@
                 if (surface == null) {
                     throw new IllegalArgumentException("Null Surface targets are not allowed");
                 }
+
+                if (!request.isReprocess()) {
+                    continue;
+                }
+                for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+                    OutputConfiguration configuration = mConfiguredOutputs.valueAt(i);
+                    if (configuration.isForPhysicalCamera()
+                            && configuration.getSurfaces().contains(surface)) {
+                        throw new IllegalArgumentException(
+                                "Reprocess request on physical stream is not allowed");
+                    }
+                }
             }
+
         }
 
         synchronized(mInterfaceLock) {
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index a85b5f7..f47cd66 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -31,13 +31,12 @@
 import android.util.Size;
 import android.view.Surface;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Collections;
-import java.util.ArrayList;
-
 import static com.android.internal.util.Preconditions.*;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * A class for describing camera output, which contains a {@link Surface} and its specific
  * configuration for creating capture session.
@@ -266,6 +265,7 @@
         mConfiguredGenerationId = surface.getGenerationId();
         mIsDeferredConfig = false;
         mIsShared = false;
+        mPhysicalCameraId = null;
     }
 
     /**
@@ -319,6 +319,7 @@
         mConfiguredGenerationId = 0;
         mIsDeferredConfig = true;
         mIsShared = false;
+        mPhysicalCameraId = null;
     }
 
     /**
@@ -348,8 +349,9 @@
      * </ol>
      *
      * <p>To enable surface sharing, this function must be called before {@link
-     * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after {@link
-     * CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
+     * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
+     * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function after
+     * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
      *
      * <p>Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration.
      * The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView,
@@ -360,6 +362,44 @@
     }
 
     /**
+     * Set the id of the physical camera for this OutputConfiguration
+     *
+     * <p>In the case one logical camera is made up of multiple physical cameras, it could be
+     * desirable for the camera application to request streams from individual physical cameras.
+     * This call achieves it by mapping the OutputConfiguration to the physical camera id.</p>
+     *
+     * <p>The valid physical camera id can be queried by {@link
+     * android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
+     * </p>
+     *
+     * <p>Passing in a null physicalCameraId means that the OutputConfiguration is for a logical
+     * stream.</p>
+     *
+     * <p>This function must be called before {@link
+     * CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
+     * CameraDevice#createReprocessableCaptureSessionByConfigurations}. Calling this function
+     * after {@link CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
+     * CameraDevice#createReprocessableCaptureSessionByConfigurations} has no effect.</p>
+     *
+     * <p>The surface belonging to a physical camera OutputConfiguration must not be used as input
+     * or output of a reprocessing request. </p>
+     */
+    public void setPhysicalCameraId(@Nullable String physicalCameraId) {
+        mPhysicalCameraId = physicalCameraId;
+    }
+
+    /**
+     * Check if this configuration is for a physical camera.
+     *
+     * <p>This returns true if the output configuration was for a physical camera making up a
+     * logical multi camera via {@link OutputConfiguration#setPhysicalCameraId}.</p>
+     * @hide
+     */
+    public boolean isForPhysicalCamera() {
+        return (mPhysicalCameraId != null);
+    }
+
+    /**
      * Check if this configuration has deferred configuration.
      *
      * <p>This will return true if the output configuration was constructed with surface deferred by
@@ -487,6 +527,7 @@
         this.mConfiguredGenerationId = other.mConfiguredGenerationId;
         this.mIsDeferredConfig = other.mIsDeferredConfig;
         this.mIsShared = other.mIsShared;
+        this.mPhysicalCameraId = other.mPhysicalCameraId;
     }
 
     /**
@@ -502,6 +543,7 @@
         boolean isShared = source.readInt() == 1;
         ArrayList<Surface> surfaces = new ArrayList<Surface>();
         source.readTypedList(surfaces, Surface.CREATOR);
+        String physicalCameraId = source.readString();
 
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
 
@@ -524,6 +566,7 @@
                     StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
             mConfiguredGenerationId = 0;
         }
+        mPhysicalCameraId = physicalCameraId;
     }
 
     /**
@@ -622,6 +665,7 @@
         dest.writeInt(mIsDeferredConfig ? 1 : 0);
         dest.writeInt(mIsShared ? 1 : 0);
         dest.writeTypedList(mSurfaces);
+        dest.writeString(mPhysicalCameraId);
     }
 
     /**
@@ -675,13 +719,15 @@
         if (mIsDeferredConfig) {
             return HashCodeHelpers.hashCode(
                     mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
-                    mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0);
+                    mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
+                    mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
         }
 
         return HashCodeHelpers.hashCode(
                 mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
                 mConfiguredSize.hashCode(), mConfiguredFormat,
-                mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0);
+                mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
+                mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
     }
 
     private static final String TAG = "OutputConfiguration";
@@ -701,4 +747,6 @@
     private final boolean mIsDeferredConfig;
     // Flag indicating if this config has shared surfaces
     private boolean mIsShared;
+    // The physical camera id that this output configuration is for.
+    private String mPhysicalCameraId;
 }
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 790c80b..eeb30e2 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -39,9 +39,9 @@
 
     void closeUdpEncapsulationSocket(int resourceId);
 
-    IpSecTransformResponse createTransportModeTransform(in IpSecConfig c, in IBinder binder);
+    IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder);
 
-    void deleteTransportModeTransform(int transformId);
+    void deleteTransform(int transformId);
 
     void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
 
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index be6026f..37e2c4f 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -124,8 +124,7 @@
         synchronized (this) {
             try {
                 IIpSecService svc = getIpSecService();
-                IpSecTransformResponse result =
-                        svc.createTransportModeTransform(mConfig, new Binder());
+                IpSecTransformResponse result = svc.createTransform(mConfig, new Binder());
                 int status = result.status;
                 checkResultStatus(status);
                 mResourceId = result.resourceId;
@@ -170,7 +169,7 @@
              * still want to clear out the transform.
              */
             IIpSecService svc = getIpSecService();
-            svc.deleteTransportModeTransform(mResourceId);
+            svc.deleteTransform(mResourceId);
             stopKeepalive();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index a85f80e..01b2b39 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -160,13 +160,6 @@
                     rxBytes, rxPackets, txBytes, txPackets, operations);
         }
 
-        // TODO: fix the the telephony code to pass DEFAULT_NETWORK_YES and remove this constructor.
-        public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
-                 long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
-            this(iface, uid, set, tag, metered, roaming, DEFAULT_NETWORK_YES, rxBytes, rxPackets,
-                    txBytes, txPackets, operations);
-        }
-
         public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
                  int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
                  long operations) {
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b307c5d..8efd39a 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -24,6 +24,15 @@
 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
+import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkStats.ROAMING_ALL;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
@@ -191,16 +200,30 @@
 
     private final String mNetworkId;
 
+    // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
+    private final int mMetered;
+    private final int mRoaming;
+    private final int mDefaultNetwork;
+
     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
     }
 
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
             String networkId) {
+        this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
+                DEFAULT_NETWORK_ALL);
+    }
+
+    public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+            String networkId, int metered, int roaming, int defaultNetwork) {
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         mMatchSubscriberIds = matchSubscriberIds;
         mNetworkId = networkId;
+        mMetered = metered;
+        mRoaming = roaming;
+        mDefaultNetwork = defaultNetwork;
 
         if (!isKnownMatchRule(matchRule)) {
             Log.e(TAG, "Unknown network template rule " + matchRule
@@ -213,6 +236,9 @@
         mSubscriberId = in.readString();
         mMatchSubscriberIds = in.createStringArray();
         mNetworkId = in.readString();
+        mMetered = in.readInt();
+        mRoaming = in.readInt();
+        mDefaultNetwork = in.readInt();
     }
 
     @Override
@@ -221,6 +247,9 @@
         dest.writeString(mSubscriberId);
         dest.writeStringArray(mMatchSubscriberIds);
         dest.writeString(mNetworkId);
+        dest.writeInt(mMetered);
+        dest.writeInt(mRoaming);
+        dest.writeInt(mDefaultNetwork);
     }
 
     @Override
@@ -243,12 +272,23 @@
         if (mNetworkId != null) {
             builder.append(", networkId=").append(mNetworkId);
         }
+        if (mMetered != METERED_ALL) {
+            builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
+        }
+        if (mRoaming != ROAMING_ALL) {
+            builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming));
+        }
+        if (mDefaultNetwork != DEFAULT_NETWORK_ALL) {
+            builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
+                    mDefaultNetwork));
+        }
         return builder.toString();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId);
+        return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
+                mDefaultNetwork);
     }
 
     @Override
@@ -257,7 +297,10 @@
             final NetworkTemplate other = (NetworkTemplate) obj;
             return mMatchRule == other.mMatchRule
                     && Objects.equals(mSubscriberId, other.mSubscriberId)
-                    && Objects.equals(mNetworkId, other.mNetworkId);
+                    && Objects.equals(mNetworkId, other.mNetworkId)
+                    && mMetered == other.mMetered
+                    && mRoaming == other.mRoaming
+                    && mDefaultNetwork == other.mDefaultNetwork;
         }
         return false;
     }
@@ -300,6 +343,10 @@
      * Test if given {@link NetworkIdentity} matches this template.
      */
     public boolean matches(NetworkIdentity ident) {
+        if (!matchesMetered(ident)) return false;
+        if (!matchesRoaming(ident)) return false;
+        if (!matchesDefaultNetwork(ident)) return false;
+
         switch (mMatchRule) {
             case MATCH_MOBILE_ALL:
                 return matchesMobile(ident);
@@ -326,6 +373,24 @@
         }
     }
 
+    private boolean matchesMetered(NetworkIdentity ident) {
+        return (mMetered == METERED_ALL)
+            || (mMetered == METERED_YES && ident.mMetered)
+            || (mMetered == METERED_NO && !ident.mMetered);
+    }
+
+    private boolean matchesRoaming(NetworkIdentity ident) {
+        return (mRoaming == ROAMING_ALL)
+            || (mRoaming == ROAMING_YES && ident.mRoaming)
+            || (mRoaming == ROAMING_NO && !ident.mRoaming);
+    }
+
+    private boolean matchesDefaultNetwork(NetworkIdentity ident) {
+        return (mDefaultNetwork == DEFAULT_NETWORK_ALL)
+            || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork)
+            || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
+    }
+
     public boolean matchesSubscriberId(String subscriberId) {
         return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 49879a8..03a8dba 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -336,6 +336,9 @@
     private final StringBuilder mFormatBuilder = new StringBuilder(32);
     private final Formatter mFormatter = new Formatter(mFormatBuilder);
 
+    private static final String CELLULAR_CONTROLLER_NAME = "Cellular";
+    private static final String WIFI_CONTROLLER_NAME = "WiFi";
+
     /**
      * Indicates times spent by the uid at each cpu frequency in all process states.
      *
@@ -413,6 +416,13 @@
 
         /**
          * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
+         * scan state.
+         */
+        public abstract LongCounter getScanTimeCounter();
+
+
+        /**
+         * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
          * receive state.
          */
         public abstract LongCounter getRxTimeCounter();
@@ -2399,6 +2409,14 @@
     public abstract long getWifiOnTime(long elapsedRealtimeUs, int which);
 
     /**
+     * Returns the time in microseconds that wifi has been active while the device was
+     * running on battery.
+     *
+     * {@hide}
+     */
+    public abstract long getWifiActiveTime(long elapsedRealtimeUs, int which);
+
+    /**
      * Returns the time in microseconds that wifi has been on and the driver has
      * been in the running state while the device was running on battery.
      *
@@ -3345,6 +3363,20 @@
         final long sleepTimeMs
             = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + totalTxTimeMs);
 
+        if (controllerName.equals(WIFI_CONTROLLER_NAME)) {
+            final long scanTimeMs = counter.getScanTimeCounter().getCountLocked(which);
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("     ");
+            sb.append(controllerName);
+            sb.append(" Scan time:  ");
+            formatTimeMs(sb, scanTimeMs);
+            sb.append("(");
+            sb.append(formatRatioLocked(scanTimeMs, totalControllerActivityTimeMs));
+            sb.append(")");
+            pw.println(sb.toString());
+        }
+
         sb.setLength(0);
         sb.append(prefix);
         sb.append("     ");
@@ -3386,7 +3418,7 @@
 
         String [] powerLevel;
         switch(controllerName) {
-            case "Cellular":
+            case CELLULAR_CONTROLLER_NAME:
                 powerLevel = new String[] {
                     "   less than 0dBm: ",
                     "   0dBm to 8dBm: ",
@@ -4674,7 +4706,7 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        printControllerActivity(pw, sb, prefix, "Cellular",
+        printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
             getModemControllerActivity(), which);
 
         pw.print(prefix);
@@ -4683,6 +4715,16 @@
         sb.append("  Wifi Statistics:");
         pw.println(sb.toString());
 
+        pw.print(prefix);
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("     Wifi kernel active time: ");
+        final long wifiActiveTime = getWifiActiveTime(rawRealtime, which);
+        formatTimeMs(sb, wifiActiveTime / 1000);
+        sb.append("("); sb.append(formatRatioLocked(wifiActiveTime, whichBatteryRealtime));
+        sb.append(")");
+        pw.println(sb.toString());
+
         pw.print("     Wifi data received: "); pw.println(formatBytesLocked(wifiRxTotalBytes));
         pw.print("     Wifi data sent: "); pw.println(formatBytesLocked(wifiTxTotalBytes));
         pw.print("     Wifi packets received: "); pw.println(wifiRxTotalPackets);
@@ -4760,7 +4802,8 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        printControllerActivity(pw, sb, prefix, "WiFi", getWifiControllerActivity(), which);
+        printControllerActivity(pw, sb, prefix, WIFI_CONTROLLER_NAME,
+            getWifiControllerActivity(), which);
 
         pw.print(prefix);
         sb.setLength(0);
@@ -5238,8 +5281,8 @@
                 pw.println(sb.toString());
             }
 
-            printControllerActivityIfInteresting(pw, sb, prefix + "  ", "Modem",
-                    u.getModemControllerActivity(), which);
+            printControllerActivityIfInteresting(pw, sb, prefix + "  ",
+                CELLULAR_CONTROLLER_NAME, u.getModemControllerActivity(), which);
 
             if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) {
                 pw.print(prefix); pw.print("    Wi-Fi network: ");
@@ -5293,7 +5336,7 @@
                 pw.println(sb.toString());
             }
 
-            printControllerActivityIfInteresting(pw, sb, prefix + "  ", "WiFi",
+            printControllerActivityIfInteresting(pw, sb, prefix + "  ", WIFI_CONTROLLER_NAME,
                     u.getWifiControllerActivity(), which);
 
             if (btRxBytes > 0 || btTxBytes > 0) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 848ab88..33e8c3e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2352,22 +2352,28 @@
     }
 
     /**
-     * Attach a library as a jvmti agent to the current runtime.
+     * Attach a library as a jvmti agent to the current runtime, with the given classloader
+     * determining the library search path.
+     * <p>
+     * Note: agents may only be attached to debuggable apps. Otherwise, this function will
+     * throw a SecurityException.
      *
-     * @param library library containing the agent
-     * @param options options passed to the agent
+     * @param library the library containing the agent.
+     * @param options the options passed to the agent.
+     * @param classLoader the classloader determining the library search path.
      *
-     * @throws IOException If the agent could not be attached
+     * @throws IOException if the agent could not be attached.
+     * @throws SecurityException if the app is not debuggable.
      */
-    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options)
-            throws IOException {
+    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options,
+            @Nullable ClassLoader classLoader) throws IOException {
         Preconditions.checkNotNull(library);
         Preconditions.checkArgument(!library.contains("="));
 
         if (options == null) {
-            VMDebug.attachAgent(library);
+            VMDebug.attachAgent(library, classLoader);
         } else {
-            VMDebug.attachAgent(library + "=" + options);
+            VMDebug.attachAgent(library + "=" + options, classLoader);
         }
     }
 }
diff --git a/core/java/android/os/ISystemUpdateManager.aidl b/core/java/android/os/ISystemUpdateManager.aidl
new file mode 100644
index 0000000..f7f5079
--- /dev/null
+++ b/core/java/android/os/ISystemUpdateManager.aidl
@@ -0,0 +1,27 @@
+/* //device/java/android/android/os/ISystemUpdateInfo.aidl
+**
+** Copyright 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.os.Bundle;
+import android.os.PersistableBundle;
+
+/** @hide */
+interface ISystemUpdateManager {
+    Bundle retrieveSystemUpdateInfo();
+    void updateSystemUpdateInfo(in PersistableBundle data);
+}
diff --git a/core/java/android/os/SystemUpdateManager.java b/core/java/android/os/SystemUpdateManager.java
new file mode 100644
index 0000000..ce3e2259
--- /dev/null
+++ b/core/java/android/os/SystemUpdateManager.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 android.os;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * Allows querying and posting system update information.
+ *
+ * {@hide}
+ */
+@SystemApi
+@SystemService(Context.SYSTEM_UPDATE_SERVICE)
+public class SystemUpdateManager {
+    private static final String TAG = "SystemUpdateManager";
+
+    /** The status key of the system update info, expecting an int value. */
+    @SystemApi
+    public static final String KEY_STATUS = "status";
+
+    /** The title of the current update, expecting a String value. */
+    @SystemApi
+    public static final String KEY_TITLE = "title";
+
+    /** Whether it is a security update, expecting a boolean value. */
+    @SystemApi
+    public static final String KEY_IS_SECURITY_UPDATE = "is_security_update";
+
+    /** The build fingerprint after installing the current update, expecting a String value. */
+    @SystemApi
+    public static final String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
+
+    /** The security patch level after installing the current update, expecting a String value. */
+    @SystemApi
+    public static final String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
+
+    /**
+     * The KEY_STATUS value that indicates there's no update status info available.
+     */
+    @SystemApi
+    public static final int STATUS_UNKNOWN = 0;
+
+    /**
+     * The KEY_STATUS value that indicates there's no pending update.
+     */
+    @SystemApi
+    public static final int STATUS_IDLE = 1;
+
+    /**
+     * The KEY_STATUS value that indicates an update is available for download, but pending user
+     * approval to start.
+     */
+    @SystemApi
+    public static final int STATUS_WAITING_DOWNLOAD = 2;
+
+    /**
+     * The KEY_STATUS value that indicates an update is in progress (i.e. downloading or installing
+     * has started).
+     */
+    @SystemApi
+    public static final int STATUS_IN_PROGRESS = 3;
+
+    /**
+     * The KEY_STATUS value that indicates an update is available for install.
+     */
+    @SystemApi
+    public static final int STATUS_WAITING_INSTALL = 4;
+
+    /**
+     * The KEY_STATUS value that indicates an update will be installed after a reboot. This applies
+     * to both of A/B and non-A/B OTAs.
+     */
+    @SystemApi
+    public static final int STATUS_WAITING_REBOOT = 5;
+
+    private final ISystemUpdateManager mService;
+
+    /** @hide */
+    public SystemUpdateManager(ISystemUpdateManager service) {
+        mService = checkNotNull(service, "missing ISystemUpdateManager");
+    }
+
+    /**
+     * Queries the current pending system update info.
+     *
+     * <p>Requires the {@link android.Manifest.permission#READ_SYSTEM_UPDATE_INFO} or
+     * {@link android.Manifest.permission#RECOVERY} permission.
+     *
+     * @return A {@code Bundle} that contains the pending system update information in key-value
+     * pairs.
+     *
+     * @throws SecurityException if the caller is not allowed to read the info.
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.READ_SYSTEM_UPDATE_INFO,
+            android.Manifest.permission.RECOVERY,
+    })
+    public Bundle retrieveSystemUpdateInfo() {
+        try {
+            return mService.retrieveSystemUpdateInfo();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Allows a system updater to publish the pending update info.
+     *
+     * <p>The reported info will not persist across reboots. Because only the reporting updater
+     * understands the criteria to determine a successful/failed update.
+     *
+     * <p>Requires the {@link android.Manifest.permission#RECOVERY} permission.
+     *
+     * @param infoBundle The {@code PersistableBundle} that contains the system update information,
+     * such as the current update status. {@link #KEY_STATUS} is required in the bundle.
+     *
+     * @throws IllegalArgumentException if @link #KEY_STATUS} does not exist.
+     * @throws SecurityException if the caller is not allowed to update the info.
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.RECOVERY)
+    public void updateSystemUpdateInfo(PersistableBundle infoBundle) {
+        if (infoBundle == null || !infoBundle.containsKey(KEY_STATUS)) {
+            throw new IllegalArgumentException("Missing status in the bundle");
+        }
+        try {
+            mService.updateSystemUpdateInfo(infoBundle);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java b/core/java/android/os/connectivity/WifiBatteryStats.aidl
similarity index 66%
rename from packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java
rename to core/java/android/os/connectivity/WifiBatteryStats.aidl
index dbc61c2..12ac738 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/Instrumentable.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.aidl
@@ -14,15 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.core.instrumentation;
+package android.os.connectivity;
 
-public interface Instrumentable {
-
-    int METRICS_CATEGORY_UNKNOWN = 0;
-
-    /**
-     * Instrumented name for a view as defined in
-     * {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}.
-     */
-    int getMetricsCategory();
-}
+/** {@hide} */
+parcelable WifiBatteryStats;
\ No newline at end of file
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
new file mode 100644
index 0000000..e5341ee
--- /dev/null
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.connectivity;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * API for Wifi power stats
+ *
+ * @hide
+ */
+public final class WifiBatteryStats implements Parcelable {
+
+  private long mLoggingDurationMs;
+  private long mKernelActiveTimeMs;
+  private long mNumPacketsTx;
+  private long mNumBytesTx;
+  private long mNumPacketsRx;
+  private long mNumBytesRx;
+  private long mSleepTimeMs;
+  private long mScanTimeMs;
+  private long mIdleTimeMs;
+  private long mRxTimeMs;
+  private long mTxTimeMs;
+  private long mEnergyConsumedMaMs;
+  private long mNumAppScanRequest;
+  private long[] mTimeInStateMs;
+  private long[] mTimeInSupplicantStateMs;
+  private long[] mTimeInRxSignalStrengthLevelMs;
+
+  public static final Parcelable.Creator<WifiBatteryStats> CREATOR = new
+      Parcelable.Creator<WifiBatteryStats>() {
+        public WifiBatteryStats createFromParcel(Parcel in) {
+          return new WifiBatteryStats(in);
+        }
+
+        public WifiBatteryStats[] newArray(int size) {
+          return new WifiBatteryStats[size];
+        }
+      };
+
+  public WifiBatteryStats() {
+    initialize();
+  }
+
+  public void writeToParcel(Parcel out, int flags) {
+    out.writeLong(mLoggingDurationMs);
+    out.writeLong(mKernelActiveTimeMs);
+    out.writeLong(mNumPacketsTx);
+    out.writeLong(mNumBytesTx);
+    out.writeLong(mNumPacketsRx);
+    out.writeLong(mNumBytesRx);
+    out.writeLong(mSleepTimeMs);
+    out.writeLong(mScanTimeMs);
+    out.writeLong(mIdleTimeMs);
+    out.writeLong(mRxTimeMs);
+    out.writeLong(mTxTimeMs);
+    out.writeLong(mEnergyConsumedMaMs);
+    out.writeLong(mNumAppScanRequest);
+    out.writeLongArray(mTimeInStateMs);
+    out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
+    out.writeLongArray(mTimeInSupplicantStateMs);
+  }
+
+  public void readFromParcel(Parcel in) {
+    mLoggingDurationMs = in.readLong();
+    mKernelActiveTimeMs = in.readLong();
+    mNumPacketsTx = in.readLong();
+    mNumBytesTx = in.readLong();
+    mNumPacketsRx = in.readLong();
+    mNumBytesRx = in.readLong();
+    mSleepTimeMs = in.readLong();
+    mScanTimeMs = in.readLong();
+    mIdleTimeMs = in.readLong();
+    mRxTimeMs = in.readLong();
+    mTxTimeMs = in.readLong();
+    mEnergyConsumedMaMs = in.readLong();
+    mNumAppScanRequest = in.readLong();
+    in.readLongArray(mTimeInStateMs);
+    in.readLongArray(mTimeInRxSignalStrengthLevelMs);
+    in.readLongArray(mTimeInSupplicantStateMs);
+  }
+
+  public long getLoggingDurationMs() {
+    return mLoggingDurationMs;
+  }
+
+  public long getKernelActiveTimeMs() {
+    return mKernelActiveTimeMs;
+  }
+
+  public long getNumPacketsTx() {
+    return mNumPacketsTx;
+  }
+
+  public long getNumBytesTx() {
+    return mNumBytesTx;
+  }
+
+  public long getNumPacketsRx() {
+    return mNumPacketsRx;
+  }
+
+  public long getNumBytesRx() {
+    return mNumBytesRx;
+  }
+
+  public long getSleepTimeMs() {
+    return mSleepTimeMs;
+  }
+
+  public long getScanTimeMs() {
+    return mScanTimeMs;
+  }
+
+  public long getIdleTimeMs() {
+    return mIdleTimeMs;
+  }
+
+  public long getRxTimeMs() {
+    return mRxTimeMs;
+  }
+
+  public long getTxTimeMs() {
+    return mTxTimeMs;
+  }
+
+  public long getEnergyConsumedMaMs() {
+    return mEnergyConsumedMaMs;
+  }
+
+  public long getNumAppScanRequest() {
+    return mNumAppScanRequest;
+  }
+
+  public long[] getTimeInStateMs() {
+    return mTimeInStateMs;
+  }
+
+  public long[] getTimeInRxSignalStrengthLevelMs() {
+    return mTimeInRxSignalStrengthLevelMs;
+  }
+
+  public long[] getTimeInSupplicantStateMs() {
+    return mTimeInSupplicantStateMs;
+  }
+
+  public void setLoggingDurationMs(long t) {
+    mLoggingDurationMs = t;
+    return;
+  }
+
+  public void setKernelActiveTimeMs(long t) {
+    mKernelActiveTimeMs = t;
+    return;
+  }
+
+  public void setNumPacketsTx(long n) {
+    mNumPacketsTx = n;
+    return;
+  }
+
+  public void setNumBytesTx(long b) {
+    mNumBytesTx = b;
+    return;
+  }
+
+  public void setNumPacketsRx(long n) {
+    mNumPacketsRx = n;
+    return;
+  }
+
+  public void setNumBytesRx(long b) {
+    mNumBytesRx = b;
+    return;
+  }
+
+  public void setSleepTimeMs(long t) {
+    mSleepTimeMs = t;
+    return;
+  }
+
+  public void setScanTimeMs(long t) {
+    mScanTimeMs = t;
+    return;
+  }
+
+  public void setIdleTimeMs(long t) {
+    mIdleTimeMs = t;
+    return;
+  }
+
+  public void setRxTimeMs(long t) {
+    mRxTimeMs = t;
+    return;
+  }
+
+  public void setTxTimeMs(long t) {
+    mTxTimeMs = t;
+    return;
+  }
+
+  public void setEnergyConsumedMaMs(long e) {
+    mEnergyConsumedMaMs = e;
+    return;
+  }
+
+  public void setNumAppScanRequest(long n) {
+    mNumAppScanRequest = n;
+    return;
+  }
+
+  public void setTimeInStateMs(long[] t) {
+    mTimeInStateMs = Arrays.copyOfRange(t, 0,
+        Math.min(t.length, BatteryStats.NUM_WIFI_STATES));
+    return;
+  }
+
+  public void setTimeInRxSignalStrengthLevelMs(long[] t) {
+    mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0,
+        Math.min(t.length, BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS));
+    return;
+  }
+
+  public void setTimeInSupplicantStateMs(long[] t) {
+    mTimeInSupplicantStateMs = Arrays.copyOfRange(
+        t, 0, Math.min(t.length, BatteryStats.NUM_WIFI_SUPPL_STATES));
+    return;
+  }
+
+  public int describeContents() {
+    return 0;
+  }
+
+  private WifiBatteryStats(Parcel in) {
+    initialize();
+    readFromParcel(in);
+  }
+
+  private void initialize() {
+    mLoggingDurationMs = 0;
+    mKernelActiveTimeMs = 0;
+    mNumPacketsTx = 0;
+    mNumBytesTx = 0;
+    mNumPacketsRx = 0;
+    mNumBytesRx = 0;
+    mSleepTimeMs = 0;
+    mScanTimeMs = 0;
+    mIdleTimeMs = 0;
+    mRxTimeMs = 0;
+    mTxTimeMs = 0;
+    mEnergyConsumedMaMs = 0;
+    mNumAppScanRequest = 0;
+    mTimeInStateMs = new long[BatteryStats.NUM_WIFI_STATES];
+    Arrays.fill(mTimeInStateMs, 0);
+    mTimeInRxSignalStrengthLevelMs = new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
+    Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
+    mTimeInSupplicantStateMs = new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
+    Arrays.fill(mTimeInSupplicantStateMs, 0);
+    return;
+  }
+}
\ No newline at end of file
diff --git a/core/java/android/privacy/internal/rappor/RapporEncoder.java b/core/java/android/privacy/internal/rappor/RapporEncoder.java
index 2eca4c98..9ac2b3e 100644
--- a/core/java/android/privacy/internal/rappor/RapporEncoder.java
+++ b/core/java/android/privacy/internal/rappor/RapporEncoder.java
@@ -33,7 +33,6 @@
 public class RapporEncoder implements DifferentialPrivacyEncoder {
 
     // Hard-coded seed and secret for insecure encoder
-    private static final long INSECURE_RANDOM_SEED = 0x12345678L;
     private static final byte[] INSECURE_SECRET = new byte[]{
             (byte) 0xD7, (byte) 0x68, (byte) 0x99, (byte) 0x93,
             (byte) 0x94, (byte) 0x13, (byte) 0x53, (byte) 0x54,
@@ -66,8 +65,8 @@
             // Use SecureRandom as random generator.
             random = sSecureRandom;
         } else {
-            // Hard-coded random generator, to have deterministic result.
-            random = new Random(INSECURE_RANDOM_SEED);
+            // To have deterministic result by hard coding encoder id as seed.
+            random = new Random((long) config.mEncoderId.hashCode());
             userSecret = INSECURE_SECRET;
         }
         mEncoder = new Encoder(random, null, null,
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index 2169457..7ad9e01 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -154,9 +154,12 @@
     public static final String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
 
     /**
-     * Activity Action: Dismiss timers.
+     * Activity Action: Dismiss a timer.
      * <p>
-     * Dismiss all currently expired timers. If there are no expired timers, then this is a no-op.
+     * The timer to dismiss should be specified using the Intent's data URI, which represents a
+     * deeplink to the timer.
+     * </p><p>
+     * If no data URI is provided, dismiss all expired timers.
      * </p>
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 60df467..c6c8d9d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -223,14 +223,13 @@
         /** Call was WIFI call. */
         public static final int FEATURES_WIFI = 1 << 3;
 
-        /** Call was on RTT at some point */
-        public static final int FEATURES_RTT = 1 << 4;
-
         /**
          * Indicates the call underwent Assisted Dialing.
-         * @hide
          */
-        public static final Integer FEATURES_ASSISTED_DIALING_USED = 0x10;
+        public static final int FEATURES_ASSISTED_DIALING_USED = 1 << 4;
+
+        /** Call was on RTT at some point */
+        public static final int FEATURES_RTT = 1 << 5;
 
         /**
          * The phone number as the user entered it.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b2cc18b..4228fbb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10128,7 +10128,8 @@
          * This is encoded as a key=value list, separated by commas. Ex:
          *
          * "battery_tip_enabled=true,summary_enabled=true,high_usage_enabled=true,"
-         * "high_usage_app_count=3,reduced_battery_enabled=false,reduced_battery_percent=50"
+         * "high_usage_app_count=3,reduced_battery_enabled=false,reduced_battery_percent=50,"
+         * "high_usage_battery_draining=25,high_usage_period_ms=3000"
          *
          * The following keys are supported:
          *
@@ -10138,6 +10139,8 @@
          * battery_saver_tip_enabled        (boolean)
          * high_usage_enabled               (boolean)
          * high_usage_app_count             (int)
+         * high_usage_period_ms             (long)
+         * high_usage_battery_draining      (int)
          * app_restriction_enabled          (boolean)
          * reduced_battery_enabled          (boolean)
          * reduced_battery_percent          (int)
@@ -10348,6 +10351,8 @@
          * The following keys are supported:
          * <pre>
          * track_cpu_times_by_proc_state (boolean)
+         * track_cpu_active_cluster_time (boolean)
+         * read_binary_cpu_time          (boolean)
          * </pre>
          *
          * <p>
@@ -10375,6 +10380,15 @@
         public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
 
         /**
+         * Whether or not to enable Forced App Standby on small battery devices.
+         * Type: int (0 for false, 1 for true)
+         * Default: 0
+         * @hide
+         */
+        public static final String FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED
+                = "forced_app_standby_for_small_battery_enabled";
+
+        /**
          * Whether or not Network Watchlist feature is enabled.
          * Type: int (0 for false, 1 for true)
          * Default: 0
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index 4e4caf0..df63a91 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -99,7 +99,9 @@
                 final String[] userDataValues = (String[]) args.arg5;
                 final float[][] scores = onGetScores(algorithmName, algorithmArgs, actualValues,
                         Arrays.asList(userDataValues));
-                data.putParcelable(EXTRA_SCORES, new Scores(scores));
+                if (scores != null) {
+                    data.putParcelable(EXTRA_SCORES, new Scores(scores));
+                }
                 break;
             default:
                 Log.w(TAG, "Handling unknown message: " + action);
@@ -148,7 +150,8 @@
     public float[][] onGetScores(@Nullable String algorithm,
             @Nullable Bundle args, @NonNull List<AutofillValue> actualValues,
             @NonNull List<String> userDataValues) {
-        throw new UnsupportedOperationException("Must be implemented by external service");
+        Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()");
+        return null;
     }
 
     private final class AutofillFieldClassificationServiceWrapper
@@ -182,7 +185,7 @@
             }
         }
 
-        private  Scores(float[][] scores) {
+        private Scores(float[][] scores) {
             this.scores = scores;
         }
 
diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java
index 908ef55..3b4eea7 100644
--- a/core/java/android/text/style/AbsoluteSizeSpan.java
+++ b/core/java/android/text/style/AbsoluteSizeSpan.java
@@ -16,71 +16,105 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * A span that changes the size of the text it's attached to.
+ * <p>
+ * For example, the size of the text can be changed to 55dp like this:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with absolute size span");
+ *string.setSpan(new AbsoluteSizeSpan(55, true), 10, 23, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/absolutesizespan.png" />
+ * <figcaption>Text with text size updated.</figcaption>
+ */
 public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
 
     private final int mSize;
-    private boolean mDip;
+    private final boolean mDip;
 
     /**
      * Set the text size to <code>size</code> physical pixels.
      */
     public AbsoluteSizeSpan(int size) {
-        mSize = size;
+        this(size, false);
     }
 
     /**
-     * Set the text size to <code>size</code> physical pixels,
-     * or to <code>size</code> device-independent pixels if
-     * <code>dip</code> is true.
+     * Set the text size to <code>size</code> physical pixels, or to <code>size</code>
+     * device-independent pixels if <code>dip</code> is true.
      */
     public AbsoluteSizeSpan(int size, boolean dip) {
         mSize = size;
         mDip = dip;
     }
 
-    public AbsoluteSizeSpan(Parcel src) {
+    /**
+     * Creates an {@link AbsoluteSizeSpan} from a parcel.
+     */
+    public AbsoluteSizeSpan(@NonNull Parcel src) {
         mSize = src.readInt();
         mDip = src.readInt() != 0;
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.ABSOLUTE_SIZE_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeInt(mSize);
         dest.writeInt(mDip ? 1 : 0);
     }
 
+    /**
+     * Get the text size. This is in physical pixels if {@link #getDip()} returns false or in
+     * device-independent pixels if {@link #getDip()} returns true.
+     *
+     * @return the text size, either in physical pixels or device-independent pixels.
+     * @see AbsoluteSizeSpan#AbsoluteSizeSpan(int, boolean)
+     */
     public int getSize() {
         return mSize;
     }
 
+    /**
+     * Returns whether the size is in device-independent pixels or not, depending on the
+     * <code>dip</code> flag passed in {@link #AbsoluteSizeSpan(int, boolean)}
+     *
+     * @return <code>true</code> if the size is in device-independent pixels, <code>false</code>
+     * otherwise
+     *
+     * @see #AbsoluteSizeSpan(int, boolean)
+     */
     public boolean getDip() {
         return mDip;
     }
 
     @Override
-    public void updateDrawState(TextPaint ds) {
+    public void updateDrawState(@NonNull TextPaint ds) {
         if (mDip) {
             ds.setTextSize(mSize * ds.density);
         } else {
@@ -89,7 +123,7 @@
     }
 
     @Override
-    public void updateMeasureState(TextPaint ds) {
+    public void updateMeasureState(@NonNull TextPaint ds) {
         if (mDip) {
             ds.setTextSize(mSize * ds.density);
         } else {
diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java
index 4f471a8..44e35615 100644
--- a/core/java/android/text/style/BackgroundColorSpan.java
+++ b/core/java/android/text/style/BackgroundColorSpan.java
@@ -27,11 +27,10 @@
  * Changes the background color of the text to which the span is attached.
  * <p>
  * For example, to set a green background color for a text you would create a {@link
- * android.text.SpannableStringBuilder} based on the text and set the span.
+ * android.text.SpannableString} based on the text and set the span.
  * <pre>{@code
  * SpannableString string = new SpannableString("Text with a background color span");
- *string.setSpan(new BackgroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- * }</pre>
+ *string.setSpan(new BackgroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
  * <img src="{@docRoot}reference/android/images/text/style/backgroundcolorspan.png" />
  * <figcaption>Set a background color for the text.</figcaption>
  */
@@ -58,30 +57,29 @@
         mColor = src.readInt();
     }
 
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.BACKGROUND_COLOR_SPAN;
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written.
-     */
+    @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
+    @Override
     public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeInt(mColor);
     }
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index 08ab2a1..f7706745 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -27,11 +27,10 @@
  * Changes the color of the text to which the span is attached.
  * <p>
  * For example, to set a green text color you would create a {@link
- * android.text.SpannableStringBuilder} based on the text and set the span.
+ * android.text.SpannableString} based on the text and set the span.
  * <pre>{@code
  * SpannableString string = new SpannableString("Text with a foreground color span");
- *string.setSpan(new ForegroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- * }</pre>
+ *string.setSpan(new ForegroundColorSpan(color), 12, 28, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
  * <img src="{@docRoot}reference/android/images/text/style/foregroundcolorspan.png" />
  * <figcaption>Set a text color.</figcaption>
  */
@@ -59,30 +58,29 @@
         mColor = src.readInt();
     }
 
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.FOREGROUND_COLOR_SPAN;
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest  The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written.
-     */
+    @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
+    @Override
     public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeInt(mColor);
     }
diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java
index 95f048a..3094f27 100644
--- a/core/java/android/text/style/RelativeSizeSpan.java
+++ b/core/java/android/text/style/RelativeSizeSpan.java
@@ -16,56 +16,85 @@
 
 package android.text.style;
 
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * Uniformly scales the size of the text to which it's attached by a certain proportion.
+ * <p>
+ * For example, a <code>RelativeSizeSpan</code> that increases the text size by 50% can be
+ * constructed like this:
+ * <pre>{@code
+ *  SpannableString string = new SpannableString("Text with relative size span");
+ *string.setSpan(new RelativeSizeSpan(1.5f), 10, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/relativesizespan.png" />
+ * <figcaption>Text increased by 50% with <code>RelativeSizeSpan</code>.</figcaption>
+ */
 public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
 
     private final float mProportion;
 
-    public RelativeSizeSpan(float proportion) {
+    /**
+     * Creates a {@link RelativeSizeSpan} based on a proportion.
+     *
+     * @param proportion the proportion with which the text is scaled.
+     */
+    public RelativeSizeSpan(@FloatRange(from = 0) float proportion) {
         mProportion = proportion;
     }
 
-    public RelativeSizeSpan(Parcel src) {
+    /**
+     * Creates a {@link RelativeSizeSpan} from a parcel.
+     */
+    public RelativeSizeSpan(@NonNull Parcel src) {
         mProportion = src.readFloat();
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.RELATIVE_SIZE_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeFloat(mProportion);
     }
 
+    /**
+     * @return the proportion with which the text size is changed.
+     */
     public float getSizeChange() {
         return mProportion;
     }
 
     @Override
-    public void updateDrawState(TextPaint ds) {
+    public void updateDrawState(@NonNull TextPaint ds) {
         ds.setTextSize(ds.getTextSize() * mProportion);
     }
 
     @Override
-    public void updateMeasureState(TextPaint ds) {
+    public void updateMeasureState(@NonNull TextPaint ds) {
         ds.setTextSize(ds.getTextSize() * mProportion);
     }
 }
diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java
index d0850185..6ef4cec 100644
--- a/core/java/android/text/style/ScaleXSpan.java
+++ b/core/java/android/text/style/ScaleXSpan.java
@@ -16,45 +16,79 @@
 
 package android.text.style;
 
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * Scales horizontally the size of the text to which it's attached by a certain factor.
+ * <p>
+ * Values > 1.0 will stretch the text wider. Values < 1.0 will stretch the text narrower.
+ * <p>
+ * For example, a <code>ScaleXSpan</code> that stretches the text size by 100% can be
+ * constructed like this:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with ScaleX span");
+ *string.setSpan(new ScaleXSpan(2f), 10, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/scalexspan.png" />
+ * <figcaption>Text scaled by 100% with <code>ScaleXSpan</code>.</figcaption>
+ */
 public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan {
 
     private final float mProportion;
 
-    public ScaleXSpan(float proportion) {
+    /**
+     * Creates a {@link ScaleXSpan} based on a proportion. Values > 1.0 will stretch the text wider.
+     * Values < 1.0 will stretch the text narrower.
+     *
+     * @param proportion the horizontal scale factor.
+     */
+    public ScaleXSpan(@FloatRange(from = 0) float proportion) {
         mProportion = proportion;
     }
 
-    public ScaleXSpan(Parcel src) {
+    /**
+     * Creates a {@link ScaleXSpan} from a parcel.
+     */
+    public ScaleXSpan(@NonNull Parcel src) {
         mProportion = src.readFloat();
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.SCALE_X_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeFloat(mProportion);
     }
 
+    /**
+     * Get the horizontal scale factor for the text.
+     *
+     * @return the horizontal scale factor.
+     */
     public float getScaleX() {
         return mProportion;
     }
diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java
index 1389704..a630505 100644
--- a/core/java/android/text/style/StrikethroughSpan.java
+++ b/core/java/android/text/style/StrikethroughSpan.java
@@ -16,42 +16,65 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * A span that strikes through the text it's attached to.
+ * <p>
+ * The span can be used like this:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with strikethrough span");
+ *string.setSpan(new StrikethroughSpan(), 10, 23, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/strikethroughspan.png" />
+ * <figcaption>Strikethrough text.</figcaption>
+ */
 public class StrikethroughSpan extends CharacterStyle
         implements UpdateAppearance, ParcelableSpan {
+
+    /**
+     * Creates a {@link StrikethroughSpan}.
+     */
     public StrikethroughSpan() {
     }
-    
-    public StrikethroughSpan(Parcel src) {
+
+    /**
+     * Creates a {@link StrikethroughSpan} from a parcel.
+     */
+    public StrikethroughSpan(@NonNull Parcel src) {
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.STRIKETHROUGH_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
     }
 
     @Override
-    public void updateDrawState(TextPaint ds) {
+    public void updateDrawState(@NonNull TextPaint ds) {
         ds.setStrikeThruText(true);
     }
 }
diff --git a/core/java/android/text/style/SubscriptSpan.java b/core/java/android/text/style/SubscriptSpan.java
index f1b0d38..3d15aad 100644
--- a/core/java/android/text/style/SubscriptSpan.java
+++ b/core/java/android/text/style/SubscriptSpan.java
@@ -16,46 +16,74 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * The span that moves the position of the text baseline lower.
+ * <p>
+ * The span can be used like this:
+ * <pre>{@code
+ *  SpannableString string = new SpannableString("☕- C8H10N4O2\n");
+ *string.setSpan(new SubscriptSpan(), 4, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ *string.setSpan(new SubscriptSpan(), 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ *string.setSpan(new SubscriptSpan(), 9, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ *string.setSpan(new SubscriptSpan(), 11, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/subscriptspan.png" />
+ * <figcaption>Text with <code>SubscriptSpan</code>.</figcaption>
+ * Note: Since the span affects the position of the text, if the text is on the last line of a
+ * TextView, it may appear cut.
+ */
 public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan {
+
+    /**
+     * Creates a {@link SubscriptSpan}.
+     */
     public SubscriptSpan() {
     }
-    
-    public SubscriptSpan(Parcel src) {
+
+    /**
+     * Creates a {@link SubscriptSpan} from a parcel.
+     */
+    public SubscriptSpan(@NonNull Parcel src) {
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.SUBSCRIPT_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
+    @Override
     public void writeToParcelInternal(Parcel dest, int flags) {
     }
 
     @Override
-    public void updateDrawState(TextPaint tp) {
-        tp.baselineShift -= (int) (tp.ascent() / 2);
+    public void updateDrawState(@NonNull TextPaint textPaint) {
+        textPaint.baselineShift -= (int) (textPaint.ascent() / 2);
     }
 
     @Override
-    public void updateMeasureState(TextPaint tp) {
-        tp.baselineShift -= (int) (tp.ascent() / 2);
+    public void updateMeasureState(@NonNull TextPaint textPaint) {
+        textPaint.baselineShift -= (int) (textPaint.ascent() / 2);
     }
 }
diff --git a/core/java/android/text/style/SuperscriptSpan.java b/core/java/android/text/style/SuperscriptSpan.java
index abcf688..3dc9d3f 100644
--- a/core/java/android/text/style/SuperscriptSpan.java
+++ b/core/java/android/text/style/SuperscriptSpan.java
@@ -16,46 +16,71 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * The span that moves the position of the text baseline higher.
+ * <p>
+ * The span can be used like this:
+ * <pre>{@code
+ *  SpannableString string = new SpannableString("1st example");
+ *string.setSpan(new SuperscriptSpan(), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/superscriptspan.png" />
+ * <figcaption>Text with <code>SuperscriptSpan</code>.</figcaption>
+ * Note: Since the span affects the position of the text, if the text is on the first line of a
+ * TextView, it may appear cut. This can be avoided by decreasing the text size with an {@link
+ * AbsoluteSizeSpan}
+ */
 public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSpan {
+    /**
+     * Creates a {@link SuperscriptSpan}.
+     */
     public SuperscriptSpan() {
     }
-    
-    public SuperscriptSpan(Parcel src) {
+
+    /**
+     * Creates a {@link SuperscriptSpan} from a parcel.
+     */
+    public SuperscriptSpan(@NonNull Parcel src) {
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.SUPERSCRIPT_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
     }
 
     @Override
-    public void updateDrawState(TextPaint tp) {
-        tp.baselineShift += (int) (tp.ascent() / 2);
+    public void updateDrawState(@NonNull TextPaint textPaint) {
+        textPaint.baselineShift += (int) (textPaint.ascent() / 2);
     }
 
     @Override
-    public void updateMeasureState(TextPaint tp) {
-        tp.baselineShift += (int) (tp.ascent() / 2);
+    public void updateMeasureState(@NonNull TextPaint textPaint) {
+        textPaint.baselineShift += (int) (textPaint.ascent() / 2);
     }
 }
diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java
index 9024dcd..800838e 100644
--- a/core/java/android/text/style/UnderlineSpan.java
+++ b/core/java/android/text/style/UnderlineSpan.java
@@ -16,42 +16,65 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
 
+/**
+ * A span that underlines the text it's attached to.
+ * <p>
+ * The span can be used like this:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with underline span");
+ *string.setSpan(new UnderlineSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/underlinespan.png" />
+ * <figcaption>Underlined text.</figcaption>
+ */
 public class UnderlineSpan extends CharacterStyle
         implements UpdateAppearance, ParcelableSpan {
+
+    /**
+     * Creates an {@link UnderlineSpan}.
+     */
     public UnderlineSpan() {
     }
-    
-    public UnderlineSpan(Parcel src) {
+
+    /**
+     * Creates an {@link UnderlineSpan} from a parcel.
+     */
+    public UnderlineSpan(@NonNull Parcel src) {
     }
-    
+
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
     /** @hide */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.UNDERLINE_SPAN;
     }
-    
+
+    @Override
     public int describeContents() {
         return 0;
     }
 
-    public void writeToParcel(Parcel dest, int flags) {
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
     }
 
     @Override
-    public void updateDrawState(TextPaint ds) {
+    public void updateDrawState(@NonNull TextPaint ds) {
         ds.setUnderlineText(true);
     }
 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index e94f91a..4e98d9b 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -43,7 +43,7 @@
         DEFAULT_FLAGS.put("settings_battery_v2", "false");
         DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_security_settings_v2", "true");
-        DEFAULT_FLAGS.put("settings_zone_picker_v2", "false");
+        DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
         DEFAULT_FLAGS.put("settings_suggestion_ui_v2", "false");
     }
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 1f7f8b9..8830c90 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -283,6 +283,7 @@
      */
     public long getNextFrameNumber() {
         synchronized (mLock) {
+            checkNotReleasedLocked();
             return nativeGetNextFrameNumber(mNativeObject);
         }
     }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index e2d1ad5..d3e807d 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -23,6 +23,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.WifiBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
 import android.os.health.HealthStatsParceler;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -143,6 +144,9 @@
     CellularBatteryStats getCellularBatteryStats();
 
     /** {@hide} */
+    WifiBatteryStats getWifiBatteryStats();
+
+    /** {@hide} */
     GpsBatteryStats getGpsBatteryStats();
 
     HealthStatsParceler takeUidSnapshot(int uid);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 799e3e8..b1c45f7 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -34,6 +34,7 @@
 import android.os.BatteryStats;
 import android.os.Build;
 import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.WifiBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -131,7 +132,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 173 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 174 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS;
@@ -751,6 +752,8 @@
     final StopwatchTimer[] mWifiSignalStrengthsTimer =
             new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
 
+    StopwatchTimer mWifiActiveTimer;
+
     int mBluetoothScanNesting;
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     protected StopwatchTimer mBluetoothScanTimer;
@@ -2785,12 +2788,14 @@
     public static class ControllerActivityCounterImpl extends ControllerActivityCounter
             implements Parcelable {
         private final LongSamplingCounter mIdleTimeMillis;
+        private final LongSamplingCounter mScanTimeMillis;
         private final LongSamplingCounter mRxTimeMillis;
         private final LongSamplingCounter[] mTxTimeMillis;
         private final LongSamplingCounter mPowerDrainMaMs;
 
         public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates) {
             mIdleTimeMillis = new LongSamplingCounter(timeBase);
+            mScanTimeMillis = new LongSamplingCounter(timeBase);
             mRxTimeMillis = new LongSamplingCounter(timeBase);
             mTxTimeMillis = new LongSamplingCounter[numTxStates];
             for (int i = 0; i < numTxStates; i++) {
@@ -2801,6 +2806,7 @@
 
         public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates, Parcel in) {
             mIdleTimeMillis = new LongSamplingCounter(timeBase, in);
+            mScanTimeMillis = new LongSamplingCounter(timeBase, in);
             mRxTimeMillis = new LongSamplingCounter(timeBase, in);
             final int recordedTxStates = in.readInt();
             if (recordedTxStates != numTxStates) {
@@ -2816,6 +2822,7 @@
 
         public void readSummaryFromParcel(Parcel in) {
             mIdleTimeMillis.readSummaryFromParcelLocked(in);
+            mScanTimeMillis.readSummaryFromParcelLocked(in);
             mRxTimeMillis.readSummaryFromParcelLocked(in);
             final int recordedTxStates = in.readInt();
             if (recordedTxStates != mTxTimeMillis.length) {
@@ -2834,6 +2841,7 @@
 
         public void writeSummaryToParcel(Parcel dest) {
             mIdleTimeMillis.writeSummaryFromParcelLocked(dest);
+            mScanTimeMillis.writeSummaryFromParcelLocked(dest);
             mRxTimeMillis.writeSummaryFromParcelLocked(dest);
             dest.writeInt(mTxTimeMillis.length);
             for (LongSamplingCounter counter : mTxTimeMillis) {
@@ -2845,6 +2853,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             mIdleTimeMillis.writeToParcel(dest);
+            mScanTimeMillis.writeToParcel(dest);
             mRxTimeMillis.writeToParcel(dest);
             dest.writeInt(mTxTimeMillis.length);
             for (LongSamplingCounter counter : mTxTimeMillis) {
@@ -2855,6 +2864,7 @@
 
         public void reset(boolean detachIfReset) {
             mIdleTimeMillis.reset(detachIfReset);
+            mScanTimeMillis.reset(detachIfReset);
             mRxTimeMillis.reset(detachIfReset);
             for (LongSamplingCounter counter : mTxTimeMillis) {
                 counter.reset(detachIfReset);
@@ -2864,6 +2874,7 @@
 
         public void detach() {
             mIdleTimeMillis.detach();
+            mScanTimeMillis.detach();
             mRxTimeMillis.detach();
             for (LongSamplingCounter counter : mTxTimeMillis) {
                 counter.detach();
@@ -2881,6 +2892,15 @@
         }
 
         /**
+         * @return a LongSamplingCounter, measuring time spent in the scan state in
+         * milliseconds.
+         */
+        @Override
+        public LongSamplingCounter getScanTimeCounter() {
+            return mScanTimeMillis;
+        }
+
+        /**
          * @return a LongSamplingCounter, measuring time spent in the receive state in
          * milliseconds.
          */
@@ -3892,8 +3912,10 @@
         }
         mKernelUidCpuTimeReader.removeUid(isolatedUid);
         mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
-        mKernelUidCpuActiveTimeReader.removeUid(isolatedUid);
-        mKernelUidCpuClusterTimeReader.removeUid(isolatedUid);
+        if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+            mKernelUidCpuActiveTimeReader.removeUid(isolatedUid);
+            mKernelUidCpuClusterTimeReader.removeUid(isolatedUid);
+        }
     }
 
     public int mapUid(int uid) {
@@ -5618,8 +5640,11 @@
                     noteWifiRadioApWakeupLocked(elapsedRealtime, uptime, uid);
                 }
                 mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
+                mWifiActiveTimer.startRunningLocked(elapsedRealtime);
             } else {
                 mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
+                mWifiActiveTimer.stopRunningLocked(
+                    timestampNs / (1000 * 1000));
             }
             if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: "
                     + Integer.toHexString(mHistoryCur.states));
@@ -6270,6 +6295,10 @@
         return mWifiOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
+    @Override public long getWifiActiveTime(long elapsedRealtimeUs, int which) {
+        return mWifiActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+    }
+
     @Override public long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which) {
         return mGlobalWifiRunningTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -9916,6 +9945,7 @@
             mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i, null,
                     mOnBatteryTimeBase);
         }
+        mWifiActiveTimer = new StopwatchTimer(mClocks, null, -900, null, mOnBatteryTimeBase);
         for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i, null,
                 mOnBatteryTimeBase);
@@ -10609,10 +10639,11 @@
             mWifiSignalStrengthsTimer[i].reset(false);
         }
         mWifiMulticastWakelockTimer.reset(false);
+        mWifiActiveTimer.reset(false);
+        mWifiActivity.reset(false);
         for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i].reset(false);
         }
-        mWifiActivity.reset(false);
         mBluetoothActivity.reset(false);
         mModemActivity.reset(false);
         mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
@@ -10875,6 +10906,7 @@
                 // Measured in mAms
                 final long txTimeMs = info.getControllerTxTimeMillis();
                 final long rxTimeMs = info.getControllerRxTimeMillis();
+                final long scanTimeMs = info.getControllerScanTimeMillis();
                 final long idleTimeMs = info.getControllerIdleTimeMillis();
                 final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
 
@@ -10887,6 +10919,7 @@
                     Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
                     Slog.d(TAG, "  Idle Time:  " + idleTimeMs + " ms");
                     Slog.d(TAG, "  Total Time: " + totalTimeMs + " ms");
+                    Slog.d(TAG, "  Scan Time:  " + scanTimeMs + " ms");
                 }
 
                 long totalWifiLockTimeMs = 0;
@@ -11020,6 +11053,8 @@
                 mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
                 mWifiActivity.getTxTimeCounters()[0].addCountLocked(
                         info.getControllerTxTimeMillis());
+                mWifiActivity.getScanTimeCounter().addCountLocked(
+                    info.getControllerScanTimeMillis());
                 mWifiActivity.getIdleTimeCounter().addCountLocked(
                         info.getControllerIdleTimeMillis());
 
@@ -11063,6 +11098,39 @@
                 return;
             }
 
+            if (activityInfo != null) {
+                mHasModemReporting = true;
+                mModemActivity.getIdleTimeCounter().addCountLocked(
+                    activityInfo.getIdleTimeMillis());
+                mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
+                for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+                    mModemActivity.getTxTimeCounters()[lvl]
+                        .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
+                }
+
+                // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
+                final double opVolt = mPowerProfile.getAveragePower(
+                    PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
+                if (opVolt != 0) {
+                    double energyUsed =
+                        activityInfo.getSleepTimeMillis() *
+                            mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_SLEEP)
+                            + activityInfo.getIdleTimeMillis() *
+                            mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+                            + activityInfo.getRxTimeMillis() *
+                            mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
+                    int[] txCurrentMa = activityInfo.getTxTimeMillis();
+                    for (int i = 0; i < Math.min(txCurrentMa.length,
+                        SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) {
+                        energyUsed += txCurrentMa[i] * mPowerProfile.getAveragePower(
+                            PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+                    }
+
+                    // We store the power drain as mAms.
+                    mModemActivity.getPowerCounter().addCountLocked((long) energyUsed);
+                }
+            }
+
             final long elapsedRealtimeMs = mClocks.elapsedRealtime();
             long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
                     elapsedRealtimeMs * 1000);
@@ -11161,26 +11229,6 @@
                 mNetworkStatsPool.release(delta);
                 delta = null;
             }
-
-            if (activityInfo != null) {
-                mHasModemReporting = true;
-                mModemActivity.getIdleTimeCounter().addCountLocked(
-                        activityInfo.getIdleTimeMillis());
-                mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
-                for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
-                    mModemActivity.getTxTimeCounters()[lvl]
-                            .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
-                }
-
-                // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
-                final double opVolt = mPowerProfile.getAveragePower(
-                        PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
-                if (opVolt != 0) {
-                    // We store the power drain as mAms.
-                    mModemActivity.getPowerCounter().addCountLocked(
-                            (long) (activityInfo.getEnergyUsed() / opVolt));
-                }
-            }
         }
     }
 
@@ -11538,8 +11586,10 @@
         if (!mOnBatteryInternal) {
             mKernelUidCpuTimeReader.readDelta(null);
             mKernelUidCpuFreqTimeReader.readDelta(null);
-            mKernelUidCpuActiveTimeReader.readDelta(null);
-            mKernelUidCpuClusterTimeReader.readDelta(null);
+            if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+                mKernelUidCpuActiveTimeReader.readDelta(null);
+                mKernelUidCpuClusterTimeReader.readDelta(null);
+            }
             for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
                 mKernelCpuSpeedReaders[cluster].readDelta();
             }
@@ -11556,8 +11606,10 @@
             updateClusterSpeedTimes(updatedUids);
         }
         readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
-        readKernelUidCpuActiveTimesLocked();
-        readKernelUidCpuClusterTimesLocked();
+        if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
+            readKernelUidCpuActiveTimesLocked();
+            readKernelUidCpuClusterTimesLocked();
+        }
     }
 
     /**
@@ -12530,6 +12582,56 @@
         return s;
     }
 
+     /*@hide */
+     public WifiBatteryStats getWifiBatteryStats() {
+         WifiBatteryStats s = new WifiBatteryStats();
+         final int which = STATS_SINCE_CHARGED;
+         final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
+         final ControllerActivityCounter counter = getWifiControllerActivity();
+         final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
+         final long scanTimeMs = counter.getScanTimeCounter().getCountLocked(which);
+         final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
+         final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(which);
+         final long totalControllerActivityTimeMs
+             = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which) / 1000;
+         final long sleepTimeMs
+             = totalControllerActivityTimeMs - (idleTimeMs + rxTimeMs + txTimeMs);
+         final long energyConsumedMaMs = counter.getPowerCounter().getCountLocked(which);
+         long numAppScanRequest = 0;
+         for (int i = 0; i < mUidStats.size(); i++) {
+             numAppScanRequest += mUidStats.valueAt(i).mWifiScanTimer.getCountLocked(which);
+         }
+         long[] timeInStateMs = new long[NUM_WIFI_STATES];
+         for (int i=0; i<NUM_WIFI_STATES; i++) {
+            timeInStateMs[i] = getWifiStateTime(i, rawRealTime, which) / 1000;
+         }
+         long[] timeInSupplStateMs = new long[NUM_WIFI_SUPPL_STATES];
+         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+             timeInSupplStateMs[i] = getWifiSupplStateTime(i, rawRealTime, which) / 1000;
+         }
+         long[] timeSignalStrengthTimeMs = new long[NUM_WIFI_SIGNAL_STRENGTH_BINS];
+         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+             timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
+         }
+         s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
+         s.setKernelActiveTimeMs(getWifiActiveTime(rawRealTime, which) / 1000);
+         s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which));
+         s.setNumBytesTx(getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which));
+         s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which));
+         s.setNumBytesRx(getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which));
+         s.setSleepTimeMs(sleepTimeMs);
+         s.setIdleTimeMs(idleTimeMs);
+         s.setRxTimeMs(rxTimeMs);
+         s.setTxTimeMs(txTimeMs);
+         s.setScanTimeMs(scanTimeMs);
+         s.setEnergyConsumedMaMs(energyConsumedMaMs);
+         s.setNumAppScanRequest(numAppScanRequest);
+         s.setTimeInStateMs(timeInStateMs);
+         s.setTimeInSupplicantStateMs(timeInSupplStateMs);
+         s.setTimeInRxSignalStrengthLevelMs(timeSignalStrengthTimeMs);
+         return s;
+     }
+
     /*@hide */
     public GpsBatteryStats getGpsBatteryStats() {
         GpsBatteryStats s = new GpsBatteryStats();
@@ -12804,10 +12906,19 @@
     public final class Constants extends ContentObserver {
         public static final String KEY_TRACK_CPU_TIMES_BY_PROC_STATE
                 = "track_cpu_times_by_proc_state";
+        public static final String KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME
+                = "track_cpu_active_cluster_time";
+        public static final String KEY_READ_BINARY_CPU_TIME
+                = "read_binary_cpu_time";
 
         private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true;
+        private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
+        private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false;
 
         public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
+        public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
+        // Not used right now.
+        public boolean READ_BINARY_CPU_TIME = DEFAULT_READ_BINARY_CPU_TIME;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -12843,6 +12954,11 @@
                 updateTrackCpuTimesByProcStateLocked(TRACK_CPU_TIMES_BY_PROC_STATE,
                         mParser.getBoolean(KEY_TRACK_CPU_TIMES_BY_PROC_STATE,
                                 DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE));
+                TRACK_CPU_ACTIVE_CLUSTER_TIME = mParser.getBoolean(
+                        KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME, DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME);
+                READ_BINARY_CPU_TIME = mParser.getBoolean(
+                        KEY_READ_BINARY_CPU_TIME, DEFAULT_READ_BINARY_CPU_TIME);
+
             }
         }
 
@@ -12857,6 +12973,10 @@
         public void dumpLocked(PrintWriter pw) {
             pw.print(KEY_TRACK_CPU_TIMES_BY_PROC_STATE); pw.print("=");
             pw.println(TRACK_CPU_TIMES_BY_PROC_STATE);
+            pw.print(KEY_TRACK_CPU_ACTIVE_CLUSTER_TIME); pw.print("=");
+            pw.println(TRACK_CPU_ACTIVE_CLUSTER_TIME);
+            pw.print(KEY_READ_BINARY_CPU_TIME); pw.print("=");
+            pw.println(READ_BINARY_CPU_TIME);
         }
     }
 
@@ -13222,10 +13342,11 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
         }
+        mWifiActiveTimer.readSummaryFromParcelLocked(in);
+        mWifiActivity.readSummaryFromParcel(in);
         for (int i=0; i<GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i].readSummaryFromParcelLocked(in);
         }
-        mWifiActivity.readSummaryFromParcel(in);
         mBluetoothActivity.readSummaryFromParcel(in);
         mModemActivity.readSummaryFromParcel(in);
         mHasWifiReporting = in.readInt() != 0;
@@ -13667,10 +13788,11 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        mWifiActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        mWifiActivity.writeSummaryToParcel(out);
         for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
-        mWifiActivity.writeSummaryToParcel(out);
         mBluetoothActivity.writeSummaryToParcel(out);
         mModemActivity.writeSummaryToParcel(out);
         out.writeInt(mHasWifiReporting ? 1 : 0);
@@ -14145,12 +14267,14 @@
             mWifiSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -800-i,
                     null, mOnBatteryTimeBase, in);
         }
+        mWifiActiveTimer = new StopwatchTimer(mClocks, null, -900, null,
+            mOnBatteryTimeBase, in);
+        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                NUM_WIFI_TX_LEVELS, in);
         for (int i=0; i<GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i] = new StopwatchTimer(mClocks, null, -1000-i,
                 null, mOnBatteryTimeBase, in);
         }
-        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
-                NUM_WIFI_TX_LEVELS, in);
         mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
                 NUM_BT_TX_LEVELS, in);
         mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
@@ -14348,10 +14472,11 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
         }
+        mWifiActiveTimer.writeToParcel(out, uSecRealtime);
+        mWifiActivity.writeToParcel(out, 0);
         for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             mGpsSignalQualityTimer[i].writeToParcel(out, uSecRealtime);
         }
-        mWifiActivity.writeToParcel(out, 0);
         mBluetoothActivity.writeToParcel(out, 0);
         mModemActivity.writeToParcel(out, 0);
         out.writeInt(mHasWifiReporting ? 1 : 0);
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index fcbbcd0..240fc51 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -97,6 +97,7 @@
     public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
             "bluetooth.controller.voltage";
 
+    public static final String POWER_MODEM_CONTROLLER_SLEEP = "modem.controller.sleep";
     public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle";
     public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx";
     public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx";
@@ -296,10 +297,6 @@
                 com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
                 com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
                 com.android.internal.R.integer.config_bluetooth_operating_voltage_mv,
-                com.android.internal.R.integer.config_wifi_idle_receive_cur_ma,
-                com.android.internal.R.integer.config_wifi_active_rx_cur_ma,
-                com.android.internal.R.integer.config_wifi_tx_cur_ma,
-                com.android.internal.R.integer.config_wifi_operating_voltage_mv,
         };
 
         String[] configResIdKeys = new String[]{
@@ -307,10 +304,6 @@
                 POWER_BLUETOOTH_CONTROLLER_RX,
                 POWER_BLUETOOTH_CONTROLLER_TX,
                 POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
-                POWER_WIFI_CONTROLLER_IDLE,
-                POWER_WIFI_CONTROLLER_RX,
-                POWER_WIFI_CONTROLLER_TX,
-                POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
         };
 
         for (int i = 0; i < configResIds.length; i++) {
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index eefcb74..34544d3 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -18,8 +18,108 @@
 
 #include <utils/String8.h>
 
+#include <map>
+
 namespace android {
 
+static const std::map<int, std::string> sErrorCodesMap = {
+    // Primary Result Code List
+    {4,     "SQLITE_ABORT"},
+    {23,    "SQLITE_AUTH"},
+    {5,     "SQLITE_BUSY"},
+    {14,    "SQLITE_CANTOPEN"},
+    {19,    "SQLITE_CONSTRAINT"},
+    {11,    "SQLITE_CORRUPT"},
+    {101,   "SQLITE_DONE"},
+    {16,    "SQLITE_EMPTY"},
+    {1,     "SQLITE_ERROR"},
+    {24,    "SQLITE_FORMAT"},
+    {13,    "SQLITE_FULL"},
+    {2,     "SQLITE_INTERNAL"},
+    {9,     "SQLITE_INTERRUPT"},
+    {10,    "SQLITE_IOERR"},
+    {6,     "SQLITE_LOCKED"},
+    {20,    "SQLITE_MISMATCH"},
+    {21,    "SQLITE_MISUSE"},
+    {22,    "SQLITE_NOLFS"},
+    {7,     "SQLITE_NOMEM"},
+    {26,    "SQLITE_NOTADB"},
+    {12,    "SQLITE_NOTFOUND"},
+    {27,    "SQLITE_NOTICE"},
+    {0,     "SQLITE_OK"},
+    {3,     "SQLITE_PERM"},
+    {15,    "SQLITE_PROTOCOL"},
+    {25,    "SQLITE_RANGE"},
+    {8,     "SQLITE_READONLY"},
+    {100,   "SQLITE_ROW"},
+    {17,    "SQLITE_SCHEMA"},
+    {18,    "SQLITE_TOOBIG"},
+    {28,    "SQLITE_WARNING"},
+    // Extended Result Code List
+    {516,   "SQLITE_ABORT_ROLLBACK"},
+    {261,   "SQLITE_BUSY_RECOVERY"},
+    {517,   "SQLITE_BUSY_SNAPSHOT"},
+    {1038,  "SQLITE_CANTOPEN_CONVPATH"},
+    {782,   "SQLITE_CANTOPEN_FULLPATH"},
+    {526,   "SQLITE_CANTOPEN_ISDIR"},
+    {270,   "SQLITE_CANTOPEN_NOTEMPDIR"},
+    {275,   "SQLITE_CONSTRAINT_CHECK"},
+    {531,   "SQLITE_CONSTRAINT_COMMITHOOK"},
+    {787,   "SQLITE_CONSTRAINT_FOREIGNKEY"},
+    {1043,  "SQLITE_CONSTRAINT_FUNCTION"},
+    {1299,  "SQLITE_CONSTRAINT_NOTNULL"},
+    {1555,  "SQLITE_CONSTRAINT_PRIMARYKEY"},
+    {2579,  "SQLITE_CONSTRAINT_ROWID"},
+    {1811,  "SQLITE_CONSTRAINT_TRIGGER"},
+    {2067,  "SQLITE_CONSTRAINT_UNIQUE"},
+    {2323,  "SQLITE_CONSTRAINT_VTAB"},
+    {267,   "SQLITE_CORRUPT_VTAB"},
+    {3338,  "SQLITE_IOERR_ACCESS"},
+    {2826,  "SQLITE_IOERR_BLOCKED"},
+    {3594,  "SQLITE_IOERR_CHECKRESERVEDLOCK"},
+    {4106,  "SQLITE_IOERR_CLOSE"},
+    {6666,  "SQLITE_IOERR_CONVPATH"},
+    {2570,  "SQLITE_IOERR_DELETE"},
+    {5898,  "SQLITE_IOERR_DELETE_NOENT"},
+    {4362,  "SQLITE_IOERR_DIR_CLOSE"},
+    {1290,  "SQLITE_IOERR_DIR_FSYNC"},
+    {1802,  "SQLITE_IOERR_FSTAT"},
+    {1034,  "SQLITE_IOERR_FSYNC"},
+    {6410,  "SQLITE_IOERR_GETTEMPPATH"},
+    {3850,  "SQLITE_IOERR_LOCK"},
+    {6154,  "SQLITE_IOERR_MMAP"},
+    {3082,  "SQLITE_IOERR_NOMEM"},
+    {2314,  "SQLITE_IOERR_RDLOCK"},
+    {266,   "SQLITE_IOERR_READ"},
+    {5642,  "SQLITE_IOERR_SEEK"},
+    {5130,  "SQLITE_IOERR_SHMLOCK"},
+    {5386,  "SQLITE_IOERR_SHMMAP"},
+    {4618,  "SQLITE_IOERR_SHMOPEN"},
+    {4874,  "SQLITE_IOERR_SHMSIZE"},
+    {522,   "SQLITE_IOERR_SHORT_READ"},
+    {1546,  "SQLITE_IOERR_TRUNCATE"},
+    {2058,  "SQLITE_IOERR_UNLOCK"},
+    {778,   "SQLITE_IOERR_WRITE"},
+    {262,   "SQLITE_LOCKED_SHAREDCACHE"},
+    {539,   "SQLITE_NOTICE_RECOVER_ROLLBACK"},
+    {283,   "SQLITE_NOTICE_RECOVER_WAL"},
+    {256,   "SQLITE_OK_LOAD_PERMANENTLY"},
+    {520,   "SQLITE_READONLY_CANTLOCK"},
+    {1032,  "SQLITE_READONLY_DBMOVED"},
+    {264,   "SQLITE_READONLY_RECOVERY"},
+    {776,   "SQLITE_READONLY_ROLLBACK"},
+    {284,   "SQLITE_WARNING_AUTOINDEX"},
+};
+
+static std::string sqlite3_error_code_to_msg(int errcode) {
+    auto it = sErrorCodesMap.find(errcode);
+    if (it != sErrorCodesMap.end()) {
+        return std::to_string(errcode) + " " + it->second;
+    } else {
+        return std::to_string(errcode);
+    }
+}
+
 /* throw a SQLiteException with a message appropriate for the error in handle */
 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
     throw_sqlite3_exception(env, handle, NULL);
@@ -123,7 +223,8 @@
     if (sqlite3Message) {
         String8 fullMessage;
         fullMessage.append(sqlite3Message);
-        fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
+        const char* errcode_msg = sqlite3_error_code_to_msg(errcode).c_str();
+        fullMessage.appendFormat(" (code %s)", errcode_msg); // print extended error code
         if (message) {
             fullMessage.append(": ");
             fullMessage.append(message);
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 8753bf7..c9f7d52 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -41,4 +41,13 @@
 
   // Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
   repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
+
+  // Whether device is a small battery device
+  optional bool is_small_battery_device = 6;
+
+  // Whether force app standby for small battery device setting is enabled
+  optional bool force_all_apps_standby_for_small_battery = 7;
+
+  // Whether device is charging
+  optional bool is_charging = 8;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ba30981..93d852c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2313,6 +2313,11 @@
     <permission android:name="android.permission.RECOVERY"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to read system update info.
+         @hide -->
+    <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
+        android:protectionLevel="signature" />
+
     <!-- Allows the system to bind to an application's task services
          @hide -->
     <permission android:name="android.permission.BIND_JOB_SERVICE"
@@ -2843,6 +2848,14 @@
     <permission android:name="android.permission.INSTALL_SELF_UPDATES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to install updates. This is a limited version
+         of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
+    <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to clear user data.
          <p>Not for use by third-party applications
          @hide
diff --git a/core/res/res/drawable/ic_screenshot.xml b/core/res/res/drawable/ic_screenshot.xml
index 3074b28..24dd4d8 100644
--- a/core/res/res/drawable/ic_screenshot.xml
+++ b/core/res/res/drawable/ic_screenshot.xml
@@ -17,10 +17,8 @@
     android:width="24.0dp"
     android:height="24.0dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:pathData="M0,0h24v24H0V0z"
-        android:fillColor="#00000000"/>
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
     <path
         android:fillColor="#FF000000"
         android:pathData="M17.0,1.0L7.0,1.0C5.9,1.0 5.0,1.9 5.0,3.0l0.0,18.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L19.0,3.0C19.0,1.9 18.1,1.0 17.0,1.0zM17.0,20.0L7.0,20.0L7.0,4.0l10.0,0.0L17.0,20.0z"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 64f291c..c623c9a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -645,19 +645,7 @@
 
     <!-- Wifi driver supports IEEE80211AC for softap -->
     <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
-
-    <!-- Idle Receive current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">0</integer>
-
-    <!-- Rx current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_active_rx_cur_ma">0</integer>
-
-    <!-- Tx current for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_tx_cur_ma">0</integer>
-
-    <!-- Operating volatage for wifi radio. 0 by default-->
-    <integer translatable="false" name="config_wifi_operating_voltage_mv">0</integer>
-
+    
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0c844c9..170ba42 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4821,4 +4821,7 @@
     <!-- Text describing a permission request for one app to show another app's
          slices [CHAR LIMIT=NONE] -->
     <string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
+
+    <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
+    <string name="screenshot_edit">Edit</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 03a800d..4ef0a6c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -384,10 +384,6 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="string"  name="config_wifi_random_mac_oui" />
   <java-symbol type="integer"  name="config_wifi_network_switching_blacklist_time" />
-  <java-symbol type="integer"  name="config_wifi_idle_receive_cur_ma" />
-  <java-symbol type="integer"  name="config_wifi_active_rx_cur_ma" />
-  <java-symbol type="integer"  name="config_wifi_tx_cur_ma" />
-  <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
   <java-symbol type="string"  name="config_wifi_framework_sap_2G_channel_list" />
   <java-symbol type="integer" name="config_wifi_framework_max_tx_rate_for_full_scan" />
   <java-symbol type="integer" name="config_wifi_framework_max_rx_rate_for_full_scan" />
@@ -3227,5 +3223,8 @@
   <java-symbol type="string" name="config_defaultAssistantAccessPackage" />
 
   <java-symbol type="bool" name="config_supportBluetoothPersistedState" />
+
   <java-symbol type="string" name="slices_permission_request" />
+
+  <java-symbol type="string" name="screenshot_edit" />
 </resources>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 6e31cd2..bc4b10f 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -51,15 +51,6 @@
       <value>0.1</value> <!-- ~1mA -->
   </array>
 
-
-  <!-- Radio related values. For modems WITH energy reporting support in firmware, use
-       modem.controller.idle, modem.controller.tx, modem.controller.rx, modem.controller.voltage.
-       -->
-  <item name="modem.controller.idle">0</item>
-  <item name="modem.controller.rx">0</item>
-  <item name="modem.controller.tx">0</item>
-  <item name="modem.controller.voltage">0</item>
-
   <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
        number of CPU cores for that cluster.
 
@@ -123,4 +114,17 @@
     <value>2</value>    <!-- 4097-/hr -->
   </array>
 
+  <!-- Cellular modem related values. Default is 0.-->
+  <item name="modem.controller.sleep">0</item>
+  <item name="modem.controller.idle">0</item>
+  <item name="modem.controller.rx">0</item>
+  <array name="modem.controller.tx"> <!-- Strength 0 to 4 -->
+    <value>0</value>
+    <value>0</value>
+    <value>0</value>
+    <value>0</value>
+    <value>0</value>
+  </array>
+  <item name="modem.controller.voltage">0</item>
+
 </device>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec3a6ce..fa0ea5c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -213,6 +213,7 @@
                     Settings.Global.FANCY_IME_ANIMATIONS,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
                     Settings.Global.FSTRIM_MANDATORY_INTERVAL,
                     Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                     Settings.Global.GLOBAL_HTTP_PROXY_HOST,
diff --git a/core/tests/privacytests/src/android/privacy/LongitudinalReportingEncoderTest.java b/core/tests/privacytests/src/android/privacy/LongitudinalReportingEncoderTest.java
index 9166438..6fe19a2 100644
--- a/core/tests/privacytests/src/android/privacy/LongitudinalReportingEncoderTest.java
+++ b/core/tests/privacytests/src/android/privacy/LongitudinalReportingEncoderTest.java
@@ -72,26 +72,26 @@
         final LongitudinalReportingEncoder encoder =
                 LongitudinalReportingEncoder.createInsecureEncoderForTest(
                         config);
+        assertEquals(0, encoder.encodeBoolean(true)[0]);
+        assertEquals(0, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(0, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
-        assertEquals(0, encoder.encodeBoolean(true)[0]);
-        assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
         assertEquals(1, encoder.encodeBoolean(true)[0]);
 
         assertEquals(0, encoder.encodeBoolean(false)[0]);
         assertEquals(1, encoder.encodeBoolean(false)[0]);
         assertEquals(1, encoder.encodeBoolean(false)[0]);
-        assertEquals(0, encoder.encodeBoolean(false)[0]);
+        assertEquals(1, encoder.encodeBoolean(false)[0]);
         assertEquals(0, encoder.encodeBoolean(false)[0]);
         assertEquals(0, encoder.encodeBoolean(false)[0]);
         assertEquals(1, encoder.encodeBoolean(false)[0]);
         assertEquals(0, encoder.encodeBoolean(false)[0]);
-        assertEquals(0, encoder.encodeBoolean(false)[0]);
+        assertEquals(1, encoder.encodeBoolean(false)[0]);
         assertEquals(1, encoder.encodeBoolean(false)[0]);
 
         // Test if IRR returns original result when f = 0
diff --git a/core/tests/privacytests/src/android/privacy/RapporEncoderTest.java b/core/tests/privacytests/src/android/privacy/RapporEncoderTest.java
index dad98b8..fa0343d 100644
--- a/core/tests/privacytests/src/android/privacy/RapporEncoderTest.java
+++ b/core/tests/privacytests/src/android/privacy/RapporEncoderTest.java
@@ -80,7 +80,7 @@
         int numBits = 8;
         final long inputValue = 254L;
         final long prrValue = 250L;
-        final long prrAndIrrValue = 184L;
+        final long prrAndIrrValue = 244L;
 
         final RapporConfig config1 = new RapporConfig(
                 "Foo", // encoderId
diff --git a/docs/html/reference/images/text/style/absolutesizespan.png b/docs/html/reference/images/text/style/absolutesizespan.png
new file mode 100644
index 0000000..40d5a79
--- /dev/null
+++ b/docs/html/reference/images/text/style/absolutesizespan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/relativesizespan.png b/docs/html/reference/images/text/style/relativesizespan.png
new file mode 100644
index 0000000..eaca5ad
--- /dev/null
+++ b/docs/html/reference/images/text/style/relativesizespan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/scalexspan.png b/docs/html/reference/images/text/style/scalexspan.png
new file mode 100644
index 0000000..a5ca26f
--- /dev/null
+++ b/docs/html/reference/images/text/style/scalexspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/strikethroughspan.png b/docs/html/reference/images/text/style/strikethroughspan.png
new file mode 100644
index 0000000..a49ecad
--- /dev/null
+++ b/docs/html/reference/images/text/style/strikethroughspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/subscriptspan.png b/docs/html/reference/images/text/style/subscriptspan.png
new file mode 100644
index 0000000..aac7092
--- /dev/null
+++ b/docs/html/reference/images/text/style/subscriptspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/superscriptspan.png b/docs/html/reference/images/text/style/superscriptspan.png
new file mode 100644
index 0000000..996f59d
--- /dev/null
+++ b/docs/html/reference/images/text/style/superscriptspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/underlinespan.png b/docs/html/reference/images/text/style/underlinespan.png
new file mode 100644
index 0000000..dbcd0d9
--- /dev/null
+++ b/docs/html/reference/images/text/style/underlinespan.png
Binary files differ
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index e2f02df..77925fd 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -142,6 +142,7 @@
 
 static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
                             SkPaint* paint) {
+    paint->setFilterQuality(kLow_SkFilterQuality);
     if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
         properties.xferMode() != SkBlendMode::kSrcOver || properties.colorFilter() != nullptr) {
         paint->setAlpha(properties.alpha() * alphaMultiplier);
@@ -200,18 +201,15 @@
         // composing a hardware layer
         if (renderNode->getLayerSurface() && mComposeLayer) {
             SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
-            SkPaint* paint = nullptr;
-            SkPaint tmpPaint;
-            if (layerNeedsPaint(layerProperties, alphaMultiplier, &tmpPaint)) {
-                paint = &tmpPaint;
-            }
+            SkPaint paint;
+            layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
 
             // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
             // we need to restrict the portion of the surface drawn to the size of the renderNode.
             SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width());
             SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height());
             canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(),
-                                  bounds, bounds, paint);
+                    bounds, bounds, &paint);
 
             if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
                 renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index c7f57fe..2953ea8 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1046,6 +1046,40 @@
     EXPECT_EQ(2, canvas.mDrawCounter);
 }
 
+// Verify that layers are composed with kLow_SkFilterQuality filter quality.
+RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
+    static const int CANVAS_WIDTH = 1;
+    static const int CANVAS_HEIGHT = 1;
+    static const int LAYER_WIDTH = 1;
+    static const int LAYER_HEIGHT = 1;
+    class FrameTestCanvas : public TestCanvasBase {
+    public:
+        FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+        void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+                const SkPaint* paint, SrcRectConstraint constraint) override {
+            mDrawCounter++;
+            EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality());
+        }
+    };
+
+    auto layerNode = TestUtils::createSkiaNode(
+            0, 0, LAYER_WIDTH, LAYER_HEIGHT,
+            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
+                canvas.drawPaint(SkPaint());
+            });
+
+    layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
+    layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
+
+    FrameTestCanvas canvas;
+    RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
+    canvas.drawDrawable(&drawable);
+    EXPECT_EQ(1, canvas.mDrawCounter);  //make sure the layer was composed
+
+    // clean up layer pointer, so we can safely destruct RenderNode
+    layerNode->setLayerSurface(nullptr);
+}
+
 TEST(ReorderBarrierDrawable, testShadowMatrix) {
     static const int CANVAS_WIDTH = 100;
     static const int CANVAS_HEIGHT = 100;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3c49b80..78477f7 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1380,7 +1380,8 @@
             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
                 enableNativeRoutingCallbacksLocked(true);
                 mRoutingChangeListeners.put(
-                        listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
+                                handler != null ? handler : mEventHandler));
             }
         }
     }
@@ -1401,36 +1402,6 @@
         }
     }
 
-    /**
-     * Helper class to handle the forwarding of native events to the appropriate listener
-     * (potentially) handled in a different thread
-     */
-    private class NativeRoutingEventHandlerDelegate {
-        private MediaRecorder mMediaRecorder;
-        private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
-        private Handler mHandler;
-
-        NativeRoutingEventHandlerDelegate(final MediaRecorder mediaRecorder,
-                final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
-            mMediaRecorder = mediaRecorder;
-            mOnRoutingChangedListener = listener;
-            mHandler = handler != null ? handler : mEventHandler;
-        }
-
-        void notifyClient() {
-            if (mHandler != null) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mOnRoutingChangedListener != null) {
-                            mOnRoutingChangedListener.onRoutingChanged(mMediaRecorder);
-                        }
-                    }
-                });
-            }
-        }
-    }
-
     private native final boolean native_setInputDevice(int deviceId);
     private native final int native_getRoutedDeviceId();
     private native final void native_enableDeviceCallback(boolean enabled);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index fadb76d..4c96d89 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -197,7 +197,7 @@
         assertFalse(metadata.isEmpty());
 
         CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false,
-                CameraCaptureSession.SESSION_ID_NONE);
+                CameraCaptureSession.SESSION_ID_NONE, mCameraId, /*physicalCameraIdSet*/null);
         assertFalse(request.isEmpty());
         assertFalse(metadata.isEmpty());
         if (needStream) {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b13de2e..f6541bb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1015,4 +1015,10 @@
     <!-- About phone, status item value if the actual value is not available. -->
     <string name="status_unavailable">Unavailable</string>
 
+    <!-- Summary to show how many devices are connected in wifi hotspot [CHAR LIMIT=NONE] -->
+    <plurals name="wifi_tether_connected_summary">
+        <item quantity="one">%1$d device connected</item>
+        <item quantity="other">%1$d devices connected</item>
+    </plurals>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 764c5922..9b69304 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -128,14 +128,18 @@
 
     public boolean connect(BluetoothDevice device) {
         if (mService == null) return false;
-        List<BluetoothDevice> sinks = getConnectedDevices();
-        if (sinks != null) {
-            for (BluetoothDevice sink : sinks) {
-                if (sink.equals(device)) {
-                    Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
-                    continue;
+        int max_connected_devices = mLocalAdapter.getMaxConnectedAudioDevices();
+        if (max_connected_devices == 1) {
+            // Original behavior: disconnect currently connected device
+            List<BluetoothDevice> sinks = getConnectedDevices();
+            if (sinks != null) {
+                for (BluetoothDevice sink : sinks) {
+                    if (sink.equals(device)) {
+                        Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
+                        continue;
+                    }
+                    mService.disconnect(sink);
                 }
-                mService.disconnect(sink);
             }
         }
         return mService.connect(device);
@@ -157,6 +161,16 @@
         return mService.getConnectionState(device);
     }
 
+    public boolean setActiveDevice(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.setActiveDevice(device);
+    }
+
+    public BluetoothDevice getActiveDevice() {
+        if (mService == null) return null;
+        return mService.getActiveDevice();
+    }
+
     public boolean isPreferred(BluetoothDevice device) {
         if (mService == null) return false;
         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
@@ -180,8 +194,8 @@
     boolean isA2dpPlaying() {
         if (mService == null) return false;
         List<BluetoothDevice> sinks = mService.getConnectedDevices();
-        if (!sinks.isEmpty()) {
-            if (mService.isA2dpPlaying(sinks.get(0))) {
+        for (BluetoothDevice device : sinks) {
+            if (mService.isA2dpPlaying(device)) {
                 return true;
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
index 4c41b49..ac3599c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -28,4 +28,5 @@
     void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
     void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
     void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);
+    void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile);
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index f57d02b..3cda9c9 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -16,9 +16,12 @@
 
 package com.android.settingslib.bluetooth;
 
+import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -31,6 +34,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -106,6 +110,12 @@
         // Dock event broadcasts
         addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
 
+        // Active device broadcasts
+        addHandler(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED,
+                   new ActiveDeviceChangedHandler());
+        addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED,
+                   new ActiveDeviceChangedHandler());
+
         mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler);
         mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler);
     }
@@ -409,4 +419,35 @@
 
         return deviceAdded;
     }
+
+    private class ActiveDeviceChangedHandler implements Handler {
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            String action = intent.getAction();
+            if (action == null) {
+                Log.w(TAG, "ActiveDeviceChangedHandler: action is null");
+                return;
+            }
+            CachedBluetoothDevice activeDevice = mDeviceManager.findDevice(device);
+            int bluetoothProfile = 0;
+            if (Objects.equals(action, BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) {
+                bluetoothProfile = BluetoothProfile.A2DP;
+            } else if (Objects.equals(action, BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
+                bluetoothProfile = BluetoothProfile.HEADSET;
+            } else {
+                Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action);
+                return;
+            }
+            dispatchActiveDeviceChanged(activeDevice, bluetoothProfile);
+        }
+    }
+
+    private void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice,
+                                             int bluetoothProfile) {
+        synchronized (mCallbacks) {
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onActiveDeviceChanged(activeDevice, bluetoothProfile);
+            }
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9caff10..fb0f75b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -105,6 +105,10 @@
     private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
     private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
 
+    // Active device state
+    private boolean mIsActiveDeviceA2dp = false;
+    private boolean mIsActiveDeviceHeadset = false;
+
     /**
      * Describes the current device and profile for logging.
      *
@@ -156,6 +160,7 @@
             mRemovedProfiles.add(profile);
             mLocalNapRoleConnected = false;
         }
+        fetchActiveDevices();
     }
 
     CachedBluetoothDevice(Context context,
@@ -359,6 +364,7 @@
         fetchName();
         fetchBtClass();
         updateProfiles();
+        fetchActiveDevices();
         migratePhonebookPermissionChoice();
         migrateMessagePermissionChoice();
         fetchMessageRejectionCount();
@@ -454,6 +460,33 @@
         return mDevice.getBondState();
     }
 
+    /**
+     * Set the device status as active or non-active per Bluetooth profile.
+     *
+     * @param isActive true if the device is active
+     * @param bluetoothProfile the Bluetooth profile
+     */
+    public void setActiveDevice(boolean isActive, int bluetoothProfile) {
+        boolean changed = false;
+        switch (bluetoothProfile) {
+        case BluetoothProfile.A2DP:
+            changed = (mIsActiveDeviceA2dp != isActive);
+            mIsActiveDeviceA2dp = isActive;
+            break;
+        case BluetoothProfile.HEADSET:
+            changed = (mIsActiveDeviceHeadset != isActive);
+            mIsActiveDeviceHeadset = isActive;
+            break;
+        default:
+            Log.w(TAG, "setActiveDevice: unknown profile " + bluetoothProfile +
+                    " isActive " + isActive);
+            break;
+        }
+        if (changed) {
+            dispatchAttributesChanged();
+        }
+    }
+
     void setRssi(short rssi) {
         if (mRssi != rssi) {
             mRssi = rssi;
@@ -529,6 +562,17 @@
         return true;
     }
 
+    private void fetchActiveDevices() {
+        A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+        if (a2dpProfile != null) {
+            mIsActiveDeviceA2dp = mDevice.equals(a2dpProfile.getActiveDevice());
+        }
+        HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile();
+        if (headsetProfile != null) {
+            mIsActiveDeviceHeadset = mDevice.equals(headsetProfile.getActiveDevice());
+        }
+    }
+
     /**
      * Refreshes the UI for the BT class, including fetching the latest value
      * for the class.
@@ -896,37 +940,60 @@
                     com.android.settingslib.Utils.formatPercentage(batteryLevel);
         }
 
+        // TODO: A temporary workaround solution using string description the device is active.
+        // Issue tracked by b/72317067 .
+        // An alternative solution would be visual indication.
+        // Intentionally not adding the strings to strings.xml for now:
+        //  1) If this is just a short-term solution, no need to waste translation effort
+        //  2) The number of strings with all possible combinations becomes enormously large.
+        // If string description becomes part of the final solution, we MUST NOT
+        // concatenate the strings here: this does not translate well.
+        String activeString = null;
+        if (mIsActiveDeviceA2dp && mIsActiveDeviceHeadset) {
+            activeString = ", active";
+        } else {
+            if (mIsActiveDeviceA2dp) {
+                activeString = ", active(media)";
+            }
+            if (mIsActiveDeviceHeadset) {
+                activeString = ", active(phone)";
+            }
+        }
+        if (activeString == null) activeString = "";
+
         if (profileConnected) {
             if (a2dpNotConnected && hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(
                             R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
-                            batteryLevelPercentageString);
+                            batteryLevelPercentageString) + activeString;
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp);
+                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp) +
+                        activeString;
                 }
 
             } else if (a2dpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level,
-                            batteryLevelPercentageString);
+                            batteryLevelPercentageString) + activeString;
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_a2dp);
+                    return mContext.getString(R.string.bluetooth_connected_no_a2dp) + activeString;
                 }
 
             } else if (hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level,
-                            batteryLevelPercentageString);
+                            batteryLevelPercentageString) + activeString;
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset);
+                    return mContext.getString(R.string.bluetooth_connected_no_headset)
+                          + activeString;
                 }
             } else {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_battery_level,
-                            batteryLevelPercentageString);
+                            batteryLevelPercentageString) + activeString;
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected);
+                    return mContext.getString(R.string.bluetooth_connected) + activeString;
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index d45fe1a..ee12191 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -153,6 +153,16 @@
         return BluetoothProfile.STATE_DISCONNECTED;
     }
 
+    public boolean setActiveDevice(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.setActiveDevice(device);
+    }
+
+    public BluetoothDevice getActiveDevice() {
+        if (mService == null) return null;
+        return mService.getActiveDevice();
+    }
+
     public boolean isPreferred(BluetoothDevice device) {
         if (mService == null) return false;
         return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 22674cb..cda4e45 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -239,4 +239,8 @@
     public BluetoothDevice getRemoteDevice(String address) {
         return mAdapter.getRemoteDevice(address);
     }
+
+    public int getMaxConnectedAudioDevices() {
+        return mAdapter.getMaxConnectedAudioDevices();
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
deleted file mode 100644
index 7227304..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.core.instrumentation;
-
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-
-/**
- * {@link LogWriter} that writes data to eventlog.
- */
-public class EventLogWriter implements LogWriter {
-
-    private final MetricsLogger mMetricsLogger = new MetricsLogger();
-
-    public void visible(Context context, int source, int category) {
-        final LogMaker logMaker = new LogMaker(category)
-                .setType(MetricsProto.MetricsEvent.TYPE_OPEN)
-                .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
-        MetricsLogger.action(logMaker);
-    }
-
-    public void hidden(Context context, int category) {
-        MetricsLogger.hidden(context, category);
-    }
-
-    public void action(int category, int value, Pair<Integer, Object>... taggedData) {
-        if (taggedData == null || taggedData.length == 0) {
-            mMetricsLogger.action(category, value);
-        } else {
-            final LogMaker logMaker = new LogMaker(category)
-                    .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
-                    .setSubtype(value);
-            for (Pair<Integer, Object> pair : taggedData) {
-                logMaker.addTaggedData(pair.first, pair.second);
-            }
-            mMetricsLogger.write(logMaker);
-        }
-    }
-
-    public void action(int category, boolean value, Pair<Integer, Object>... taggedData) {
-        action(category, value ? 1 : 0, taggedData);
-    }
-
-    public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
-        action(context, category, "", taggedData);
-    }
-
-    public void actionWithSource(Context context, int source, int category) {
-        final LogMaker logMaker = new LogMaker(category)
-                .setType(MetricsProto.MetricsEvent.TYPE_ACTION);
-        if (source != MetricsProto.MetricsEvent.VIEW_UNKNOWN) {
-            logMaker.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
-        }
-        MetricsLogger.action(logMaker);
-    }
-
-    /** @deprecated use {@link #action(int, int, Pair[])} */
-    @Deprecated
-    public void action(Context context, int category, int value) {
-        MetricsLogger.action(context, category, value);
-    }
-
-    /** @deprecated use {@link #action(int, boolean, Pair[])} */
-    @Deprecated
-    public void action(Context context, int category, boolean value) {
-        MetricsLogger.action(context, category, value);
-    }
-
-    public void action(Context context, int category, String pkg,
-            Pair<Integer, Object>... taggedData) {
-        if (taggedData == null || taggedData.length == 0) {
-            MetricsLogger.action(context, category, pkg);
-        } else {
-            final LogMaker logMaker = new LogMaker(category)
-                    .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
-                    .setPackageName(pkg);
-            for (Pair<Integer, Object> pair : taggedData) {
-                logMaker.addTaggedData(pair.first, pair.second);
-            }
-            MetricsLogger.action(logMaker);
-        }
-    }
-
-    public void count(Context context, String name, int value) {
-        MetricsLogger.count(context, name, value);
-    }
-
-    public void histogram(Context context, String name, int bucket) {
-        MetricsLogger.histogram(context, name, bucket);
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
deleted file mode 100644
index 4b9f572..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.instrumentation;
-
-import android.content.Context;
-import android.util.Pair;
-
-/**
- * Generic log writer interface.
- */
-public interface LogWriter {
-
-    /**
-     * Logs a visibility event when view becomes visible.
-     */
-    void visible(Context context, int source, int category);
-
-    /**
-     * Logs a visibility event when view becomes hidden.
-     */
-    void hidden(Context context, int category);
-
-    /**
-     * Logs a user action.
-     */
-    void action(int category, int value, Pair<Integer, Object>... taggedData);
-
-    /**
-     * Logs a user action.
-     */
-    void action(int category, boolean value, Pair<Integer, Object>... taggedData);
-
-    /**
-     * Logs an user action.
-     */
-    void action(Context context, int category, Pair<Integer, Object>... taggedData);
-
-    /**
-     * Logs an user action.
-     */
-    void actionWithSource(Context context, int source, int category);
-
-    /**
-     * Logs an user action.
-     * @deprecated use {@link #action(int, int, Pair[])}
-     */
-    @Deprecated
-    void action(Context context, int category, int value);
-
-    /**
-     * Logs an user action.
-     * @deprecated use {@link #action(int, boolean, Pair[])}
-     */
-    @Deprecated
-    void action(Context context, int category, boolean value);
-
-    /**
-     * Logs an user action.
-     */
-    void action(Context context, int category, String pkg, Pair<Integer, Object>... taggedData);
-
-    /**
-     * Logs a count.
-     */
-    void count(Context context, String name, int value);
-
-    /**
-     * Logs a histogram event.
-     */
-    void histogram(Context context, String name, int bucket);
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
deleted file mode 100644
index 1e5b378..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.instrumentation;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * FeatureProvider for metrics.
- */
-public class MetricsFeatureProvider {
-    private List<LogWriter> mLoggerWriters;
-
-    public MetricsFeatureProvider() {
-        mLoggerWriters = new ArrayList<>();
-        installLogWriters();
-    }
-
-    protected void installLogWriters() {
-        mLoggerWriters.add(new EventLogWriter());
-    }
-
-    public void visible(Context context, int source, int category) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.visible(context, source, category);
-        }
-    }
-
-    public void hidden(Context context, int category) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.hidden(context, category);
-        }
-    }
-
-    public void actionWithSource(Context context, int source, int category) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.actionWithSource(context, source, category);
-        }
-    }
-
-    /**
-     * Logs a user action. Includes the elapsed time since the containing
-     * fragment has been visible.
-     */
-    public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(category, value,
-                    sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
-        }
-    }
-
-    /**
-     * Logs a user action. Includes the elapsed time since the containing
-     * fragment has been visible.
-     */
-    public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(category, value,
-                    sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
-        }
-    }
-
-    public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(context, category, taggedData);
-        }
-    }
-
-    /** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */
-    @Deprecated
-    public void action(Context context, int category, int value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(context, category, value);
-        }
-    }
-
-    /** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */
-    @Deprecated
-    public void action(Context context, int category, boolean value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(context, category, value);
-        }
-    }
-
-    public void action(Context context, int category, String pkg,
-            Pair<Integer, Object>... taggedData) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.action(context, category, pkg, taggedData);
-        }
-    }
-
-    public void count(Context context, String name, int value) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.count(context, name, value);
-        }
-    }
-
-    public void histogram(Context context, String name, int bucket) {
-        for (LogWriter writer : mLoggerWriters) {
-            writer.histogram(context, name, bucket);
-        }
-    }
-
-    public int getMetricsCategory(Object object) {
-        if (object == null || !(object instanceof Instrumentable)) {
-            return MetricsEvent.VIEW_UNKNOWN;
-        }
-        return ((Instrumentable) object).getMetricsCategory();
-    }
-
-    public void logDashboardStartIntent(Context context, Intent intent,
-            int sourceMetricsCategory) {
-        if (intent == null) {
-            return;
-        }
-        final ComponentName cn = intent.getComponent();
-        if (cn == null) {
-            final String action = intent.getAction();
-            if (TextUtils.isEmpty(action)) {
-                // Not loggable
-                return;
-            }
-            action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, action,
-                    Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
-            return;
-        } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
-            // Going to a Setting internal page, skip click logging in favor of page's own
-            // visibility logging.
-            return;
-        }
-        action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, cn.flattenToString(),
-                Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
-    }
-
-    private Pair<Integer, Object> sinceVisibleTaggedData(long timestamp) {
-        return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp);
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
deleted file mode 100644
index facce4e..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.settingslib.core.instrumentation;
-
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.AsyncTask;
-import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentSkipListSet;
-
-public class SharedPreferencesLogger implements SharedPreferences {
-
-    private static final String LOG_TAG = "SharedPreferencesLogger";
-
-    private final String mTag;
-    private final Context mContext;
-    private final MetricsFeatureProvider mMetricsFeature;
-    private final Set<String> mPreferenceKeySet;
-
-    public SharedPreferencesLogger(Context context, String tag,
-            MetricsFeatureProvider metricsFeature) {
-        mContext = context;
-        mTag = tag;
-        mMetricsFeature = metricsFeature;
-        mPreferenceKeySet = new ConcurrentSkipListSet<>();
-    }
-
-    @Override
-    public Map<String, ?> getAll() {
-        return null;
-    }
-
-    @Override
-    public String getString(String key, @Nullable String defValue) {
-        return defValue;
-    }
-
-    @Override
-    public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
-        return defValues;
-    }
-
-    @Override
-    public int getInt(String key, int defValue) {
-        return defValue;
-    }
-
-    @Override
-    public long getLong(String key, long defValue) {
-        return defValue;
-    }
-
-    @Override
-    public float getFloat(String key, float defValue) {
-        return defValue;
-    }
-
-    @Override
-    public boolean getBoolean(String key, boolean defValue) {
-        return defValue;
-    }
-
-    @Override
-    public boolean contains(String key) {
-        return false;
-    }
-
-    @Override
-    public Editor edit() {
-        return new EditorLogger();
-    }
-
-    @Override
-    public void registerOnSharedPreferenceChangeListener(
-            OnSharedPreferenceChangeListener listener) {
-    }
-
-    @Override
-    public void unregisterOnSharedPreferenceChangeListener(
-            OnSharedPreferenceChangeListener listener) {
-    }
-
-    private void logValue(String key, Object value) {
-        logValue(key, value, false /* forceLog */);
-    }
-
-    private void logValue(String key, Object value, boolean forceLog) {
-        final String prefKey = buildPrefKey(mTag, key);
-        if (!forceLog && !mPreferenceKeySet.contains(prefKey)) {
-            // Pref key doesn't exist in set, this is initial display so we skip metrics but
-            // keeps track of this key.
-            mPreferenceKeySet.add(prefKey);
-            return;
-        }
-        // TODO: Remove count logging to save some resource.
-        mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1);
-
-        final Pair<Integer, Object> valueData;
-        if (value instanceof Long) {
-            final Long longVal = (Long) value;
-            final int intVal;
-            if (longVal > Integer.MAX_VALUE) {
-                intVal = Integer.MAX_VALUE;
-            } else if (longVal < Integer.MIN_VALUE) {
-                intVal = Integer.MIN_VALUE;
-            } else {
-                intVal = longVal.intValue();
-            }
-            valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
-                    intVal);
-        } else if (value instanceof Integer) {
-            valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
-                    value);
-        } else if (value instanceof Boolean) {
-            valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
-                    (Boolean) value ? 1 : 0);
-        } else if (value instanceof Float) {
-            valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE,
-                    value);
-        } else if (value instanceof String) {
-            Log.d(LOG_TAG, "Tried to log string preference " + prefKey + " = " + value);
-            valueData = null;
-        } else {
-            Log.w(LOG_TAG, "Tried to log unloggable object" + value);
-            valueData = null;
-        }
-        if (valueData != null) {
-            // Pref key exists in set, log it's change in metrics.
-            mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE,
-                    Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey),
-                    valueData);
-        }
-    }
-
-    @VisibleForTesting
-    void logPackageName(String key, String value) {
-        final String prefKey = mTag + "/" + key;
-        mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, value,
-                Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey));
-    }
-
-    private void safeLogValue(String key, String value) {
-        new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value);
-    }
-
-    public static String buildCountName(String prefKey, Object value) {
-        return prefKey + "|" + value;
-    }
-
-    public static String buildPrefKey(String tag, String key) {
-        return tag + "/" + key;
-    }
-
-    private class AsyncPackageCheck extends AsyncTask<String, Void, Void> {
-        @Override
-        protected Void doInBackground(String... params) {
-            String key = params[0];
-            String value = params[1];
-            PackageManager pm = mContext.getPackageManager();
-            try {
-                // Check if this might be a component.
-                ComponentName name = ComponentName.unflattenFromString(value);
-                if (value != null) {
-                    value = name.getPackageName();
-                }
-            } catch (Exception e) {
-            }
-            try {
-                pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER);
-                logPackageName(key, value);
-            } catch (PackageManager.NameNotFoundException e) {
-                // Clearly not a package, and it's unlikely this preference is in prefSet, so
-                // lets force log it.
-                logValue(key, value, true /* forceLog */);
-            }
-            return null;
-        }
-    }
-
-    public class EditorLogger implements Editor {
-        @Override
-        public Editor putString(String key, @Nullable String value) {
-            safeLogValue(key, value);
-            return this;
-        }
-
-        @Override
-        public Editor putStringSet(String key, @Nullable Set<String> values) {
-            safeLogValue(key, TextUtils.join(",", values));
-            return this;
-        }
-
-        @Override
-        public Editor putInt(String key, int value) {
-            logValue(key, value);
-            return this;
-        }
-
-        @Override
-        public Editor putLong(String key, long value) {
-            logValue(key, value);
-            return this;
-        }
-
-        @Override
-        public Editor putFloat(String key, float value) {
-            logValue(key, value);
-            return this;
-        }
-
-        @Override
-        public Editor putBoolean(String key, boolean value) {
-            logValue(key, value);
-            return this;
-        }
-
-        @Override
-        public Editor remove(String key) {
-            return this;
-        }
-
-        @Override
-        public Editor clear() {
-            return this;
-        }
-
-        @Override
-        public boolean commit() {
-            return true;
-        }
-
-        @Override
-        public void apply() {
-        }
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
deleted file mode 100644
index 7983896..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.core.instrumentation;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-
-import android.os.SystemClock;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-
-import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
-
-/**
- * Logs visibility change of a fragment.
- */
-public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause {
-
-    private static final String TAG = "VisibilityLoggerMixin";
-
-    private final int mMetricsCategory;
-
-    private MetricsFeatureProvider mMetricsFeature;
-    private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
-    private long mVisibleTimestamp;
-
-    /**
-     * The metrics category constant for logging source when a setting fragment is opened.
-     */
-    public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics";
-
-    private VisibilityLoggerMixin() {
-        mMetricsCategory = METRICS_CATEGORY_UNKNOWN;
-    }
-
-    public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
-        mMetricsCategory = metricsCategory;
-        mMetricsFeature = metricsFeature;
-    }
-
-    @Override
-    public void onResume() {
-        mVisibleTimestamp = SystemClock.elapsedRealtime();
-        if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
-            mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
-        }
-    }
-
-    @Override
-    public void onPause() {
-        mVisibleTimestamp = 0;
-        if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
-            mMetricsFeature.hidden(null /* context */, mMetricsCategory);
-        }
-    }
-
-    /**
-     * Sets source metrics category for this logger. Source is the caller that opened this UI.
-     */
-    public void setSourceMetricsCategory(Activity activity) {
-        if (mSourceMetricsCategory != MetricsProto.MetricsEvent.VIEW_UNKNOWN || activity == null) {
-            return;
-        }
-        final Intent intent = activity.getIntent();
-        if (intent == null) {
-            return;
-        }
-        mSourceMetricsCategory = intent.getIntExtra(EXTRA_SOURCE_METRICS_CATEGORY,
-                MetricsProto.MetricsEvent.VIEW_UNKNOWN);
-    }
-
-    /** Returns elapsed time since onResume() */
-    public long elapsedTimeSinceVisible() {
-        if (mVisibleTimestamp == 0) {
-            return 0;
-        }
-        return SystemClock.elapsedRealtime() - mVisibleTimestamp;
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
deleted file mode 100644
index 8bea51d..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.instrumentation;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Pair;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class MetricsFeatureProviderTest {
-    private static int CATEGORY = 10;
-    private static boolean SUBTYPE_BOOLEAN = true;
-    private static int SUBTYPE_INTEGER = 1;
-    private static long ELAPSED_TIME = 1000;
-
-    @Mock private LogWriter mockLogWriter;
-    @Mock private VisibilityLoggerMixin mockVisibilityLogger;
-
-    private Context mContext;
-    private MetricsFeatureProvider mProvider;
-
-    @Captor
-    private ArgumentCaptor<Pair> mPairCaptor;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mProvider = new MetricsFeatureProvider();
-        List<LogWriter> writers = new ArrayList<>();
-        writers.add(mockLogWriter);
-        ReflectionHelpers.setField(mProvider, "mLoggerWriters", writers);
-
-        when(mockVisibilityLogger.elapsedTimeSinceVisible()).thenReturn(ELAPSED_TIME);
-    }
-
-    @Test
-    public void logDashboardStartIntent_intentEmpty_shouldNotLog() {
-        mProvider.logDashboardStartIntent(mContext, null /* intent */,
-                MetricsEvent.SETTINGS_GESTURES);
-
-        verifyNoMoreInteractions(mockLogWriter);
-    }
-
-    @Test
-    public void logDashboardStartIntent_intentHasNoComponent_shouldLog() {
-        final Intent intent = new Intent(Intent.ACTION_ASSIST);
-
-        mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
-
-        verify(mockLogWriter).action(
-                eq(mContext),
-                eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
-                anyString(),
-                eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
-    }
-
-    @Test
-    public void logDashboardStartIntent_intentIsExternal_shouldLog() {
-        final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
-
-        mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
-
-        verify(mockLogWriter).action(
-                eq(mContext),
-                eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
-                anyString(),
-                eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
-    }
-
-    @Test
-    public void action_BooleanLogsElapsedTime() {
-        mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_BOOLEAN);
-        verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_BOOLEAN), mPairCaptor.capture());
-
-        Pair value = mPairCaptor.getValue();
-        assertThat(value.first instanceof Integer).isTrue();
-        assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
-        assertThat(value.second).isEqualTo(ELAPSED_TIME);
-    }
-
-    @Test
-    public void action_IntegerLogsElapsedTime() {
-        mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_INTEGER);
-        verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_INTEGER), mPairCaptor.capture());
-
-        Pair value = mPairCaptor.getValue();
-        assertThat(value.first instanceof Integer).isTrue();
-        assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
-        assertThat(value.second).isEqualTo(ELAPSED_TIME);
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
deleted file mode 100644
index d558a64..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.instrumentation;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Pair;
-
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-
-import com.google.common.truth.Platform;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class SharedPreferenceLoggerTest {
-
-    private static final String TEST_TAG = "tag";
-    private static final String TEST_KEY = "key";
-
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private Context mContext;
-
-    private ArgumentMatcher<Pair<Integer, Object>> mNamePairMatcher;
-    @Mock
-    private MetricsFeatureProvider mMetricsFeature;
-    private SharedPreferencesLogger mSharedPrefLogger;
-
-    @Before
-    public void init() {
-        MockitoAnnotations.initMocks(this);
-        mSharedPrefLogger = new SharedPreferencesLogger(mContext, TEST_TAG, mMetricsFeature);
-        mNamePairMatcher = pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, String.class);
-    }
-
-    @Test
-    public void putInt_shouldNotLogInitialPut() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        editor.putInt(TEST_KEY, 1);
-        editor.putInt(TEST_KEY, 1);
-        editor.putInt(TEST_KEY, 1);
-        editor.putInt(TEST_KEY, 2);
-        editor.putInt(TEST_KEY, 2);
-        editor.putInt(TEST_KEY, 2);
-        editor.putInt(TEST_KEY, 2);
-
-        verify(mMetricsFeature, times(6)).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
-    }
-
-    @Test
-    public void putBoolean_shouldNotLogInitialPut() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        editor.putBoolean(TEST_KEY, true);
-        editor.putBoolean(TEST_KEY, true);
-        editor.putBoolean(TEST_KEY, false);
-        editor.putBoolean(TEST_KEY, false);
-        editor.putBoolean(TEST_KEY, false);
-
-
-        verify(mMetricsFeature).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, true)));
-        verify(mMetricsFeature, times(3)).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, false)));
-    }
-
-    @Test
-    public void putLong_shouldNotLogInitialPut() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, 2);
-
-        verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
-    }
-
-    @Test
-    public void putLong_biggerThanIntMax_shouldLogIntMax() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        final long veryBigNumber = 500L + Integer.MAX_VALUE;
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, veryBigNumber);
-
-        verify(mMetricsFeature).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(
-                        FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MAX_VALUE)));
-    }
-
-    @Test
-    public void putLong_smallerThanIntMin_shouldLogIntMin() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        final long veryNegativeNumber = -500L + Integer.MIN_VALUE;
-        editor.putLong(TEST_KEY, 1);
-        editor.putLong(TEST_KEY, veryNegativeNumber);
-
-        verify(mMetricsFeature).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(
-                        FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MIN_VALUE)));
-    }
-
-    @Test
-    public void putFloat_shouldNotLogInitialPut() {
-        final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
-        editor.putFloat(TEST_KEY, 1);
-        editor.putFloat(TEST_KEY, 1);
-        editor.putFloat(TEST_KEY, 1);
-        editor.putFloat(TEST_KEY, 1);
-        editor.putFloat(TEST_KEY, 2);
-
-        verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
-                argThat(mNamePairMatcher),
-                argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, Float.class)));
-    }
-
-    @Test
-    public void logPackage_shouldUseLogPackageApi() {
-        mSharedPrefLogger.logPackageName("key", "com.android.settings");
-        verify(mMetricsFeature).action(any(Context.class),
-                eq(ACTION_SETTINGS_PREFERENCE_CHANGE),
-                eq("com.android.settings"),
-                any(Pair.class));
-    }
-
-    private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) {
-        return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz);
-    }
-
-    private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) {
-        return pair -> pair.first == tag
-                && Platform.isInstanceOfType(pair.second, Integer.class)
-                && pair.second.equals((bool ? 1 : 0));
-    }
-
-    private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) {
-        return pair -> pair.first == tag
-                && Platform.isInstanceOfType(pair.second, Integer.class)
-                && pair.second.equals(val);
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
deleted file mode 100644
index a264886..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.instrumentation;
-
-import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
-
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class VisibilityLoggerMixinTest {
-
-    @Mock
-    private MetricsFeatureProvider mMetricsFeature;
-
-    private VisibilityLoggerMixin mMixin;
-
-    @Before
-    public void init() {
-        MockitoAnnotations.initMocks(this);
-        mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, mMetricsFeature);
-    }
-
-    @Test
-    public void shouldLogVisibleOnResume() {
-        mMixin.onResume();
-
-        verify(mMetricsFeature, times(1))
-                .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN),
-                        eq(TestInstrumentable.TEST_METRIC));
-    }
-
-    @Test
-    public void shouldLogVisibleWithSource() {
-        final Intent sourceIntent = new Intent()
-                .putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
-                        MetricsProto.MetricsEvent.SETTINGS_GESTURES);
-        final Activity activity = mock(Activity.class);
-        when(activity.getIntent()).thenReturn(sourceIntent);
-        mMixin.setSourceMetricsCategory(activity);
-        mMixin.onResume();
-
-        verify(mMetricsFeature, times(1))
-                .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES),
-                        eq(TestInstrumentable.TEST_METRIC));
-    }
-
-    @Test
-    public void shouldLogHideOnPause() {
-        mMixin.onPause();
-
-        verify(mMetricsFeature, times(1))
-                .hidden(nullable(Context.class), eq(TestInstrumentable.TEST_METRIC));
-    }
-
-    @Test
-    public void shouldNotLogIfMetricsFeatureIsNull() {
-        mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, null);
-        mMixin.onResume();
-        mMixin.onPause();
-
-        verify(mMetricsFeature, never())
-                .hidden(nullable(Context.class), anyInt());
-    }
-
-    @Test
-    public void shouldNotLogIfMetricsCategoryIsUnknown() {
-        mMixin = new VisibilityLoggerMixin(METRICS_CATEGORY_UNKNOWN, mMetricsFeature);
-
-        mMixin.onResume();
-        mMixin.onPause();
-
-        verify(mMetricsFeature, never())
-                .hidden(nullable(Context.class), anyInt());
-    }
-
-    private final class TestInstrumentable implements Instrumentable {
-
-        public static final int TEST_METRIC = 12345;
-
-        @Override
-        public int getMetricsCategory() {
-            return TEST_METRIC;
-        }
-    }
-}
diff --git a/packages/SystemUI/res/drawable/ic_screenshot_edit.xml b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
new file mode 100644
index 0000000..d901292
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_screenshot_edit.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.81,9.94l-3.75,-3.75L3.0,17.25zM20.71,7.04c0.39,-0.3 0.39,-1.02 0.0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+    <path
+        android:pathData="M0 0h24v24H0z"
+        android:fillColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index bfe1b62..2c69501 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -41,6 +41,17 @@
         systemui:showDark="false"
     />
 
+    <com.android.systemui.statusbar.policy.DateView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="4dp"
+        android:singleLine="true"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+        android:textSize="@dimen/qs_time_collapsed_size"
+        android:gravity="center_vertical"
+        systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
+
     <android.widget.Space
         android:id="@+id/space"
         android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
index 7762950..5074682 100644
--- a/packages/SystemUI/res/layout/rotate_suggestion.xml
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -14,19 +14,13 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:layout_width="@dimen/navigation_side_padding"
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/rotate_suggestion"
+    android:layout_width="@dimen/navigation_extra_key_width"
     android:layout_height="match_parent"
-    android:layout_weight="0"
-    >
-    <com.android.systemui.statusbar.policy.KeyButtonView
-        android:id="@+id/rotate_suggestion"
-        android:layout_width="@dimen/navigation_extra_key_width"
-        android:layout_height="match_parent"
-        android:layout_marginEnd="2dp"
-        android:visibility="invisible"
-        android:scaleType="centerInside"
-    />
-    <!-- TODO android:contentDescription -->
-</FrameLayout>
+    android:layout_marginEnd="2dp"
+    android:visibility="invisible"
+    android:scaleType="centerInside"
+    android:contentDescription="@string/accessibility_rotate_button"
+/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 199ccfc..ab83bcf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -228,6 +228,8 @@
     <string name="accessibility_menu">Menu</string>
     <!-- Content description of the accessibility button in the navigation bar (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_accessibility_button">Accessibility</string>
+    <!-- Content description of the rotate button in the navigation bar (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_rotate_button">Rotate screen</string>
     <!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_recent">Overview</string>
     <!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4837fef..bcce6d1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -173,7 +173,7 @@
     <style name="TextAppearance.StatusBar.Expanded.Date">
         <item name="android:textSize">@dimen/qs_time_expanded_size</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textColor">#ffffffff</item>
         <item name="android:fontFamily">sans-serif</item>
     </style>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 13f30b2..7d159b7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorSet;
 import android.animation.RectEvaluator;
 import android.annotation.FloatRange;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -39,6 +40,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.ViewRootImpl;
 import android.view.ViewStub;
 
 import java.util.ArrayList;
@@ -294,17 +296,25 @@
     }
 
     /**
-     * @return The next frame name for the specified surface.
+     * @return The next frame name for the specified surface or -1 if the surface is no longer
+     *         valid.
      */
     public static long getNextFrameNumber(Surface s) {
-        return s.getNextFrameNumber();
+        return s != null && s.isValid()
+                ? s.getNextFrameNumber()
+                : -1;
+
     }
 
     /**
      * @return The surface for the specified view.
      */
-    public static Surface getSurface(View v) {
-        return v.getViewRootImpl().mSurface;
+    public static @Nullable Surface getSurface(View v) {
+        ViewRootImpl viewRoot = v.getViewRootImpl();
+        if (viewRoot == null) {
+            return null;
+        }
+        return viewRoot.mSurface;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 4b775a5..b8411e2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -608,6 +608,9 @@
         public void onScanningStateChanged(boolean started) { }
         @Override
         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
+        @Override
+        public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice,
+                                          int bluetoothProfile) { }
     }
 
     private final class BluetoothErrorListener implements Utils.ErrorListener {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index e6fd2f4..a97b35c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -18,10 +18,12 @@
 import static android.app.StatusBarManager.DISABLE_NONE;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
+import android.provider.AlarmClock;
 import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
 import android.view.View;
@@ -41,7 +43,8 @@
 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
-public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks {
+public class QuickStatusBarHeader extends RelativeLayout
+        implements CommandQueue.Callbacks, View.OnClickListener {
 
     private ActivityStarter mActivityStarter;
 
@@ -54,6 +57,8 @@
     protected QuickQSPanel mHeaderQsPanel;
     protected QSTileHost mHost;
 
+    private View mDate;
+
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -64,6 +69,8 @@
         Resources res = getResources();
 
         mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
+        mDate = findViewById(R.id.date);
+        mDate.setOnClickListener(this);
 
         // RenderThread is doing more harm than good when touching the header (to expand quick
         // settings), so disable it for this view
@@ -145,6 +152,14 @@
         super.onDetachedFromWindow();
     }
 
+    @Override
+    public void onClick(View v) {
+        if (v == mDate) {
+            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent(
+                    AlarmClock.ACTION_SHOW_ALARMS), 0);
+        }
+    }
+
     public void setListening(boolean listening) {
         if (listening == mListening) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 9e265e22..4ceace3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -33,7 +33,6 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.service.quicksettings.Tile;
-import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -55,7 +54,6 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeController.Callback;
 import com.android.systemui.volume.ZenModePanel;
 
 /** Quick settings tile: Do not disturb **/
@@ -134,8 +132,7 @@
         if (mState.value) {
             mController.setZen(ZEN_MODE_OFF, null, TAG);
         } else {
-            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
-            mController.setZen(zen, null, TAG);
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
         }
     }
 
@@ -159,9 +156,7 @@
                     showDetail(true);
                 }
             });
-            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
-                    Global.ZEN_MODE_ALARMS);
-            mController.setZen(zen, null, TAG);
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
         } else {
             showDetail(true);
         }
@@ -313,9 +308,7 @@
                 mController.setZen(ZEN_MODE_OFF, null, TAG);
                 mAuto = false;
             } else {
-                int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
-                        ZEN_MODE_ALARMS);
-                mController.setZen(zen, null, TAG);
+                mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 6db46b5..675aa8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -293,12 +293,13 @@
             sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
             sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
 
-            // Create a share action for the notification. Note, we proxy the call to ShareReceiver
-            // because RemoteViews currently forces an activity options on the PendingIntent being
-            // launched, and since we don't want to trigger the share sheet in this case, we will
-            // start the chooser activitiy directly in ShareReceiver.
+            // Create a share action for the notification. Note, we proxy the call to
+            // ScreenshotActionReceiver because RemoteViews currently forces an activity options
+            // on the PendingIntent being launched, and since we don't want to trigger the share
+            // sheet in this case, we start the chooser activity directly in
+            // ScreenshotActionReceiver.
             PendingIntent shareAction = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.ShareReceiver.class)
+                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
                             .putExtra(SHARING_INTENT, sharingIntent),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
@@ -306,15 +307,19 @@
                     r.getString(com.android.internal.R.string.share), shareAction);
             mNotificationBuilder.addAction(shareActionBuilder.build());
 
-            // Create a delete action for the notification
-            PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0,
-                    new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
-                            .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-            Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
-                    R.drawable.ic_screenshot_delete,
-                    r.getString(com.android.internal.R.string.delete), deleteAction);
-            mNotificationBuilder.addAction(deleteActionBuilder.build());
+            Intent editIntent = new Intent(Intent.ACTION_EDIT);
+            editIntent.setType("image/png");
+            editIntent.putExtra(Intent.EXTRA_STREAM, uri);
+
+            // Create a edit action for the notification the same way.
+            PendingIntent editAction = PendingIntent.getBroadcast(context, 1,
+                    new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class)
+                            .putExtra(SHARING_INTENT, editIntent),
+                    PendingIntent.FLAG_CANCEL_CURRENT);
+            Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_edit,
+                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);
+            mNotificationBuilder.addAction(editActionBuilder.build());
 
             mParams.imageUri = uri;
             mParams.image = null;
@@ -879,9 +884,9 @@
     }
 
     /**
-     * Receiver to proxy the share intent.
+     * Receiver to proxy the share or edit intent.
      */
-    public static class ShareReceiver extends BroadcastReceiver {
+    public static class ScreenshotActionReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             try {
@@ -903,7 +908,7 @@
     }
 
     /**
-     * Removes the notification for a screenshot after a share target is chosen.
+     * Removes the notification for a screenshot after a share or edit target is chosen.
      */
     public static class TargetChosenReceiver extends BroadcastReceiver {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 9b123cb..7284ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -34,6 +34,7 @@
     private View.OnClickListener mClickListener;
     private View.OnTouchListener mTouchListener;
     private View.OnLongClickListener mLongClickListener;
+    private View.OnHoverListener mOnHoverListener;
     private Boolean mLongClickable;
     private Integer mAlpha;
     private Float mDarkIntensity;
@@ -56,6 +57,7 @@
         view.setOnClickListener(mClickListener);
         view.setOnTouchListener(mTouchListener);
         view.setOnLongClickListener(mLongClickListener);
+        view.setOnHoverListener(mOnHoverListener);
         if (mLongClickable != null) {
             view.setLongClickable(mLongClickable);
         }
@@ -174,6 +176,14 @@
         }
     }
 
+    public void setOnHoverListener(View.OnHoverListener hoverListener) {
+        mOnHoverListener = hoverListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnHoverListener(mOnHoverListener);
+        }
+    }
+
     public void setClickable(boolean clickable) {
         abortCurrentGesture();
         final int N = mViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 4225843..368b36b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -26,7 +26,6 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -111,7 +110,7 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
-    private static final int ROTATE_SUGGESTION_TIMEOUT_MS = 4000;
+    private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
 
     protected NavigationBarView mNavigationBarView = null;
     protected AssistManager mAssistManager;
@@ -120,6 +119,7 @@
 
     private int mNavigationIconHints = 0;
     private int mNavigationBarMode;
+    private boolean mAccessibilityFeedbackEnabled;
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
@@ -143,6 +143,7 @@
     public boolean mHomeBlockedThisTouch;
 
     private int mLastRotationSuggestion;
+    private boolean mHoveringRotationSuggestion;
     private RotationLockController mRotationLockController;
     private TaskStackListenerImpl mTaskStackListener;
 
@@ -345,40 +346,67 @@
             return;
         }
 
-        Handler h = getView().getHandler();
         if (rotation == mWindowManager.getDefaultDisplay().getRotation()) {
             // Use this as a signal to remove any current suggestions
-            h.removeCallbacks(mRemoveRotationProposal);
+            getView().getHandler().removeCallbacks(mRemoveRotationProposal);
             setRotateSuggestionButtonState(false);
         } else {
             mLastRotationSuggestion = rotation; // Remember rotation for click
             setRotateSuggestionButtonState(true);
-            h.removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
-            h.postDelayed(mRemoveRotationProposal,
-                    ROTATE_SUGGESTION_TIMEOUT_MS); // Schedule timeout
+            rescheduleRotationTimeout(false);
         }
     }
 
+    private void rescheduleRotationTimeout(final boolean reasonHover) {
+        // May be called due to a new rotation proposal or a change in hover state
+        if (reasonHover) {
+            // Don't reschedule if a hide animator is running
+            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+                return;
+            }
+            // Don't reschedule if not visible
+            if (mNavigationBarView.getRotateSuggestionButton().getVisibility() != View.VISIBLE) {
+                return;
+            }
+        }
+
+        Handler h = getView().getHandler();
+        h.removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
+        h.postDelayed(mRemoveRotationProposal,
+                computeRotationProposalTimeout()); // Schedule timeout
+    }
+
+    private int computeRotationProposalTimeout() {
+        if (mAccessibilityFeedbackEnabled) return 20000;
+        if (mHoveringRotationSuggestion) return 16000;
+        return 6000;
+    }
+
     public void setRotateSuggestionButtonState(final boolean visible) {
         setRotateSuggestionButtonState(visible, false);
     }
 
     public void setRotateSuggestionButtonState(final boolean visible, final boolean skipAnim) {
         ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
-        boolean currentlyVisible = rotBtn.getVisibility() == View.VISIBLE;
+        final boolean currentlyVisible = rotBtn.getVisibility() == View.VISIBLE;
 
         // Rerun a show animation to indicate change but don't rerun a hide animation
         if (!visible && !currentlyVisible) return;
 
-        View currentView = mNavigationBarView.getRotateSuggestionButton().getCurrentView();
+        View currentView = rotBtn.getCurrentView();
         if (currentView == null) return;
 
-        KeyButtonDrawable kbd = mNavigationBarView.getRotateSuggestionButton().getImageDrawable();
+        KeyButtonDrawable kbd = rotBtn.getImageDrawable();
         if (kbd == null) return;
 
-        AnimatedVectorDrawable animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
+        AnimatedVectorDrawable animIcon = null;
+        if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
+            animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
+        }
+
         if (visible) { // Appear and change
             rotBtn.setVisibility(View.VISIBLE);
+            mNavigationBarView.notifyAccessibilitySubtreeChanged();
 
             if (skipAnim) {
                 currentView.setAlpha(1f);
@@ -391,18 +419,22 @@
 
             ObjectAnimator appearFade = ObjectAnimator.ofFloat(currentView, "alpha",
                     0f, 1f);
-            appearFade.setDuration(100);
+            appearFade.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
             appearFade.setInterpolator(Interpolators.LINEAR);
             mRotateShowAnimator = appearFade;
             appearFade.start();
 
-            // Run the rotate icon's animation
-            animIcon.reset();
-            animIcon.start();
+            // Run the rotate icon's animation if it has one
+            if (animIcon != null) {
+                animIcon.reset();
+                animIcon.start();
+            }
+
         } else { // Hide
 
             if (skipAnim) {
                 rotBtn.setVisibility(View.INVISIBLE);
+                mNavigationBarView.notifyAccessibilitySubtreeChanged();
                 return;
             }
 
@@ -413,12 +445,13 @@
 
             ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
                     0f);
-            fadeOut.setDuration(100);
+            fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
             fadeOut.setInterpolator(Interpolators.LINEAR);
             fadeOut.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     rotBtn.setVisibility(View.INVISIBLE);
+                    mNavigationBarView.notifyAccessibilitySubtreeChanged();
                 }
             });
 
@@ -532,6 +565,7 @@
 
         ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
         rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
+        rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -707,6 +741,7 @@
         } catch (Settings.SettingNotFoundException e) {
         }
 
+        boolean feedbackEnabled = false;
         // AccessibilityManagerService resolves services for the current user since the local
         // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
         final List<AccessibilityServiceInfo> services =
@@ -717,8 +752,15 @@
             if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
                 requestingServices++;
             }
+
+            if (info.feedbackType != 0 && info.feedbackType !=
+                    AccessibilityServiceInfo.FEEDBACK_GENERIC) {
+                feedbackEnabled = true;
+            }
         }
 
+        mAccessibilityFeedbackEnabled = feedbackEnabled;
+
         final boolean showAccessibilityButton = requestingServices >= 1;
         final boolean targetSelection = requestingServices >= 2;
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
@@ -728,6 +770,14 @@
         mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
     }
 
+    private boolean onRotateSuggestionHover(View v, MotionEvent event) {
+        final int action = event.getActionMasked();
+        mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
+                || (action == MotionEvent.ACTION_HOVER_MOVE);
+        rescheduleRotationTimeout(true);
+        return false; // Must return false so a11y hover events are dispatched correctly.
+    }
+
     // ----- Methods that StatusBar talks to (should be minimized) -----
 
     public void setLightBarController(LightBarController lightBarController) {
@@ -775,18 +825,18 @@
 
     private final Stub mRotationWatcher = new Stub() {
         @Override
-        public void onRotationChanged(int rotation) throws RemoteException {
-            // If the screen rotation changes while locked, update lock rotation to flow with
-            // new screen rotation and hide any showing suggestions.
-            if (mRotationLockController.isRotationLocked()) {
-                mRotationLockController.setRotationLockedAtAngle(true, rotation);
-                setRotateSuggestionButtonState(false, true);
-            }
-
+        public void onRotationChanged(final int rotation) throws RemoteException {
             // We need this to be scheduled as early as possible to beat the redrawing of
             // window in response to the orientation change.
             Handler h = getView().getHandler();
             Message msg = Message.obtain(h, () -> {
+                // If the screen rotation changes while locked, update lock rotation to flow with
+                // new screen rotation and hide any showing suggestions.
+                if (mRotationLockController.isRotationLocked()) {
+                    mRotationLockController.setRotationLockedAtAngle(true, rotation);
+                    setRotateSuggestionButtonState(false, true);
+                }
+
                 if (mNavigationBarView != null
                         && mNavigationBarView.needsReorient(rotation)) {
                     repositionNavigationBar();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index e8b28f2..b181212 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -62,6 +62,7 @@
     };
     private DarkReceiver mBattery;
     private int mLastOrientation;
+    @Nullable
     private View mCutoutSpace;
     @Nullable
     private DisplayCutout mDisplayCutout;
@@ -284,6 +285,11 @@
     }
 
     private void updateCutoutLocation() {
+        // Not all layouts have a cutout (e.g., Car)
+        if (mCutoutSpace == null) {
+            return;
+        }
+
         if (mDisplayCutout == null || mDisplayCutout.isEmpty()
                     || mLastOrientation != ORIENTATION_PORTRAIT) {
             mCutoutSpace.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 6220fcb..1130b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -32,6 +32,8 @@
 
 public class SettingsButton extends AlphaOptimizedImageButton {
 
+    private static final boolean TUNER_ENABLE_AVAILABLE = false;
+
     private static final long LONG_PRESS_LENGTH = 1000;
     private static final long ACCEL_LENGTH = 750;
     private static final long FULL_SPEED_LENGTH = 375;
@@ -59,7 +61,7 @@
     public boolean onTouchEvent(MotionEvent event) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
-                postDelayed(mLongPressCallback, LONG_PRESS_LENGTH);
+                if (TUNER_ENABLE_AVAILABLE) postDelayed(mLongPressCallback, LONG_PRESS_LENGTH);
                 break;
             case MotionEvent.ACTION_UP:
                 if (mUpToSpeed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 3b15c2b..fcf084b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -276,6 +276,9 @@
         mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
     }
 
+    @Override
+    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {}
+
     private ActuallyCachedState getCachedState(CachedBluetoothDevice device) {
         ActuallyCachedState state = mCachedState.get(device);
         if (state == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 8e584bc..5a4478f 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -58,7 +58,7 @@
 
     private static final String TUNER_VERSION = "sysui_tuner_version";
 
-    private static final int CURRENT_TUNER_VERSION = 1;
+    private static final int CURRENT_TUNER_VERSION = 2;
 
     private final Observer mObserver = new Observer();
     // Map of Uris we listen on to their settings keys.
@@ -116,6 +116,9 @@
                         TextUtils.join(",", iconBlacklist), mCurrentUser);
             }
         }
+        if (oldVersion < 2) {
+            setTunerEnabled(mContext, false);
+        }
         setValue(TUNER_VERSION, newVersion);
     }
 
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 cc3af8c..289dd14 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -114,14 +114,14 @@
     private RefactoredBackupManagerService backupManagerService;
     private final Object mCancelLock = new Object();
 
-    ArrayList<BackupRequest> mQueue;
-    ArrayList<BackupRequest> mOriginalQueue;
-    File mStateDir;
-    @Nullable DataChangedJournal mJournal;
-    BackupState mCurrentState;
-    List<String> mPendingFullBackups;
-    IBackupObserver mObserver;
-    IBackupManagerMonitor mMonitor;
+    private ArrayList<BackupRequest> mQueue;
+    private ArrayList<BackupRequest> mOriginalQueue;
+    private File mStateDir;
+    @Nullable private DataChangedJournal mJournal;
+    private BackupState mCurrentState;
+    private List<String> mPendingFullBackups;
+    private IBackupObserver mObserver;
+    private IBackupManagerMonitor mMonitor;
 
     private final TransportClient mTransportClient;
     private final OnTaskFinishedListener mListener;
@@ -130,18 +130,18 @@
     private volatile int mEphemeralOpToken;
 
     // carried information about the current in-flight operation
-    IBackupAgent mAgentBinder;
-    PackageInfo mCurrentPackage;
-    File mSavedStateName;
-    File mBackupDataName;
-    File mNewStateName;
-    ParcelFileDescriptor mSavedState;
-    ParcelFileDescriptor mBackupData;
-    ParcelFileDescriptor mNewState;
-    int mStatus;
-    boolean mFinished;
-    final boolean mUserInitiated;
-    final boolean mNonIncremental;
+    private IBackupAgent mAgentBinder;
+    private PackageInfo mCurrentPackage;
+    private File mSavedStateName;
+    private File mBackupDataName;
+    private File mNewStateName;
+    private ParcelFileDescriptor mSavedState;
+    private ParcelFileDescriptor mBackupData;
+    private ParcelFileDescriptor mNewState;
+    private int mStatus;
+    private boolean mFinished;
+    private final boolean mUserInitiated;
+    private final boolean mNonIncremental;
 
     private volatile boolean mCancelAll;
 
@@ -241,7 +241,7 @@
 
     // We're starting a backup pass.  Initialize the transport and send
     // the PM metadata blob if we haven't already.
-    void beginBackup() {
+    private void beginBackup() {
         if (DEBUG_BACKUP_TRACE) {
             backupManagerService.clearBackupTrace();
             StringBuilder b = new StringBuilder(256);
@@ -369,7 +369,7 @@
 
     // Transport has been initialized and the PM metadata submitted successfully
     // if that was warranted.  Now we process the single next thing in the queue.
-    void invokeNextAgent() {
+    private void invokeNextAgent() {
         mStatus = BackupTransport.TRANSPORT_OK;
         backupManagerService.addBackupTrace("invoke q=" + mQueue.size());
 
@@ -511,7 +511,7 @@
         }
     }
 
-    void finalizeBackup() {
+    private void finalizeBackup() {
         backupManagerService.addBackupTrace("finishing");
 
         // Mark packages that we didn't backup (because backup was cancelled, etc.) as needing
@@ -617,14 +617,14 @@
     }
 
     // Remove the PM metadata state. This will generate an init on the next pass.
-    void clearMetadata() {
+    private void clearMetadata() {
         final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
         if (pmState.exists()) pmState.delete();
     }
 
     // Invoke an agent's doBackup() and start a timeout message spinning on the main
     // handler in case it doesn't get back to us.
-    int invokeAgentForBackup(String packageName, IBackupAgent agent) {
+    private int invokeAgentForBackup(String packageName, IBackupAgent agent) {
         if (DEBUG) {
             Slog.d(TAG, "invokeAgentForBackup on " + packageName);
         }
@@ -711,7 +711,7 @@
         return BackupTransport.TRANSPORT_OK;
     }
 
-    public void failAgent(IBackupAgent agent, String message) {
+    private void failAgent(IBackupAgent agent, String message) {
         try {
             agent.fail(message);
         } catch (Exception e) {
@@ -1059,7 +1059,7 @@
         }
     }
 
-    void revertAndEndBackup() {
+    private void revertAndEndBackup() {
         if (MORE_DEBUG) {
             Slog.i(TAG, "Reverting backup queue - restaging everything");
         }
@@ -1085,14 +1085,14 @@
 
     }
 
-    void errorCleanup() {
+    private void errorCleanup() {
         mBackupDataName.delete();
         mNewStateName.delete();
         clearAgentState();
     }
 
     // Cleanup common to both success and failure cases
-    void clearAgentState() {
+    private void clearAgentState() {
         try {
             if (mSavedState != null) mSavedState.close();
         } catch (IOException e) {
@@ -1123,7 +1123,7 @@
         }
     }
 
-    void executeNextState(BackupState nextState) {
+    private void executeNextState(BackupState nextState) {
         if (MORE_DEBUG) {
             Slog.i(TAG, " => executing next step on "
                     + this + " nextState=" + nextState);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index a538bde..de113a6 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -26,6 +26,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -89,6 +91,9 @@
 
     private final MyHandler mHandler;
 
+    @VisibleForTesting
+    FeatureFlagsObserver mFlagsObserver;
+
     /**
      * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
      */
@@ -113,14 +118,36 @@
     @GuardedBy("mLock")
     boolean mStarted;
 
+    /**
+     * Only used for small battery use-case.
+     */
     @GuardedBy("mLock")
-    boolean mForceAllAppsStandby;   // True if device is in extreme battery saver mode
+    boolean mIsPluggedIn;
 
     @GuardedBy("mLock")
-    boolean mForcedAppStandbyEnabled;   // True if the forced app standby feature is enabled
+    boolean mBatterySaverEnabled;
 
-    private class FeatureFlagObserver extends ContentObserver {
-        FeatureFlagObserver() {
+    /**
+     * True if the forced app standby is currently enabled
+     */
+    @GuardedBy("mLock")
+    boolean mForceAllAppsStandby;
+
+    /**
+     * True if the forced app standby for small battery devices feature is enabled in settings
+     */
+    @GuardedBy("mLock")
+    boolean mForceAllAppStandbyForSmallBattery;
+
+    /**
+     * True if the forced app standby feature is enabled in settings
+     */
+    @GuardedBy("mLock")
+    boolean mForcedAppStandbyEnabled;
+
+    @VisibleForTesting
+    class FeatureFlagsObserver extends ContentObserver {
+        FeatureFlagsObserver() {
             super(null);
         }
 
@@ -128,6 +155,9 @@
             mContext.getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
                     false, this);
+
+            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
         }
 
         boolean isForcedAppStandbyEnabled() {
@@ -135,20 +165,43 @@
                     Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
         }
 
+        boolean isForcedAppStandbyForSmallBatteryEnabled() {
+            return Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
+        }
+
         @Override
-        public void onChange(boolean selfChange) {
-            final boolean enabled = isForcedAppStandbyEnabled();
-            synchronized (mLock) {
-                if (mForcedAppStandbyEnabled == enabled) {
-                    return;
+        public void onChange(boolean selfChange, Uri uri) {
+            if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
+                final boolean enabled = isForcedAppStandbyEnabled();
+                synchronized (mLock) {
+                    if (mForcedAppStandbyEnabled == enabled) {
+                        return;
+                    }
+                    mForcedAppStandbyEnabled = enabled;
+                    if (DEBUG) {
+                        Slog.d(TAG,"Forced app standby feature flag changed: "
+                                + mForcedAppStandbyEnabled);
+                    }
                 }
-                mForcedAppStandbyEnabled = enabled;
-                if (DEBUG) {
-                    Slog.d(TAG,
-                            "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
+                mHandler.notifyForcedAppStandbyFeatureFlagChanged();
+            } else if (Settings.Global.getUriFor(
+                    Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
+                final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
+                synchronized (mLock) {
+                    if (mForceAllAppStandbyForSmallBattery == enabled) {
+                        return;
+                    }
+                    mForceAllAppStandbyForSmallBattery = enabled;
+                    if (DEBUG) {
+                        Slog.d(TAG, "Forced app standby for small battery feature flag changed: "
+                                + mForceAllAppStandbyForSmallBattery);
+                    }
+                    updateForceAllAppStandbyState();
                 }
+            } else {
+                Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
             }
-            mHandler.notifyFeatureFlagChanged();
         }
     }
 
@@ -289,9 +342,11 @@
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
-            final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
-            flagObserver.register();
-            mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
+            mFlagsObserver = new FeatureFlagsObserver();
+            mFlagsObserver.register();
+            mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
+            mForceAllAppStandbyForSmallBattery =
+                    mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
 
             try {
                 mIActivityManager.registerUidObserver(new UidObserver(),
@@ -306,16 +361,24 @@
 
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_USER_REMOVED);
+            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
             mContext.registerReceiver(new MyReceiver(), filter);
 
             refreshForcedAppStandbyUidPackagesLocked();
 
             mPowerManagerInternal.registerLowPowerModeObserver(
                     ServiceType.FORCE_ALL_APPS_STANDBY,
-                    (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
+                    (state) -> {
+                        synchronized (mLock) {
+                            mBatterySaverEnabled = state.batterySaverEnabled;
+                            updateForceAllAppStandbyState();
+                        }
+                    });
 
-            updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
-                    ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
+            mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
+                    ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
+
+            updateForceAllAppStandbyState();
         }
     }
 
@@ -340,6 +403,11 @@
         return LocalServices.getService(PowerManagerInternal.class);
     }
 
+    @VisibleForTesting
+    boolean isSmallBatteryDevice() {
+        return ActivityManager.isSmallBatteryDevice();
+    }
+
     /**
      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
      */
@@ -369,18 +437,26 @@
         }
     }
 
+    private void updateForceAllAppStandbyState() {
+        synchronized (mLock) {
+            if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
+                toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
+            } else {
+                toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
+            }
+        }
+    }
+
     /**
      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
      */
-    void updateForceAllAppsStandby(boolean enable) {
-        synchronized (mLock) {
-            if (enable == mForceAllAppsStandby) {
-                return;
-            }
-            mForceAllAppsStandby = enable;
-
-            mHandler.notifyForceAllAppsStandbyChanged();
+    private void toggleForceAllAppsStandbyLocked(boolean enable) {
+        if (enable == mForceAllAppsStandby) {
+            return;
         }
+        mForceAllAppsStandby = enable;
+
+        mHandler.notifyForceAllAppsStandbyChanged();
     }
 
     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
@@ -515,6 +591,11 @@
                 if (userId > 0) {
                     mHandler.doUserRemoved(userId);
                 }
+            } else if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+                synchronized (mLock) {
+                    mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
+                }
+                updateForceAllAppStandbyState();
             }
         }
     }
@@ -533,7 +614,7 @@
         private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
         private static final int MSG_FORCE_ALL_CHANGED = 6;
         private static final int MSG_USER_REMOVED = 7;
-        private static final int MSG_FEATURE_FLAG_CHANGED = 8;
+        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
 
         public MyHandler(Looper looper) {
             super(looper);
@@ -563,8 +644,8 @@
             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
         }
 
-        public void notifyFeatureFlagChanged() {
-            obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
+        public void notifyForcedAppStandbyFeatureFlagChanged() {
+            obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
         }
 
         public void doUserRemoved(int userId) {
@@ -618,7 +699,7 @@
                         l.onForceAllAppsStandbyChanged(sender);
                     }
                     return;
-                case MSG_FEATURE_FLAG_CHANGED:
+                case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
                     // Feature flag for forced app standby changed.
                     final boolean unblockAlarms;
                     synchronized (mLock) {
@@ -845,6 +926,18 @@
             pw.println(isForceAllAppsStandbyEnabled());
 
             pw.print(indent);
+            pw.print("Small Battery Device: ");
+            pw.println(isSmallBatteryDevice());
+
+            pw.print(indent);
+            pw.print("Force all apps standby for small battery device: ");
+            pw.println(mForceAllAppStandbyForSmallBattery);
+
+            pw.print(indent);
+            pw.print("Plugged In: ");
+            pw.println(mIsPluggedIn);
+
+            pw.print(indent);
             pw.print("Foreground uids: [");
 
             String sep = "";
@@ -883,6 +976,11 @@
             final long token = proto.start(fieldId);
 
             proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
+            proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
+                    isSmallBatteryDevice());
+            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
+                    mForceAllAppStandbyForSmallBattery);
+            proto.write(ForceAppStandbyTrackerProto.IS_CHARGING, mIsPluggedIn);
 
             for (int i = 0; i < mForegroundUids.size(); i++) {
                 if (mForegroundUids.valueAt(i)) {
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 46a35ec..ef6bc43 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -148,7 +148,7 @@
          * resources.
          *
          * <p>References to the IResource object may be held by other RefcountedResource objects,
-         * and as such, the kernel resources and quota may not be cleaned up.
+         * and as such, the underlying resources and quota may not be cleaned up.
          */
         void invalidate() throws RemoteException;
 
@@ -298,7 +298,12 @@
         }
     }
 
-    /* Very simple counting class that looks much like a counting semaphore */
+    /**
+     * Very simple counting class that looks much like a counting semaphore
+     *
+     * <p>This class is not thread-safe, and expects that that users of this class will ensure
+     * synchronization and thread safety by holding the IpSecService.this instance lock.
+     */
     @VisibleForTesting
     static class ResourceTracker {
         private final int mMax;
@@ -341,26 +346,38 @@
 
     @VisibleForTesting
     static final class UserRecord {
-        /* Type names */
-        public static final String TYPENAME_SPI = "SecurityParameterIndex";
-        public static final String TYPENAME_TRANSFORM = "IpSecTransform";
-        public static final String TYPENAME_ENCAP_SOCKET = "UdpEncapSocket";
-
         /* Maximum number of each type of resource that a single UID may possess */
         public static final int MAX_NUM_ENCAP_SOCKETS = 2;
         public static final int MAX_NUM_TRANSFORMS = 4;
         public static final int MAX_NUM_SPIS = 8;
 
+        /**
+         * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing
+         * and explicit (user) reference management.
+         *
+         * <p>These are stored in separate arrays to improve debuggability and dump output clarity.
+         *
+         * <p>Resources are removed from this array when the user releases their explicit reference
+         * by calling one of the releaseResource() methods.
+         */
         final RefcountedResourceArray<SpiRecord> mSpiRecords =
-                new RefcountedResourceArray<>(TYPENAME_SPI);
-        final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
-
+                new RefcountedResourceArray<>(SpiRecord.class.getSimpleName());
         final RefcountedResourceArray<TransformRecord> mTransformRecords =
-                new RefcountedResourceArray<>(TYPENAME_TRANSFORM);
-        final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
-
+                new RefcountedResourceArray<>(TransformRecord.class.getSimpleName());
         final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords =
-                new RefcountedResourceArray<>(TYPENAME_ENCAP_SOCKET);
+                new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName());
+
+        /**
+         * Trackers for quotas for each of the OwnedResource types.
+         *
+         * <p>These trackers are separate from the resource arrays, since they are incremented and
+         * decremented at different points in time. Specifically, quota is only returned upon final
+         * resource deallocation (after all explicit and implicit references are released). Note
+         * that it is possible that calls to releaseResource() will not return the used quota if
+         * there are other resources that depend on (are parents of) the resource being released.
+         */
+        final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS);
+        final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS);
         final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
 
         void removeSpiRecord(int resourceId) {
@@ -395,11 +412,15 @@
         }
     }
 
+    /**
+     * This class is not thread-safe, and expects that that users of this class will ensure
+     * synchronization and thread safety by holding the IpSecService.this instance lock.
+     */
     @VisibleForTesting
     static final class UserResourceTracker {
         private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
 
-        /** Never-fail getter that populates the list of UIDs as-needed */
+        /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */
         public UserRecord getUserRecord(int uid) {
             checkCallerUid(uid);
 
@@ -428,18 +449,20 @@
     @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker();
 
     /**
-     * The KernelResourceRecord class provides a facility to cleanly and reliably track system
+     * The OwnedResourceRecord class provides a facility to cleanly and reliably track system
      * resources. It relies on a provided resourceId that should uniquely identify the kernel
      * resource. To use this class, the user should implement the invalidate() and
      * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource
-     * tracking arrays and kernel resources, respectively
+     * tracking arrays and kernel resources, respectively.
+     *
+     * <p>This class associates kernel resources with the UID that owns and controls them.
      */
-    private abstract class KernelResourceRecord implements IResource {
+    private abstract class OwnedResourceRecord implements IResource {
         final int pid;
         final int uid;
         protected final int mResourceId;
 
-        KernelResourceRecord(int resourceId) {
+        OwnedResourceRecord(int resourceId) {
             super();
             if (resourceId == INVALID_RESOURCE_ID) {
                 throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID");
@@ -479,8 +502,6 @@
         }
     };
 
-    // TODO: Move this to right after RefcountedResource. With this here, Gerrit was showing many
-    // more things as changed.
     /**
      * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing.
      *
@@ -534,7 +555,12 @@
         }
     }
 
-    private final class TransformRecord extends KernelResourceRecord {
+    /**
+     * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is
+     * created, the SpiRecord that originally tracked the SAs will reliquish the
+     * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag.
+     */
+    private final class TransformRecord extends OwnedResourceRecord {
         private final IpSecConfig mConfig;
         private final SpiRecord mSpi;
         private final EncapSocketRecord mSocket;
@@ -603,7 +629,12 @@
         }
     }
 
-    private final class SpiRecord extends KernelResourceRecord {
+    /**
+     * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the
+     * responsibility for cleaning up underlying resources will be passed to the TransformRecord
+     * object
+     */
+    private final class SpiRecord extends OwnedResourceRecord {
         private final String mSourceAddress;
         private final String mDestinationAddress;
         private int mSpi;
@@ -692,7 +723,14 @@
         }
     }
 
-    private final class EncapSocketRecord extends KernelResourceRecord {
+    /**
+     * Tracks a UDP encap socket, and manages cleanup paths
+     *
+     * <p>While this class does not manage non-kernel resources, race conditions around socket
+     * binding require that the service creates the encap socket, binds it and applies the socket
+     * policy before handing it to a user.
+     */
+    private final class EncapSocketRecord extends OwnedResourceRecord {
         private FileDescriptor mSocket;
         private final int mPort;
 
@@ -1105,16 +1143,14 @@
      * receive data.
      */
     @Override
-    public synchronized IpSecTransformResponse createTransportModeTransform(
-            IpSecConfig c, IBinder binder) throws RemoteException {
+    public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
+            throws RemoteException {
         checkIpSecConfig(c);
-        checkNotNull(binder, "Null Binder passed to createTransportModeTransform");
+        checkNotNull(binder, "Null Binder passed to createTransform");
         final int resourceId = mNextResourceId++;
 
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
-
-        // Avoid resizing by creating a dependency array of min-size 2 (1 UDP encap + 1 SPI)
-        List<RefcountedResource> dependencies = new ArrayList<>(2);
+        List<RefcountedResource> dependencies = new ArrayList<>();
 
         if (!userRecord.mTransformQuotaTracker.isAvailable()) {
             return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
@@ -1186,7 +1222,7 @@
      * other reasons.
      */
     @Override
-    public synchronized void deleteTransportModeTransform(int resourceId) throws RemoteException {
+    public synchronized void deleteTransform(int resourceId) throws RemoteException {
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
         releaseResource(userRecord.mTransformRecords, resourceId);
     }
diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
index 80f8e51..833def3 100644
--- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
+++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
@@ -26,4 +26,7 @@
 
     /** Retrieves handle to a lockscreen credential to be used for Factory Reset Protection. */
     byte[] getFrpCredentialHandle();
+
+    /** Update the OEM unlock enabled bit, bypassing user restriction checks. */
+    void forceOemUnlockEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index c32a2d1..4298140 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -668,5 +668,13 @@
                 IoUtils.closeQuietly(inputStream);
             }
         }
+
+        @Override
+        public void forceOemUnlockEnabled(boolean enabled) {
+            synchronized (mLock) {
+                doSetOemUnlockEnabledLocked(enabled);
+                computeAndWriteDigestLocked();
+            }
+        }
     };
 }
diff --git a/services/core/java/com/android/server/SystemUpdateManagerService.java b/services/core/java/com/android/server/SystemUpdateManagerService.java
new file mode 100644
index 0000000..6c1ffdd
--- /dev/null
+++ b/services/core/java/com/android/server/SystemUpdateManagerService.java
@@ -0,0 +1,255 @@
+/*
+ * 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 static android.os.SystemUpdateManager.KEY_STATUS;
+import static android.os.SystemUpdateManager.STATUS_IDLE;
+import static android.os.SystemUpdateManager.STATUS_UNKNOWN;
+
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ISystemUpdateManager;
+import android.os.PersistableBundle;
+import android.os.SystemUpdateManager;
+import android.provider.Settings;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class SystemUpdateManagerService extends ISystemUpdateManager.Stub {
+
+    private static final String TAG = "SystemUpdateManagerService";
+
+    private static final int UID_UNKNOWN = -1;
+
+    private static final String INFO_FILE = "system-update-info.xml";
+    private static final int INFO_FILE_VERSION = 0;
+    private static final String TAG_INFO = "info";
+    private static final String KEY_VERSION = "version";
+    private static final String KEY_UID = "uid";
+    private static final String KEY_BOOT_COUNT = "boot-count";
+    private static final String KEY_INFO_BUNDLE = "info-bundle";
+
+    private final Context mContext;
+    private final AtomicFile mFile;
+    private final Object mLock = new Object();
+    private int mLastUid = UID_UNKNOWN;
+    private int mLastStatus = STATUS_UNKNOWN;
+
+    public SystemUpdateManagerService(Context context) {
+        mContext = context;
+        mFile = new AtomicFile(new File(Environment.getDataSystemDirectory(), INFO_FILE));
+
+        // Populate mLastUid and mLastStatus.
+        synchronized (mLock) {
+            loadSystemUpdateInfoLocked();
+        }
+    }
+
+    @Override
+    public void updateSystemUpdateInfo(PersistableBundle infoBundle) {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.RECOVERY, TAG);
+
+        int status = infoBundle.getInt(KEY_STATUS, STATUS_UNKNOWN);
+        if (status == STATUS_UNKNOWN) {
+            Slog.w(TAG, "Invalid status info. Ignored");
+            return;
+        }
+
+        // There could be multiple updater apps running on a device. But only one at most should
+        // be active (i.e. with a pending update), with the rest reporting idle status. We will
+        // only accept the reported status if any of the following conditions holds:
+        //   a) none has been reported before;
+        //   b) the current on-file status was last reported by the same caller;
+        //   c) an active update is being reported.
+        int uid = Binder.getCallingUid();
+        if (mLastUid == UID_UNKNOWN || mLastUid == uid || status != STATUS_IDLE) {
+            synchronized (mLock) {
+                saveSystemUpdateInfoLocked(infoBundle, uid);
+            }
+        } else {
+            Slog.i(TAG, "Inactive updater reporting IDLE status. Ignored");
+        }
+    }
+
+    @Override
+    public Bundle retrieveSystemUpdateInfo() {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_SYSTEM_UPDATE_INFO)
+                == PackageManager.PERMISSION_DENIED
+                && mContext.checkCallingOrSelfPermission(Manifest.permission.RECOVERY)
+                == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException("Can't read system update info. Requiring "
+                    + "READ_SYSTEM_UPDATE_INFO or RECOVERY permission.");
+        }
+
+        synchronized (mLock) {
+            return loadSystemUpdateInfoLocked();
+        }
+    }
+
+    // Reads and validates the info file. Returns the loaded info bundle on success; or a default
+    // info bundle with UNKNOWN status.
+    private Bundle loadSystemUpdateInfoLocked() {
+        PersistableBundle loadedBundle = null;
+        try (FileInputStream fis = mFile.openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(fis, StandardCharsets.UTF_8.name());
+            loadedBundle = readInfoFileLocked(parser);
+        } catch (FileNotFoundException e) {
+            Slog.i(TAG, "No existing info file " + mFile.getBaseFile());
+        } catch (XmlPullParserException e) {
+            Slog.e(TAG, "Failed to parse the info file:", e);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read the info file:", e);
+        }
+
+        // Validate the loaded bundle.
+        if (loadedBundle == null) {
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        int version = loadedBundle.getInt(KEY_VERSION, -1);
+        if (version == -1) {
+            Slog.w(TAG, "Invalid info file (invalid version). Ignored");
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        int lastUid = loadedBundle.getInt(KEY_UID, -1);
+        if (lastUid == -1) {
+            Slog.w(TAG, "Invalid info file (invalid UID). Ignored");
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        int lastBootCount = loadedBundle.getInt(KEY_BOOT_COUNT, -1);
+        if (lastBootCount == -1 || lastBootCount != getBootCount()) {
+            Slog.w(TAG, "Outdated info file. Ignored");
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        PersistableBundle infoBundle = loadedBundle.getPersistableBundle(KEY_INFO_BUNDLE);
+        if (infoBundle == null) {
+            Slog.w(TAG, "Invalid info file (missing info). Ignored");
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        int lastStatus = infoBundle.getInt(KEY_STATUS, STATUS_UNKNOWN);
+        if (lastStatus == STATUS_UNKNOWN) {
+            Slog.w(TAG, "Invalid info file (invalid status). Ignored");
+            return removeInfoFileAndGetDefaultInfoBundleLocked();
+        }
+
+        // Everything looks good upon reaching this point.
+        mLastStatus = lastStatus;
+        mLastUid = lastUid;
+        return new Bundle(infoBundle);
+    }
+
+    private void saveSystemUpdateInfoLocked(PersistableBundle infoBundle, int uid) {
+        // Wrap the incoming bundle with extra info (e.g. version, uid, boot count). We use nested
+        // PersistableBundle to avoid manually parsing XML attributes when loading the info back.
+        PersistableBundle outBundle = new PersistableBundle();
+        outBundle.putPersistableBundle(KEY_INFO_BUNDLE, infoBundle);
+        outBundle.putInt(KEY_VERSION, INFO_FILE_VERSION);
+        outBundle.putInt(KEY_UID, uid);
+        outBundle.putInt(KEY_BOOT_COUNT, getBootCount());
+
+        // Only update the info on success.
+        if (writeInfoFileLocked(outBundle)) {
+            mLastUid = uid;
+            mLastStatus = infoBundle.getInt(KEY_STATUS);
+        }
+    }
+
+    // Performs I/O work only, without validating the loaded info.
+    @Nullable
+    private PersistableBundle readInfoFileLocked(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != END_DOCUMENT) {
+            if (type == START_TAG && TAG_INFO.equals(parser.getName())) {
+                return PersistableBundle.restoreFromXml(parser);
+            }
+        }
+        return null;
+    }
+
+    private boolean writeInfoFileLocked(PersistableBundle outBundle) {
+        FileOutputStream fos = null;
+        try {
+            fos = mFile.startWrite();
+
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+
+            out.startTag(null, TAG_INFO);
+            outBundle.saveToXml(out);
+            out.endTag(null, TAG_INFO);
+
+            out.endDocument();
+            mFile.finishWrite(fos);
+            return true;
+        } catch (IOException | XmlPullParserException e) {
+            Slog.e(TAG, "Failed to save the info file:", e);
+            if (fos != null) {
+                mFile.failWrite(fos);
+            }
+        }
+        return false;
+    }
+
+    private Bundle removeInfoFileAndGetDefaultInfoBundleLocked() {
+        if (mFile.exists()) {
+            Slog.i(TAG, "Removing info file");
+            mFile.delete();
+        }
+
+        mLastStatus = STATUS_UNKNOWN;
+        mLastUid = UID_UNKNOWN;
+        Bundle infoBundle = new Bundle();
+        infoBundle.putInt(KEY_STATUS, STATUS_UNKNOWN);
+        return infoBundle;
+    }
+
+    private int getBootCount() {
+        return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT, 0);
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index e38148c..db21ef1 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -676,6 +676,15 @@
         }
     }
 
+    public void dumpStacks(PrintWriter pw) {
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            pw.print(mStacks.get(i).mStackId);
+            if (i > 0) {
+                pw.print(",");
+            }
+        }
+    }
+
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c0c684c..254d49b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -27,9 +27,9 @@
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManagerInternal.ASSIST_KEY_CONTENT;
 import static android.app.ActivityManagerInternal.ASSIST_KEY_DATA;
@@ -120,6 +120,7 @@
 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;
@@ -198,6 +199,7 @@
 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;
 
@@ -277,8 +279,8 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PathPermission;
 import android.content.pm.PermissionInfo;
@@ -356,18 +358,18 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.LongSparseArray;
-import android.util.StatsLog;
-import android.util.TimingsTraceLog;
 import android.util.DebugUtils;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.StatsLog;
 import android.util.TimeUtils;
+import android.util.TimingsTraceLog;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 import android.view.Gravity;
@@ -440,6 +442,12 @@
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.PinnedStackWindowController;
 import com.android.server.wm.WindowManagerService;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -479,11 +487,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
@@ -10414,10 +10417,9 @@
 
     @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
-        if (userId != UserHandle.getCallingUserId()) {
-            enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "getTaskDescriptionIcon");
-        }
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "getTaskDescriptionIcon", null);
+
         final File passedIconFile = new File(filePath);
         final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
                 passedIconFile.getName());
@@ -21480,6 +21482,17 @@
     private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
         final Rect newStackBounds = new Rect();
         final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+        // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
+        if (stack == null) {
+            final StringWriter writer = new StringWriter();
+            final PrintWriter printWriter = new PrintWriter(writer);
+            mStackSupervisor.dumpDisplays(printWriter);
+            printWriter.flush();
+
+            Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
+        }
+
         stack.getBoundsForNewConfiguration(newStackBounds);
         mStackSupervisor.resizeStackLocked(
                 stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
@@ -25159,6 +25172,10 @@
         public int getMaxRunningUsers() {
             return mUserController.mMaxRunningUsers;
         }
+
+        public boolean isCallerRecents(int callingUid) {
+            return getRecentTasks().isCallerRecents(callingUid);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8168cba..3d8863e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3752,6 +3752,15 @@
         }
     }
 
+    public void dumpDisplays(PrintWriter pw) {
+        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+            final ActivityDisplay display = mActivityDisplays.valueAt(i);
+            pw.print("[id:" + display.mDisplayId + " stacks:");
+            display.dumpStacks(pw);
+            pw.print("]");
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
                 pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 8910274..26d65bc 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -745,7 +745,7 @@
                     mContext.getContentResolver(),
                     Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
                     0,
-                    UserHandle.USER_CURRENT) != 0;
+                    mService.mUserController.getCurrentUserId()) != 0;
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
             if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1fcaeef..927b72c 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -99,7 +99,7 @@
     // Keep the last WiFi stats so we can compute a delta.
     @GuardedBy("mWorkerLock")
     private WifiActivityEnergyInfo mLastInfo =
-            new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0);
+            new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0, 0);
 
     BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats) {
         mContext = context;
@@ -374,6 +374,7 @@
 
     private WifiActivityEnergyInfo extractDeltaLocked(WifiActivityEnergyInfo latest) {
         final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
+        final long lastScanMs = mLastInfo.mControllerScanTimeMs;
         final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
         final long lastTxMs = mLastInfo.mControllerTxTimeMs;
         final long lastRxMs = mLastInfo.mControllerRxTimeMs;
@@ -388,14 +389,16 @@
         final long txTimeMs = latest.mControllerTxTimeMs - lastTxMs;
         final long rxTimeMs = latest.mControllerRxTimeMs - lastRxMs;
         final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
+        final long scanTimeMs = latest.mControllerScanTimeMs - lastScanMs;
 
-        if (txTimeMs < 0 || rxTimeMs < 0) {
+        if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0) {
             // The stats were reset by the WiFi system (which is why our delta is negative).
             // Returns the unaltered stats.
             delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
             delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
             delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
             delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
+            delta.mControllerScanTimeMs = latest.mControllerScanTimeMs;
             Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
         } else {
             final long totalActiveTimeMs = txTimeMs + rxTimeMs;
@@ -433,6 +436,7 @@
             // These times seem to be the most reliable.
             delta.mControllerTxTimeMs = txTimeMs;
             delta.mControllerRxTimeMs = rxTimeMs;
+            delta.mControllerScanTimeMs = scanTimeMs;
             // WiFi calculates the idle time as a difference from the on time and the various
             // Rx + Tx times. There seems to be some missing time there because this sometimes
             // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 207aaa7..04b49ba 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -40,6 +40,7 @@
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.WifiBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
 import android.os.health.HealthStatsParceler;
 import android.os.health.HealthStatsWriter;
@@ -1455,6 +1456,16 @@
     }
 
     /**
+     * Gets a snapshot of Wifi stats
+     * @hide
+     */
+    public WifiBatteryStats getWifiBatteryStats() {
+        synchronized (mStats) {
+            return mStats.getWifiBatteryStats();
+        }
+    }
+
+    /**
      * Gets a snapshot of Gps stats
      * @hide
      */
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 1a47aa5..5ada484 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1431,7 +1431,13 @@
 
         if (callingUid != 0 && callingUid != SYSTEM_UID) {
             final boolean allow;
-            if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
+            if (mInjector.isCallerRecents(callingUid)
+                    && callingUserId == getCurrentUserId()
+                    && isSameProfileGroup(callingUserId, targetUserId)) {
+                // If the caller is Recents and it is running in the current user, we then allow it
+                // to access its profiles.
+                allow = true;
+            } else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
                     callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
                 // If the caller has this permission, they always pass go.  And collect $200.
                 allow = true;
@@ -2149,5 +2155,9 @@
                 mService.mLockTaskController.clearLockedTasks(reason);
             }
         }
+
+        protected boolean isCallerRecents(int callingUid) {
+            return mService.getRecentTasks().isCallerRecents(callingUid);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index bd1dbf9..fa5fdf5 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -63,6 +63,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -823,6 +824,8 @@
                 jobStatus.enqueueWorkLocked(ActivityManager.getService(), work);
             }
             startTrackingJobLocked(jobStatus, toCancel);
+            StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                    uId, null, jobStatus.getBatteryName(), 2);
 
             // 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/oemlock/OemLockService.java b/services/core/java/com/android/server/oemlock/OemLockService.java
index 2a2ff06..a6200bf 100644
--- a/services/core/java/com/android/server/oemlock/OemLockService.java
+++ b/services/core/java/com/android/server/oemlock/OemLockService.java
@@ -31,10 +31,10 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.service.oemlock.IOemLockService;
-import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
 
 import com.android.server.LocalServices;
+import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.SystemService;
 import com.android.server.pm.UserRestrictionsUtils;
 
@@ -217,13 +217,12 @@
      * is used to erase FRP information on a unlockable device.
      */
     private void setPersistentDataBlockOemUnlockAllowedBit(boolean allowed) {
-        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
-                mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+        final PersistentDataBlockManagerInternal pdbmi
+                = LocalServices.getService(PersistentDataBlockManagerInternal.class);
         // if mOemLock is PersistentDataBlockLock, then the bit should have already been set
-        if (pdbm != null && !(mOemLock instanceof PersistentDataBlockLock)
-                && pdbm.getOemUnlockEnabled() != allowed) {
+        if (pdbmi != null && !(mOemLock instanceof PersistentDataBlockLock)) {
             Slog.i(TAG, "Update OEM Unlock bit in pst partition to " + allowed);
-            pdbm.setOemUnlockEnabled(allowed);
+            pdbmi.forceOemUnlockEnabled(allowed);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index cc448da..a6ff4f7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -344,9 +344,13 @@
         final boolean isSelfUpdatePermissionGranted =
                 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
                         mInstallerUid) == PackageManager.PERMISSION_GRANTED);
+        final boolean isUpdatePermissionGranted =
+                (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
+                        mInstallerUid) == PackageManager.PERMISSION_GRANTED);
+        final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
         final boolean isPermissionGranted = isInstallPermissionGranted
-                || (isSelfUpdatePermissionGranted
-                    && mPm.getPackageUid(mPackageName, 0, userId) == mInstallerUid);
+                || (isUpdatePermissionGranted && targetPackageUid != -1)
+                || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
         final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
         final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
         final boolean forcePermissionPrompt =
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 10b377d..faf6114 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -118,6 +118,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.ResourcesManager;
@@ -992,6 +993,7 @@
     private List<String> mKeepUninstalledPackages;
 
     private UserManagerInternal mUserManagerInternal;
+    private ActivityManagerInternal mActivityManagerInternal;
 
     private DeviceIdleController.LocalService mDeviceIdleController;
 
@@ -4575,6 +4577,14 @@
         return mUserManagerInternal;
     }
 
+    private ActivityManagerInternal getActivityManagerInternal() {
+        if (mActivityManagerInternal == null) {
+            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        }
+        return mActivityManagerInternal;
+    }
+
+
     private DeviceIdleController.LocalService getDeviceIdleController() {
         if (mDeviceIdleController == null) {
             mDeviceIdleController =
@@ -4735,8 +4745,12 @@
             int filterCallingUid, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
-                false /* requireFullPermission */, false /* checkShell */, "get activity info");
+
+        if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
+            mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                    false /* requireFullPermission */, false /* checkShell */, "get activity info");
+        }
+
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
@@ -4758,6 +4772,22 @@
         return null;
     }
 
+    private boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId) {
+        if (!getActivityManagerInternal().isCallerRecents(callingUid)) {
+            return false;
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (ActivityManager.getCurrentUser() != callingUserId) {
+                return false;
+            }
+            return sUserManager.isSameProfileGroup(callingUserId, targetUserId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @Override
     public boolean activitySupportsIntent(ComponentName component, Intent intent,
             String resolvedType) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a33f071..47cd813 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -236,6 +236,8 @@
                     return runHasFeature();
                 case "set-harmful-app-warning":
                     return runSetHarmfulAppWarning();
+                case "get-harmful-app-warning":
+                    return runGetHarmfulAppWarning();
                 default: {
                     String nextArg = getNextArg();
                     if (nextArg == null) {
@@ -2125,6 +2127,31 @@
         return 0;
     }
 
+    private int runGetHarmfulAppWarning() throws RemoteException {
+        int userId = UserHandle.USER_CURRENT;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+
+        userId = translateUserId(userId, false /*allowAll*/, "runGetHarmfulAppWarning");
+
+        final String packageName = getNextArgRequired();
+        final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, userId);
+        if (!TextUtils.isEmpty(warning)) {
+            getOutPrintWriter().println(warning);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
@@ -2684,6 +2711,9 @@
         pw.println("");
         pw.println("  set-harmful-app-warning [--user <USER_ID>] <PACKAGE> [<WARNING>]");
         pw.println("    Mark the app as harmful with the given warning message.");
+        pw.println("");
+        pw.println("  get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
+        pw.println("    Return the harmful app warning message for the given app, if present");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6599fd9..0f394a4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4352,6 +4352,7 @@
             DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
             Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
         final int fl = PolicyControl.getWindowFlags(null, attrs);
+        final int pfl = attrs.privateFlags;
         final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
         final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
         final int displayRotation = displayFrames.mRotation;
@@ -4374,8 +4375,12 @@
             }
         }
 
-        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
-                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+        final boolean layoutInScreenAndInsetDecor =
+                (fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
+                        == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR);
+        final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
+
+        if (layoutInScreenAndInsetDecor && !screenDecor) {
             Rect frame;
             int availRight, availBottom;
             if (canHideNavigationBar() &&
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index 09f6da9..5811714 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -21,6 +21,8 @@
 import android.content.ContentProviderClient;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -49,11 +51,13 @@
     @GuardedBy("mLock")
     private final ArraySet<String> mPinnedPkgs = new ArraySet<>();
     @GuardedBy("mLock")
-    private final ArraySet<ISliceListener> mListeners = new ArraySet<>();
+    private final ArrayMap<IBinder, ISliceListener> mListeners = new ArrayMap<>();
     @GuardedBy("mLock")
     private SliceSpec[] mSupportedSpecs = null;
     @GuardedBy("mLock")
-    private final ArrayMap<ISliceListener, String> mPkgMap = new ArrayMap<>();
+    private final ArrayMap<IBinder, String> mPkgMap = new ArrayMap<>();
+
+    private final DeathRecipient mDeathRecipient = this::handleRecheckListeners;
 
     public PinnedSliceState(SliceManagerService service, Uri uri) {
         mService = service;
@@ -107,20 +111,27 @@
 
     public void addSliceListener(ISliceListener listener, String pkg, SliceSpec[] specs) {
         synchronized (mLock) {
-            if (mListeners.add(listener) && mListeners.size() == 1) {
+            if (mListeners.size() == 0) {
                 mService.listen(mUri);
             }
-            mPkgMap.put(listener, pkg);
+            try {
+                listener.asBinder().linkToDeath(mDeathRecipient, 0);
+            } catch (RemoteException e) {
+            }
+            mListeners.put(listener.asBinder(), listener);
+            mPkgMap.put(listener.asBinder(), pkg);
             mergeSpecs(specs);
         }
     }
 
     public boolean removeSliceListener(ISliceListener listener) {
         synchronized (mLock) {
-            mPkgMap.remove(listener);
-            if (mListeners.remove(listener) && mListeners.size() == 0) {
+            listener.asBinder().unlinkToDeath(mDeathRecipient, 0);
+            mPkgMap.remove(listener.asBinder());
+            if (mListeners.containsKey(listener.asBinder()) && mListeners.size() == 1) {
                 mService.unlisten(mUri);
             }
+            mListeners.remove(listener.asBinder());
         }
         return !isPinned();
     }
@@ -159,25 +170,44 @@
         return client;
     }
 
+    private void handleRecheckListeners() {
+        if (!isPinned()) return;
+        synchronized (mLock) {
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                ISliceListener l = mListeners.valueAt(i);
+                if (!l.asBinder().isBinderAlive()) {
+                    mListeners.removeAt(i);
+                }
+            }
+            if (!isPinned()) {
+                // All the listeners died, remove from pinned state.
+                mService.removePinnedSlice(mUri);
+            }
+        }
+    }
+
     private void handleBind() {
         Slice cachedSlice = doBind(null);
         synchronized (mLock) {
-            mListeners.removeIf(l -> {
+            if (!isPinned()) return;
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                ISliceListener l = mListeners.valueAt(i);
                 Slice s = cachedSlice;
                 if (s == null || s.hasHint(Slice.HINT_CALLER_NEEDED)) {
                     s = doBind(mPkgMap.get(l));
                 }
                 if (s == null) {
-                    return true;
+                    mListeners.removeAt(i);
+                    continue;
                 }
                 try {
                     l.onSliceUpdated(s);
-                    return false;
                 } catch (RemoteException e) {
                     Log.e(TAG, "Unable to notify slice " + mUri, e);
-                    return true;
+                    mListeners.removeAt(i);
+                    continue;
                 }
-            });
+            }
             if (!isPinned()) {
                 // All the listeners died, remove from pinned state.
                 mService.removePinnedSlice(mUri);
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ca7632c..c191580 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -91,9 +91,9 @@
 
         mObserver = new ContentObserver(mHandler) {
             @Override
-            public void onChange(boolean selfChange, Uri uri) {
+            public void onChange(boolean selfChange, Uri uri, int userId) {
                 try {
-                    getPinnedSlice(uri).onChange();
+                    getPinnedSlice(maybeAddUserId(uri, userId)).onChange();
                 } catch (IllegalStateException e) {
                     Log.e(TAG, "Received change for unpinned slice " + uri, e);
                 }
@@ -204,7 +204,7 @@
     }
 
     ///  ----- internal code -----
-    void removePinnedSlice(Uri uri) {
+    protected void removePinnedSlice(Uri uri) {
         synchronized (mLock) {
             mPinnedSlicesByUri.remove(uri).destroy();
         }
@@ -233,7 +233,7 @@
     }
 
     @VisibleForTesting
-    PinnedSliceState createPinnedSlice(Uri uri) {
+    protected PinnedSliceState createPinnedSlice(Uri uri) {
         return new PinnedSliceState(this, uri);
     }
 
@@ -352,7 +352,7 @@
     // Based on getDefaultHome in ShortcutService.
     // TODO: Unify if possible
     @VisibleForTesting
-    String getDefaultHome(int userId) {
+    protected String getDefaultHome(int userId) {
         final long token = Binder.clearCallingIdentity();
         try {
             final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 688b4ff..8515dcb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -99,11 +99,15 @@
     }
 
     private RemoteAnimationTarget[] createAnimations() {
-        final RemoteAnimationTarget[] result = new RemoteAnimationTarget[mPendingAnimations.size()];
+        final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
-            result[i] = mPendingAnimations.get(i).createRemoteAppAnimation();
+            final RemoteAnimationTarget target =
+                    mPendingAnimations.get(i).createRemoteAppAnimation();
+            if (target != null) {
+                targets.add(target);
+            }
         }
-        return result;
+        return targets.toArray(new RemoteAnimationTarget[targets.size()]);
     }
 
     private void onAnimationFinished() {
@@ -145,9 +149,17 @@
         }
 
         RemoteAnimationTarget createRemoteAppAnimation() {
-            return new RemoteAnimationTarget(mAppWindowToken.getTask().mTaskId, getMode(),
+            final Task task = mAppWindowToken.getTask();
+            final WindowState mainWindow = mAppWindowToken.findMainWindow();
+            if (task == null) {
+                return null;
+            }
+            if (mainWindow == null) {
+                return null;
+            }
+            return new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
-                    mAppWindowToken.findMainWindow().mWinAnimator.mLastClipRect,
+                    mainWindow.mWinAnimator.mLastClipRect,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds);
         }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e660c50..94a356e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1172,6 +1172,15 @@
             }
             traceEnd();
 
+            traceBeginAndSlog("StartSystemUpdateManagerService");
+            try {
+                ServiceManager.addService(Context.SYSTEM_UPDATE_SERVICE,
+                        new SystemUpdateManagerService(context));
+            } catch (Throwable e) {
+                reportWtf("starting SystemUpdateManagerService", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartUpdateLockService");
             try {
                 ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index 429dd8f..de54e52 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager.ServiceType;
@@ -51,6 +52,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
@@ -105,6 +107,9 @@
         PowerManagerInternal injectPowerManagerInternal() {
             return mMockPowerManagerInternal;
         }
+
+        @Override
+        boolean isSmallBatteryDevice() { return mIsSmallBatteryDevice; };
     }
 
     private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
@@ -144,6 +149,7 @@
     private FakeSettingsProvider mFakeSettingsProvider;
 
     private boolean mPowerSaveMode;
+    private boolean mIsSmallBatteryDevice;
 
     private final ArraySet<Pair<Integer, String>> mRestrictedPackages = new ArraySet();
 
@@ -232,6 +238,7 @@
         assertNotNull(mAppOpsCallback);
         assertNotNull(mPowerSaveObserver);
         assertNotNull(mReceiver);
+        assertNotNull(instance.mFlagsObserver);
     }
 
     private void setAppOps(int uid, String packageName, boolean restrict) throws RemoteException {
@@ -852,6 +859,56 @@
         assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
     }
 
+    @Test
+    public void testSmallBatteryAndPluggedIn() throws Exception {
+        // This is a small battery device
+        mIsSmallBatteryDevice = true;
+
+        final ForceAppStandbyTrackerTestable instance = newInstance();
+        callStart(instance);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        // Setting/experiment for all app standby for small battery is enabled
+        Global.putInt(mMockContentResolver, Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 1);
+        instance.mFlagsObserver.onChange(true,
+                Global.getUriFor(Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery is plugged in, force app standby is disabled
+        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+        mReceiver.onReceive(mMockContext, intent);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery stops plugged in, force app standby is enabled
+        mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+    }
+
+    @Test
+    public void testNotSmallBatteryAndPluggedIn() throws Exception {
+        // Not a small battery device, so plugged in status should not affect forced app standby
+        mIsSmallBatteryDevice = false;
+
+        final ForceAppStandbyTrackerTestable instance = newInstance();
+        callStart(instance);
+        assertFalse(instance.isForceAllAppsStandbyEnabled());
+
+        mPowerSaveMode = true;
+        mPowerSaveObserver.accept(getPowerSaveState());
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery is plugged in, force app standby is unaffected
+        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_USB);
+        mReceiver.onReceive(mMockContext, intent);
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+
+        // When battery stops plugged in, force app standby is unaffected
+        mReceiver.onReceive(mMockContext, new Intent(Intent.ACTION_BATTERY_CHANGED));
+        assertTrue(instance.isForceAllAppsStandbyEnabled());
+    }
+
     static int[] array(int... appIds) {
         Arrays.sort(appIds);
         return appIds;
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java
index a31b46c..999dce5 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/PrivacyUtilsTests.java
@@ -77,9 +77,9 @@
         assertEquals(6, result.size());
         assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB48"));
         assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB49"));
-        assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47"));
-        assertTrue(result.get("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45"));
-        assertFalse(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44"));
+        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB47"));
+        assertFalse(result.get("E86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB45"));
+        assertTrue(result.get("C86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB44"));
         assertTrue(result.get("B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43"));
     }
 
@@ -87,7 +87,7 @@
     public void testPrivacyUtils_createInsecureDPEncoderForTest() throws Exception {
         DifferentialPrivacyEncoder encoder = PrivacyUtils.createInsecureDPEncoderForTest("foo");
         assertEquals(
-                "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.400, ProbabilityP: 0.250, "
+                "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.469, ProbabilityP: 0.280, "
                         + "ProbabilityQ: 1.000",
                 encoder.getConfig().toString());
         assertTrue(encoder.isInsecureEncoderForTest());
@@ -97,7 +97,7 @@
     public void testPrivacyUtils_createSecureDPEncoderTest() throws Exception {
         DifferentialPrivacyEncoder encoder = PrivacyUtils.createSecureDPEncoder(TEST_SECRET, "foo");
         assertEquals(
-                "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.400, ProbabilityP: 0.250, "
+                "EncoderId: watchlist_encoder:foo, ProbabilityF: 0.469, ProbabilityP: 0.280, "
                         + "ProbabilityQ: 1.000",
                 encoder.getConfig().toString());
         assertFalse(encoder.isInsecureEncoderForTest());
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
index b6c370e..293f9af 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
@@ -27,14 +27,19 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static org.hamcrest.Matchers.equalTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout;
 import android.view.WindowManager;
 
 import org.junit.Before;
@@ -262,4 +267,23 @@
         assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
     }
 
+    @Test
+    public void insetHint_screenDecorWindow() {
+        addDisplayCutout();
+        mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
+
+        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+        final Rect content = new Rect();
+        final Rect stable = new Rect();
+        final Rect outsets = new Rect();
+        final DisplayCutout.ParcelableWrapper cutout = new DisplayCutout.ParcelableWrapper();
+        mPolicy.getInsetHintLw(mAppWindow.attrs, null /* taskBounds */, mFrames, content,
+                stable, outsets, cutout);
+
+        assertThat(content, equalTo(new Rect()));
+        assertThat(stable, equalTo(new Rect()));
+        assertThat(outsets, equalTo(new Rect()));
+        assertThat(cutout.get(), equalTo(DisplayCutout.NO_CUTOUT));
+    }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index aada682..d3bb804 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -6,6 +6,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -21,8 +22,11 @@
 import android.content.ContentProvider;
 import android.content.IContentProvider;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -34,6 +38,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -147,6 +152,7 @@
     @Test
     public void testListenerPin() {
         ISliceListener listener = mock(ISliceListener.class);
+        when(listener.asBinder()).thenReturn(new Binder());
         assertFalse(mPinnedSliceManager.isPinned());
 
         mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS);
@@ -159,7 +165,11 @@
     @Test
     public void testMultiListenerPin() {
         ISliceListener listener = mock(ISliceListener.class);
+        Binder value = new Binder();
+        when(listener.asBinder()).thenReturn(value);
         ISliceListener listener2 = mock(ISliceListener.class);
+        Binder value2 = new Binder();
+        when(listener2.asBinder()).thenReturn(value2);
         assertFalse(mPinnedSliceManager.isPinned());
 
         mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS);
@@ -172,8 +182,30 @@
     }
 
     @Test
+    public void testListenerDeath() throws RemoteException {
+        ISliceListener listener = mock(ISliceListener.class);
+        IBinder binder = mock(IBinder.class);
+        when(binder.isBinderAlive()).thenReturn(true);
+        when(listener.asBinder()).thenReturn(binder);
+        assertFalse(mPinnedSliceManager.isPinned());
+
+        mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS);
+        assertTrue(mPinnedSliceManager.isPinned());
+
+        ArgumentCaptor<DeathRecipient> arg = ArgumentCaptor.forClass(DeathRecipient.class);
+        verify(binder).linkToDeath(arg.capture(), anyInt());
+
+        when(binder.isBinderAlive()).thenReturn(false);
+        arg.getValue().binderDied();
+
+        verify(mSliceService).removePinnedSlice(eq(TEST_URI));
+        assertFalse(mPinnedSliceManager.isPinned());
+    }
+
+    @Test
     public void testPkgListenerPin() {
         ISliceListener listener = mock(ISliceListener.class);
+        when(listener.asBinder()).thenReturn(new Binder());
         assertFalse(mPinnedSliceManager.isPinned());
 
         mPinnedSliceManager.addSliceListener(listener, mContext.getPackageName(), FIRST_SPECS);
@@ -191,6 +223,7 @@
         clearInvocations(mIContentProvider);
 
         ISliceListener listener = mock(ISliceListener.class);
+        when(listener.asBinder()).thenReturn(new Binder());
         Slice s = new Slice.Builder(TEST_URI).build();
         Bundle b = new Bundle();
         b.putParcelable(SliceProvider.EXTRA_SLICE, s);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c7d6b3..d17bdc8 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -419,7 +419,6 @@
         /**
          * Indicates the call used Assisted Dialing.
          * See also {@link Connection#PROPERTY_ASSISTED_DIALING_USED}
-         * @hide
          */
         public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index aaef8d3..7522443 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -35,6 +35,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.ArraySet;
@@ -401,7 +402,6 @@
 
     /**
      * Set by the framework to indicate that a connection is using assisted dialing.
-     * @hide
      */
     public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
 
@@ -2538,6 +2538,19 @@
     }
 
     /**
+     * Adds a parcelable extra to this {@code Connection}.
+     *
+     * @param key The extra key.
+     * @param value The value.
+     * @hide
+     */
+    public final void putExtra(@NonNull String key, @NonNull Parcelable value) {
+        Bundle newExtras = new Bundle();
+        newExtras.putParcelable(key, value);
+        putExtras(newExtras);
+    }
+
+    /**
      * Removes extras from this {@code Connection}.
      *
      * @param keys The keys of the extras to remove.
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index d292db3..91d5da3 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -602,12 +602,17 @@
     /**
      * The boolean indicated by this extra controls whether or not a call is eligible to undergo
      * assisted dialing. This extra is stored under {@link #EXTRA_OUTGOING_CALL_EXTRAS}.
-     * @hide
      */
     public static final String EXTRA_USE_ASSISTED_DIALING =
             "android.telecom.extra.USE_ASSISTED_DIALING";
 
     /**
+     * The bundle indicated by this extra store information related to the assisted dialing action.
+     */
+    public static final String EXTRA_ASSISTED_DIALING_TRANSFORMATION_INFO =
+            "android.telecom.extra.ASSISTED_DIALING_TRANSFORMATION_INFO";
+
+    /**
      * The following 4 constants define how properties such as phone numbers and names are
      * displayed to the user.
      */
diff --git a/telecomm/java/android/telecom/TransformationInfo.java b/telecomm/java/android/telecom/TransformationInfo.java
new file mode 100755
index 0000000..3e848c6
--- /dev/null
+++ b/telecomm/java/android/telecom/TransformationInfo.java
@@ -0,0 +1,127 @@
+/*
+ * 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 android.telecom;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * A container class to hold information related to the Assisted Dialing operation. All member
+ * variables must be set when constructing a new instance of this class.
+ */
+public final class TransformationInfo implements Parcelable {
+    private String mOriginalNumber;
+    private String mTransformedNumber;
+    private String mUserHomeCountryCode;
+    private String mUserRoamingCountryCode;
+    private int mTransformedNumberCountryCallingCode;
+
+    public TransformationInfo(String originalNumber,
+                              String transformedNumber,
+                              String userHomeCountryCode,
+                              String userRoamingCountryCode,
+                              int transformedNumberCountryCallingCode) {
+        String missing = "";
+        if (originalNumber == null) {
+            missing += " mOriginalNumber";
+        }
+        if (transformedNumber == null) {
+            missing += " mTransformedNumber";
+        }
+        if (userHomeCountryCode == null) {
+            missing += " mUserHomeCountryCode";
+        }
+        if (userRoamingCountryCode == null) {
+            missing += " mUserRoamingCountryCode";
+        }
+
+        if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+        }
+        this.mOriginalNumber = originalNumber;
+        this.mTransformedNumber = transformedNumber;
+        this.mUserHomeCountryCode = userHomeCountryCode;
+        this.mUserRoamingCountryCode = userRoamingCountryCode;
+        this.mTransformedNumberCountryCallingCode = transformedNumberCountryCallingCode;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mOriginalNumber);
+        out.writeString(mTransformedNumber);
+        out.writeString(mUserHomeCountryCode);
+        out.writeString(mUserRoamingCountryCode);
+        out.writeInt(mTransformedNumberCountryCallingCode);
+    }
+
+    public static final Parcelable.Creator<TransformationInfo> CREATOR
+            = new Parcelable.Creator<TransformationInfo>() {
+        public TransformationInfo createFromParcel(Parcel in) {
+            return new TransformationInfo(in);
+        }
+
+        public TransformationInfo[] newArray(int size) {
+            return new TransformationInfo[size];
+        }
+    };
+
+    private TransformationInfo(Parcel in) {
+        mOriginalNumber = in.readString();
+        mTransformedNumber = in.readString();
+        mUserHomeCountryCode = in.readString();
+        mUserRoamingCountryCode = in.readString();
+        mTransformedNumberCountryCallingCode = in.readInt();
+    }
+
+    /**
+     * The original number that underwent Assisted Dialing.
+     */
+    public String getOriginalNumber() {
+        return mOriginalNumber;
+    }
+
+    /**
+     * The number after it underwent Assisted Dialing.
+     */
+    public String getTransformedNumber() {
+        return mTransformedNumber;
+    }
+
+    /**
+     * The user's home country code that was used when attempting to transform the number.
+     */
+    public String getUserHomeCountryCode() {
+        return mUserHomeCountryCode;
+    }
+
+    /**
+     * The users's roaming country code that was used when attempting to transform the number.
+     */
+    public String getUserRoamingCountryCode() {
+        return mUserRoamingCountryCode;
+    }
+
+    /**
+     * The country calling code that was used in the transformation.
+     */
+    public int getTransformedNumberCountryCallingCode() {
+        return mTransformedNumberCountryCallingCode;
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ce0b551..649d478 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1644,6 +1644,13 @@
             "roaming_operator_string_array";
 
     /**
+     * Controls whether Assisted Dialing is enabled and the preference is shown. This feature
+     * transforms numbers when the user is roaming.
+     */
+    public static final String KEY_ASSISTED_DIALING_ENABLED_BOOL =
+            "assisted_dialing_enabled_bool";
+
+    /**
      * URL from which the proto containing the public key of the Carrier used for
      * IMSI encryption will be downloaded.
      * @hide
@@ -2040,6 +2047,7 @@
                 false);
         sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_ASSISTED_DIALING_ENABLED_BOOL, true);
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index de9e691..17f809d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1024,8 +1024,8 @@
 
     /**
      * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
-     * the updated carrier id {@link TelephonyManager#getSubscriptionCarrierId()} of the current
-     * subscription.
+     * the updated carrier id {@link TelephonyManager#getAndroidCarrierIdForSubscription()} of
+     * the current subscription.
      * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
      * the carrier cannot be identified.
      */
@@ -6900,14 +6900,19 @@
 
     /**
      * Returns carrier id of the current subscription.
-     * <p>To recognize a carrier (including MVNO) as a first class identity, assign each carrier
-     * with a canonical integer a.k.a carrier id.
+     * <p>To recognize a carrier (including MVNO) as a first-class identity, Android assigns each
+     * carrier with a canonical integer a.k.a. android carrier id. The Android carrier ID is an
+     * Android platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+     *
+     * <p>Apps which have carrier-specific configurations or business logic can use the carrier id
+     * as an Android platform-wide identifier for carriers.
      *
      * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
      * subscription is unavailable or the carrier cannot be identified.
      * @throws IllegalStateException if telephony service is unavailable.
      */
-    public int getSubscriptionCarrierId() {
+    public int getAndroidCarrierIdForSubscription() {
         try {
             ITelephony service = getITelephony();
             return service.getSubscriptionCarrierId(getSubId());
@@ -6923,17 +6928,18 @@
 
     /**
      * Returns carrier name of the current subscription.
-     * <p>Carrier name is a user-facing name of carrier id {@link #getSubscriptionCarrierId()},
-     * usually the brand name of the subsidiary (e.g. T-Mobile). Each carrier could configure
-     * multiple {@link #getSimOperatorName() SPN} but should have a single carrier name.
-     * Carrier name is not a canonical identity, use {@link #getSubscriptionCarrierId()} instead.
+     * <p>Carrier name is a user-facing name of carrier id
+     * {@link #getAndroidCarrierIdForSubscription()}, usually the brand name of the subsidiary
+     * (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but
+     * should have a single carrier name. Carrier name is not a canonical identity,
+     * use {@link #getAndroidCarrierIdForSubscription()} instead.
      * <p>The returned carrier name is unlocalized.
      *
      * @return Carrier name of the current subscription. Return {@code null} if the subscription is
      * unavailable or the carrier cannot be identified.
      * @throws IllegalStateException if telephony service is unavailable.
      */
-    public String getSubscriptionCarrierName() {
+    public CharSequence getAndroidCarrierNameForSubscription() {
         try {
             ITelephony service = getITelephony();
             return service.getSubscriptionCarrierName(getSubId());
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 2ab8d4f..73a05af 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -21,22 +21,23 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.hardware.radio.V1_0.ApnTypes;
-import android.net.NetworkUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Telephony;
 import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.net.MalformedURLException;
-import java.net.UnknownHostException;
-import java.net.URL;
 import java.net.InetAddress;
-import java.util.Arrays;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -67,8 +68,8 @@
     private final int mMtu;
 
     private final boolean mCarrierEnabled;
-    private final int mBearer;
-    private final int mBearerBitmask;
+
+    private final int mNetworkTypeBitmask;
 
     private final int mProfileId;
 
@@ -103,34 +104,6 @@
     }
 
     /**
-     * Radio Access Technology info.
-     * To check what values can hold, refer to ServiceState.java.
-     * This should be spread to other technologies,
-     * but currently only used for LTE(14) and EHRPD(13).
-     *
-     * @return the bearer info of the APN
-     * @hide
-     */
-    public int getBearer() {
-        return mBearer;
-    }
-
-    /**
-     * Returns the radio access technology bitmask for this APN.
-     *
-     * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio
-     * technologies in ServiceState.
-     * This should be spread to other technologies,
-     * but currently only used for LTE(14) and EHRPD(13).
-     *
-     * @return the radio access technology bitmask
-     * @hide
-     */
-    public int getBearerBitmask() {
-        return mBearerBitmask;
-    }
-
-    /**
      * Returns the profile id to which the APN saved in modem.
      *
      * @return the profile id of the APN
@@ -411,6 +384,20 @@
         return mCarrierEnabled;
     }
 
+    /**
+     * Returns a bitmask describing the Radio Technologies(Network Types) which this APN may use.
+     *
+     * NetworkType bitmask is calculated from NETWORK_TYPE defined in {@link TelephonyManager}.
+     *
+     * Examples of Network Types include {@link TelephonyManager#NETWORK_TYPE_UNKNOWN},
+     * {@link TelephonyManager#NETWORK_TYPE_GPRS}, {@link TelephonyManager#NETWORK_TYPE_EDGE}.
+     *
+     * @return a bitmask describing the Radio Technologies(Network Types)
+     */
+    public int getNetworkTypeBitmask() {
+        return mNetworkTypeBitmask;
+    }
+
     /** @hide */
     @StringDef({
             MVNO_TYPE_SPN,
@@ -452,8 +439,7 @@
         this.mRoamingProtocol = builder.mRoamingProtocol;
         this.mMtu = builder.mMtu;
         this.mCarrierEnabled = builder.mCarrierEnabled;
-        this.mBearer = builder.mBearer;
-        this.mBearerBitmask = builder.mBearerBitmask;
+        this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
         this.mProfileId = builder.mProfileId;
         this.mModemCognitive = builder.mModemCognitive;
         this.mMaxConns = builder.mMaxConns;
@@ -467,8 +453,8 @@
     public static ApnSetting makeApnSetting(int id, String operatorNumeric, String entryName,
             String apnName, InetAddress proxy, int port, URL mmsc, InetAddress mmsProxy,
             int mmsPort, String user, String password, int authType, List<String> types,
-            String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
-            int bearerBitmask, int profileId, boolean modemCognitive, int maxConns,
+            String protocol, String roamingProtocol, boolean carrierEnabled,
+            int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
             int waitTime, int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
         return new Builder()
                 .setId(id)
@@ -487,8 +473,7 @@
                 .setProtocol(protocol)
                 .setRoamingProtocol(roamingProtocol)
                 .setCarrierEnabled(carrierEnabled)
-                .setBearer(bearer)
-                .setBearerBitmask(bearerBitmask)
+                .setNetworkTypeBitmask(networkTypeBitmask)
                 .setProfileId(profileId)
                 .setModemCognitive(modemCognitive)
                 .setMaxConns(maxConns)
@@ -504,6 +489,14 @@
     public static ApnSetting makeApnSetting(Cursor cursor) {
         String[] types = parseTypes(
                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
+        int networkTypeBitmask = cursor.getInt(
+                cursor.getColumnIndexOrThrow(Telephony.Carriers.NETWORK_TYPE_BITMASK));
+        if (networkTypeBitmask == 0) {
+            final int bearerBitmask = cursor.getInt(cursor.getColumnIndexOrThrow(
+                    Telephony.Carriers.BEARER_BITMASK));
+            networkTypeBitmask =
+                    ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
+        }
 
         return makeApnSetting(
                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
@@ -529,9 +522,7 @@
                         Telephony.Carriers.ROAMING_PROTOCOL)),
                 cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.CARRIER_ENABLED)) == 1,
-                cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)),
-                cursor.getInt(cursor.getColumnIndexOrThrow(
-                        Telephony.Carriers.BEARER_BITMASK)),
+                networkTypeBitmask,
                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
                 cursor.getInt(cursor.getColumnIndexOrThrow(
                         Telephony.Carriers.MODEM_COGNITIVE)) == 1,
@@ -551,7 +542,7 @@
         return makeApnSetting(apn.mId, apn.mOperatorNumeric, apn.mEntryName, apn.mApnName,
                 apn.mProxy, apn.mPort, apn.mMmsc, apn.mMmsProxy, apn.mMmsPort, apn.mUser,
                 apn.mPassword, apn.mAuthType, apn.mTypes, apn.mProtocol, apn.mRoamingProtocol,
-                apn.mCarrierEnabled, apn.mBearer, apn.mBearerBitmask, apn.mProfileId,
+                apn.mCarrierEnabled, apn.mNetworkTypeBitmask, apn.mProfileId,
                 apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime, apn.mMaxConnsTime, apn.mMtu,
                 apn.mMvnoType, apn.mMvnoMatchData);
     }
@@ -559,7 +550,7 @@
     /** @hide */
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("[ApnSettingV3] ")
+        sb.append("[ApnSettingV4] ")
                 .append(mEntryName)
                 .append(", ").append(mId)
                 .append(", ").append(mOperatorNumeric)
@@ -579,8 +570,6 @@
         sb.append(", ").append(mProtocol);
         sb.append(", ").append(mRoamingProtocol);
         sb.append(", ").append(mCarrierEnabled);
-        sb.append(", ").append(mBearer);
-        sb.append(", ").append(mBearerBitmask);
         sb.append(", ").append(mProfileId);
         sb.append(", ").append(mModemCognitive);
         sb.append(", ").append(mMaxConns);
@@ -590,6 +579,7 @@
         sb.append(", ").append(mMvnoType);
         sb.append(", ").append(mMvnoMatchData);
         sb.append(", ").append(mPermanentFailed);
+        sb.append(", ").append(mNetworkTypeBitmask);
         return sb.toString();
     }
 
@@ -678,8 +668,6 @@
                 && Objects.equals(mProtocol, other.mProtocol)
                 && Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
                 && Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
-                && Objects.equals(mBearer, other.mBearer)
-                && Objects.equals(mBearerBitmask, other.mBearerBitmask)
                 && Objects.equals(mProfileId, other.mProfileId)
                 && Objects.equals(mModemCognitive, other.mModemCognitive)
                 && Objects.equals(mMaxConns, other.mMaxConns)
@@ -687,13 +675,14 @@
                 && Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
                 && Objects.equals(mMtu, other.mMtu)
                 && Objects.equals(mMvnoType, other.mMvnoType)
-                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData);
+                && Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
+                && Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask);
     }
 
     /**
      * Compare two APN settings
      *
-     * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for
+     * Note: This method does not compare 'mId', 'mNetworkTypeBitmask'. We only use this for
      * determining if tearing a data call is needed when conditions change. See
      * cleanUpConnectionsOnUpdatedApns in DcTracker.
      *
@@ -752,13 +741,13 @@
                 && xorEquals(this.mProtocol, other.mProtocol)
                 && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
                 && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
-                && Objects.equals(this.mBearerBitmask, other.mBearerBitmask)
                 && Objects.equals(this.mProfileId, other.mProfileId)
                 && Objects.equals(this.mMvnoType, other.mMvnoType)
                 && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
                 && xorEqualsURL(this.mMmsc, other.mMmsc)
                 && xorEqualsInetAddress(this.mMmsProxy, other.mMmsProxy)
-                && xorEqualsPort(this.mMmsPort, other.mMmsPort));
+                && xorEqualsPort(this.mMmsPort, other.mMmsPort))
+                && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask);
     }
 
     // Equal or one is not specified.
@@ -808,53 +797,33 @@
         return TextUtils.join(",", types);
     }
 
+    private String nullToEmpty(String stringValue) {
+        return stringValue == null ? "" : stringValue;
+    }
+
     /** @hide */
     // Called by DPM.
     public ContentValues toContentValues() {
         ContentValues apnValue = new ContentValues();
-        if (mOperatorNumeric != null) {
-            apnValue.put(Telephony.Carriers.NUMERIC, mOperatorNumeric);
-        }
-        if (mEntryName != null) {
-            apnValue.put(Telephony.Carriers.NAME, mEntryName);
-        }
-        if (mApnName != null) {
-            apnValue.put(Telephony.Carriers.APN, mApnName);
-        }
-        if (mProxy != null) {
-            apnValue.put(Telephony.Carriers.PROXY, inetAddressToString(mProxy));
-        }
+        apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
+        apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
+        apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
+        apnValue.put(Telephony.Carriers.PROXY, mProxy == null ? "" : inetAddressToString(mProxy));
         apnValue.put(Telephony.Carriers.PORT, portToString(mPort));
-        if (mMmsc != null) {
-            apnValue.put(Telephony.Carriers.MMSC, URLToString(mMmsc));
-        }
+        apnValue.put(Telephony.Carriers.MMSC, mMmsc == null ? "" : URLToString(mMmsc));
         apnValue.put(Telephony.Carriers.MMSPORT, portToString(mMmsPort));
-        if (mMmsProxy != null) {
-            apnValue.put(Telephony.Carriers.MMSPROXY, inetAddressToString(mMmsProxy));
-        }
-        if (mUser != null) {
-            apnValue.put(Telephony.Carriers.USER, mUser);
-        }
-        if (mPassword != null) {
-            apnValue.put(Telephony.Carriers.PASSWORD, mPassword);
-        }
+        apnValue.put(Telephony.Carriers.MMSPROXY, mMmsProxy == null
+                ? "" : inetAddressToString(mMmsProxy));
+        apnValue.put(Telephony.Carriers.USER, nullToEmpty(mUser));
+        apnValue.put(Telephony.Carriers.PASSWORD, nullToEmpty(mPassword));
         apnValue.put(Telephony.Carriers.AUTH_TYPE, mAuthType);
         String apnType = deParseTypes(mTypes);
-        if (apnType != null) {
-            apnValue.put(Telephony.Carriers.TYPE, apnType);
-        }
-        if (mProtocol != null) {
-            apnValue.put(Telephony.Carriers.PROTOCOL, mProtocol);
-        }
-        if (mRoamingProtocol != null) {
-            apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, mRoamingProtocol);
-        }
+        apnValue.put(Telephony.Carriers.TYPE, nullToEmpty(apnType));
+        apnValue.put(Telephony.Carriers.PROTOCOL, nullToEmpty(mProtocol));
+        apnValue.put(Telephony.Carriers.ROAMING_PROTOCOL, nullToEmpty(mRoamingProtocol));
         apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
-        // networkTypeBit.
-        apnValue.put(Telephony.Carriers.BEARER_BITMASK, mBearerBitmask);
-        if (mMvnoType != null) {
-            apnValue.put(Telephony.Carriers.MVNO_TYPE, mMvnoType);
-        }
+        apnValue.put(Telephony.Carriers.MVNO_TYPE, nullToEmpty(mMvnoType));
+        apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
 
         return apnValue;
     }
@@ -905,8 +874,16 @@
         if (inetAddress == null) {
             return null;
         }
-        return TextUtils.isEmpty(inetAddress.getHostName())
-                ? inetAddress.getHostAddress() : inetAddress.getHostName();
+        final String inetAddressString = inetAddress.toString();
+        if (TextUtils.isEmpty(inetAddressString)) {
+            return null;
+        }
+        final String hostName = inetAddressString.substring(0, inetAddressString.indexOf("/"));
+        final String address = inetAddressString.substring(inetAddressString.indexOf("/") + 1);
+        if (TextUtils.isEmpty(hostName) && TextUtils.isEmpty(address)) {
+            return null;
+        }
+        return TextUtils.isEmpty(hostName) ? address : hostName;
     }
 
     private static int portFromString(String strPort) {
@@ -952,16 +929,33 @@
         dest.writeString(mRoamingProtocol);
         dest.writeInt(mCarrierEnabled ? 1: 0);
         dest.writeString(mMvnoType);
+        dest.writeInt(mNetworkTypeBitmask);
     }
 
     private static ApnSetting readFromParcel(Parcel in) {
-        return makeApnSetting(in.readInt(), in.readString(), in.readString(), in.readString(),
-                (InetAddress)in.readValue(InetAddress.class.getClassLoader()),
-                in.readInt(), (URL)in.readValue(URL.class.getClassLoader()),
-                (InetAddress)in.readValue(InetAddress.class.getClassLoader()),
-                in.readInt(), in.readString(), in.readString(), in.readInt(),
-                Arrays.asList(in.readStringArray()), in.readString(), in.readString(),
-                in.readInt() > 0, 0, 0, 0, false, 0, 0, 0, 0, in.readString(), null);
+        final int id = in.readInt();
+        final String operatorNumeric = in.readString();
+        final String entryName = in.readString();
+        final String apnName = in.readString();
+        final InetAddress proxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
+        final int port = in.readInt();
+        final URL mmsc = (URL)in.readValue(URL.class.getClassLoader());
+        final InetAddress mmsProxy = (InetAddress)in.readValue(InetAddress.class.getClassLoader());
+        final int mmsPort = in.readInt();
+        final String user = in.readString();
+        final String password = in.readString();
+        final int authType = in.readInt();
+        final List<String> types = Arrays.asList(in.readStringArray());
+        final String protocol = in.readString();
+        final String roamingProtocol = in.readString();
+        final boolean carrierEnabled = in.readInt() > 0;
+        final String mvnoType = in.readString();
+        final int networkTypeBitmask = in.readInt();
+
+        return makeApnSetting(id, operatorNumeric, entryName, apnName,
+                proxy, port, mmsc, mmsProxy, mmsPort, user, password, authType, types, protocol,
+                roamingProtocol, carrierEnabled, networkTypeBitmask, 0, false,
+                0, 0, 0, 0, mvnoType, null);
     }
 
     public static final Parcelable.Creator<ApnSetting> CREATOR =
@@ -1061,9 +1055,8 @@
         private String mProtocol;
         private String mRoamingProtocol;
         private int mMtu;
+        private int mNetworkTypeBitmask;
         private boolean mCarrierEnabled;
-        private int mBearer;
-        private int mBearerBitmask;
         private int mProfileId;
         private boolean mModemCognitive;
         private int mMaxConns;
@@ -1078,6 +1071,16 @@
         public Builder() {}
 
         /**
+         * Sets the unique database id for this entry.
+         *
+         * @param id the unique database id to set for this entry
+         */
+        private Builder setId(int id) {
+            this.mId = id;
+            return this;
+        }
+
+        /**
          * Set the MTU size of the mobile interface to which the APN connected.
          *
          * @param mtu the MTU size to set for the APN
@@ -1089,28 +1092,6 @@
         }
 
         /**
-         * Sets bearer info.
-         *
-         * @param bearer the bearer info to set for the APN
-         * @hide
-         */
-        public Builder setBearer(int bearer) {
-            this.mBearer = bearer;
-            return this;
-        }
-
-        /**
-         * Sets the radio access technology bitmask for this APN.
-         *
-         * @param bearerBitmask the radio access technology bitmask to set for this APN
-         * @hide
-         */
-        public Builder setBearerBitmask(int bearerBitmask) {
-            this.mBearerBitmask = bearerBitmask;
-            return this;
-        }
-
-        /**
          * Sets the profile id to which the APN saved in modem.
          *
          * @param profileId the profile id to set for the APN
@@ -1298,16 +1279,6 @@
         }
 
         /**
-         * Sets the unique database id for this entry.
-         *
-         * @param id the unique database id to set for this entry
-         */
-        public Builder setId(int id) {
-            this.mId = id;
-            return this;
-        }
-
-        /**
          * Set the numeric operator ID for the APN.
          *
          * @param operatorNumeric the numeric operator ID to set for this entry
@@ -1341,7 +1312,7 @@
         }
 
         /**
-         * Sets the current status of APN.
+         * Sets the current status for this APN.
          *
          * @param carrierEnabled the current status to set for this APN
          */
@@ -1351,6 +1322,16 @@
         }
 
         /**
+         * Sets Radio Technology (Network Type) info for this APN.
+         *
+         * @param networkTypeBitmask the Radio Technology (Network Type) info
+         */
+        public Builder setNetworkTypeBitmask(int networkTypeBitmask) {
+            this.mNetworkTypeBitmask = networkTypeBitmask;
+            return this;
+        }
+
+        /**
          * Sets the MVNO match type for this APN.
          *
          * Example of possible values: {@link #MVNO_TYPE_SPN}, {@link #MVNO_TYPE_IMSI}.
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 2534327..d146707 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -71,8 +71,18 @@
      * TODO(b/35851809): Make this a SystemApi.
      */
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_OTA_STATUS_CHANGED
-            = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+    public static final String ACTION_OTA_STATUS_CHANGED =
+            "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+
+    /**
+     * Broadcast Action: The action sent to carrier app so it knows the carrier setup is not
+     * completed.
+     *
+     * TODO(b/35851809): Make this a public API.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_NOTIFY_CARRIER_SETUP =
+            "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP";
 
     /**
      * Intent action to provision an embedded subscription.
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 1bd1af5..994f3cc 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -31,32 +31,34 @@
 LOCAL_CERTIFICATE := platform
 
 # These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := libframeworksnettestsjni \
+LOCAL_JNI_SHARED_LIBRARIES := \
+    android.hidl.token@1.0 \
     libbacktrace \
     libbase \
     libbinder \
     libc++ \
+    libcrypto \
     libcutils \
+    libframeworksnettestsjni \
+    libhidl-gen-utils \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
     liblog \
     liblzma \
     libnativehelper \
     libnetdaidl \
-    libui \
-    libunwind \
-    libutils \
-    libvndksupport \
-    libcrypto \
-    libhidl-gen-utils \
-    libhidlbase \
-    libhidltransport \
     libpackagelistparser \
     libpcre2 \
     libselinux \
-    libtinyxml2 \
+    libui \
+    libunwind \
+    libutils \
     libvintf \
-    libhwbinder \
+    libvndksupport \
+    libtinyxml2 \
     libunwindstack \
-    android.hidl.token@1.0
+    libutilscallstack
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 4fbb228..d9d4eeb 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -204,13 +204,13 @@
     }
 
     @Test
-    public void testCreateTransportModeTransform() throws Exception {
+    public void testCreateTransform() throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder());
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verify(mMockNetd)
@@ -236,14 +236,14 @@
     }
 
     @Test
-    public void testCreateTransportModeTransformAead() throws Exception {
+    public void testCreateTransformAead() throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
 
         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder());
         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
 
         verify(mMockNetd)
@@ -269,14 +269,14 @@
     }
 
     @Test
-    public void testDeleteTransportModeTransform() throws Exception {
+    public void testDeleteTransform() throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
-        mIpSecService.deleteTransportModeTransform(createTransformResp.resourceId);
+                mIpSecService.createTransform(ipSecConfig, new Binder());
+        mIpSecService.deleteTransform(createTransformResp.resourceId);
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
@@ -302,7 +302,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder());
 
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -334,7 +334,7 @@
         addAuthAndCryptToIpSecConfig(ipSecConfig);
 
         IpSecTransformResponse createTransformResp =
-                mIpSecService.createTransportModeTransform(ipSecConfig, new Binder());
+                mIpSecService.createTransform(ipSecConfig, new Binder());
         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
 
         int resourceId = createTransformResp.resourceId;
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 3eba881..a375b60 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -166,6 +166,7 @@
         mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
         udpEncapResp.fileDescriptor.close();
 
+        // Verify quota and RefcountedResource objects cleaned up
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
         assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
@@ -179,10 +180,8 @@
 
     @Test
     public void testUdpEncapsulationSocketBinderDeath() throws Exception {
-        int localport = findUnusedPort();
-
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
 
         IpSecService.UserRecord userRecord =
                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -192,6 +191,7 @@
 
         refcountedRecord.binderDied();
 
+        // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
         try {
             userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
@@ -412,9 +412,9 @@
     }
 
     @Test
-    public void testDeleteInvalidTransportModeTransform() throws Exception {
+    public void testDeleteInvalidTransform() throws Exception {
         try {
-            mIpSecService.deleteTransportModeTransform(1);
+            mIpSecService.deleteTransform(1);
             fail("IllegalArgumentException not thrown");
         } catch (IllegalArgumentException e) {
         }
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 29bf02c..03c9fbe 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -56,6 +56,11 @@
     /**
      * @hide
      */
+    public long mControllerScanTimeMs;
+
+    /**
+     * @hide
+     */
     public long mControllerIdleTimeMs;
 
     /**
@@ -69,13 +74,14 @@
     public static final int STACK_STATE_STATE_IDLE = 3;
 
     public WifiActivityEnergyInfo(long timestamp, int stackState,
-                                  long txTime, long[] txTimePerLevel, long rxTime, long idleTime,
-                                  long energyUsed) {
+                                  long txTime, long[] txTimePerLevel, long rxTime, long scanTime,
+                                  long idleTime, long energyUsed) {
         mTimestamp = timestamp;
         mStackState = stackState;
         mControllerTxTimeMs = txTime;
         mControllerTxTimePerLevelMs = txTimePerLevel;
         mControllerRxTimeMs = rxTime;
+        mControllerScanTimeMs = scanTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
     }
@@ -88,6 +94,7 @@
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
             + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
+            + " mControllerScanTimeMs=" + mControllerScanTimeMs
             + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
             + " mControllerEnergyUsed=" + mControllerEnergyUsed
             + " }";
@@ -101,10 +108,11 @@
             long txTime = in.readLong();
             long[] txTimePerLevel = in.createLongArray();
             long rxTime = in.readLong();
+            long scanTime = in.readLong();
             long idleTime = in.readLong();
             long energyUsed = in.readLong();
             return new WifiActivityEnergyInfo(timestamp, stackState,
-                    txTime, txTimePerLevel, rxTime, idleTime, energyUsed);
+                    txTime, txTimePerLevel, rxTime, scanTime, idleTime, energyUsed);
         }
         public WifiActivityEnergyInfo[] newArray(int size) {
             return new WifiActivityEnergyInfo[size];
@@ -117,6 +125,7 @@
         out.writeLong(mControllerTxTimeMs);
         out.writeLongArray(mControllerTxTimePerLevelMs);
         out.writeLong(mControllerRxTimeMs);
+        out.writeLong(mControllerScanTimeMs);
         out.writeLong(mControllerIdleTimeMs);
         out.writeLong(mControllerEnergyUsed);
     }
@@ -157,6 +166,13 @@
     }
 
     /**
+     * @return scan time in ms
+     */
+    public long getControllerScanTimeMillis() {
+        return mControllerScanTimeMs;
+    }
+
+    /**
      * @return idle time in ms
      */
     public long getControllerIdleTimeMillis() {
@@ -183,6 +199,7 @@
     public boolean isValid() {
         return ((mControllerTxTimeMs >=0) &&
                 (mControllerRxTimeMs >=0) &&
+                (mControllerScanTimeMs >=0) &&
                 (mControllerIdleTimeMs >=0));
     }
-}
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 99080d6..e4b510d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1625,6 +1625,7 @@
      *
      * @return hex-string encoded configuration token or null if there is no current network
      * @hide
+     * @deprecated This API is deprecated
      */
     public String getCurrentNetworkWpsNfcConfigurationToken() {
         try {
@@ -2210,20 +2211,34 @@
     /** @hide */
     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
 
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int START_WPS                       = BASE + 10;
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int START_WPS_SUCCEEDED             = BASE + 11;
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int WPS_FAILED                      = BASE + 12;
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int WPS_COMPLETED                   = BASE + 13;
 
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int CANCEL_WPS                      = BASE + 14;
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int CANCEL_WPS_FAILED               = BASE + 15;
-    /** @hide */
+    /** @hide
+     * @deprecated This is deprecated
+     */
     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
 
     /** @hide */
@@ -2263,15 +2278,25 @@
     public static final int BUSY                        = 2;
 
     /* WPS specific errors */
-    /** WPS overlap detected */
+    /** WPS overlap detected
+     * @deprecated This is deprecated
+     */
     public static final int WPS_OVERLAP_ERROR           = 3;
-    /** WEP on WPS is prohibited */
+    /** WEP on WPS is prohibited
+     * @deprecated This is deprecated
+     */
     public static final int WPS_WEP_PROHIBITED          = 4;
-    /** TKIP only prohibited */
+    /** TKIP only prohibited
+     * @deprecated This is deprecated
+     */
     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
-    /** Authentication failure on WPS */
+    /** Authentication failure on WPS
+     * @deprecated This is deprecated
+     */
     public static final int WPS_AUTH_FAILURE            = 6;
-    /** WPS timed out */
+    /** WPS timed out
+     * @deprecated This is deprecated
+     */
     public static final int WPS_TIMED_OUT               = 7;
 
     /**
@@ -2312,12 +2337,19 @@
         public void onFailure(int reason);
     }
 
-    /** Interface for callback invocation on a start WPS action */
+    /** Interface for callback invocation on a start WPS action
+     * @deprecated This is deprecated
+     */
     public static abstract class WpsCallback {
-        /** WPS start succeeded */
+
+        /** WPS start succeeded
+         * @deprecated This API is deprecated
+         */
         public abstract void onStarted(String pin);
 
-        /** WPS operation completed successfully */
+        /** WPS operation completed successfully
+         * @deprecated This API is deprecated
+         */
         public abstract void onSucceeded();
 
         /**
@@ -2326,6 +2358,7 @@
          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
          * and some generic errors.
+         * @deprecated This API is deprecated
          */
         public abstract void onFailed(int reason);
     }
@@ -3032,6 +3065,7 @@
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
+     * @deprecated This API is deprecated
      */
     public void startWps(WpsInfo config, WpsCallback listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
@@ -3044,6 +3078,7 @@
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
+     * @deprecated This API is deprecated
      */
     public void cancelWps(WpsCallback listener) {
         getChannel().sendMessage(CANCEL_WPS, 0, putListener(listener));
diff --git a/wifi/java/android/net/wifi/rtt/LocationCivic.java b/wifi/java/android/net/wifi/rtt/LocationCivic.java
new file mode 100644
index 0000000..610edb6
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/LocationCivic.java
@@ -0,0 +1,118 @@
+/*
+ * 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.net.wifi.rtt;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Location Civic Report (LCR).
+ * <p>
+ * The information matches the IEEE 802.11-2016 LCR report.
+ * <p>
+ * Note: depending on the mechanism by which this information is returned (i.e. the API which
+ * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case
+ * the information is NOT validated - use with caution. Consider validating it with other sources
+ * of information before using it.
+ */
+public final class LocationCivic implements Parcelable {
+    private final byte[] mData;
+
+    /**
+     * Parse the raw LCR information element (byte array) and extract the LocationCivic structure.
+     *
+     * Note: any parsing errors or invalid/unexpected errors will result in a null being returned.
+     *
+     * @hide
+     */
+    @Nullable
+    public static LocationCivic parseInformationElement(byte id, byte[] data) {
+        // TODO
+        return null;
+    }
+
+    /** @hide */
+    public LocationCivic(byte[] data) {
+        mData = data;
+    }
+
+    /**
+     * Return the Location Civic data reported by the peer.
+     *
+     * @return An arbitrary location information.
+     */
+    public byte[] getData() {
+        return mData;
+    }
+
+    /** @hide */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByteArray(mData);
+    }
+
+    public static final Parcelable.Creator<LocationCivic> CREATOR =
+            new Parcelable.Creator<LocationCivic>() {
+                @Override
+                public LocationCivic[] newArray(int size) {
+                    return new LocationCivic[size];
+                }
+
+                @Override
+                public LocationCivic createFromParcel(Parcel in) {
+                    byte[] data = in.createByteArray();
+
+                    return new LocationCivic(data);
+                }
+            };
+
+    /** @hide */
+    @Override
+    public String toString() {
+        return new StringBuilder("LCR: data=").append(Arrays.toString(mData)).toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof LocationCivic)) {
+            return false;
+        }
+
+        LocationCivic lhs = (LocationCivic) o;
+
+        return Arrays.equals(mData, lhs.mData);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mData);
+    }
+}
diff --git a/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java b/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java
new file mode 100644
index 0000000..8aba56a
--- /dev/null
+++ b/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java
@@ -0,0 +1,272 @@
+/*
+ * 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.net.wifi.rtt;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * The Device Location Configuration Information (LCI) specifies the location information of a peer
+ * device (e.g. an Access Point).
+ * <p>
+ * The information matches the IEEE 802.11-2016 LCI report (Location configuration information
+ * report).
+ * <p>
+ * Note: depending on the mechanism by which this information is returned (i.e. the API which
+ * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case
+ * the information is NOT validated - use with caution. Consider validating it with other sources
+ * of information before using it.
+ */
+public final class LocationConfigurationInformation implements Parcelable {
+    /** @hide */
+    @IntDef({
+            ALTITUDE_UNKNOWN, ALTITUDE_IN_METERS, ALTITUDE_IN_FLOORS })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AltitudeTypes {
+    }
+
+    /**
+     * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location
+     * does not specify an altitude or altitude uncertainty. The corresponding methods,
+     * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} are not valid and will throw
+     * an exception.
+     */
+    public static final int ALTITUDE_UNKNOWN = 0;
+
+    /**
+     * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location
+     * specifies the altitude and altitude uncertainty in meters. The corresponding methods,
+     * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} return a valid value in meters.
+     */
+    public static final int ALTITUDE_IN_METERS = 1;
+
+    /**
+     * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the
+     * location specifies the altitude in floors, and does not specify an altitude uncertainty.
+     * The {@link #getAltitude()} method returns valid value in floors, and the
+     * {@link #getAltitudeUncertainty()} method is not valid and will throw an exception.
+     */
+    public static final int ALTITUDE_IN_FLOORS = 2;
+
+    private final double mLatitude;
+    private final double mLatitudeUncertainty;
+    private final double mLongitude;
+    private final double mLongitudeUncertainty;
+    private final int mAltitudeType;
+    private final double mAltitude;
+    private final double mAltitudeUncertainty;
+
+    /**
+     * Parse the raw LCI information element (byte array) and extract the
+     * LocationConfigurationInformation structure.
+     *
+     * Note: any parsing errors or invalid/unexpected errors will result in a null being returned.
+     *
+     * @hide
+     */
+    @Nullable
+    public static LocationConfigurationInformation parseInformationElement(byte id, byte[] data) {
+        // TODO
+        return null;
+    }
+
+    /** @hide */
+    public LocationConfigurationInformation(double latitude, double latitudeUncertainty,
+            double longitude, double longitudeUncertainty, @AltitudeTypes int altitudeType,
+            double altitude, double altitudeUncertainty) {
+        mLatitude = latitude;
+        mLatitudeUncertainty = latitudeUncertainty;
+        mLongitude = longitude;
+        mLongitudeUncertainty = longitudeUncertainty;
+        mAltitudeType = altitudeType;
+        mAltitude = altitude;
+        mAltitudeUncertainty = altitudeUncertainty;
+    }
+
+    /**
+     * Get latitude in degrees. Values are per WGS 84 reference system. Valid values are between
+     * -90 and 90.
+     *
+     * @return Latitude in degrees.
+     */
+    public double getLatitude() {
+        return mLatitude;
+    }
+
+    /**
+     * Get the uncertainty of the latitude {@link #getLatitude()} in degrees. A value of 0 indicates
+     * an unknown uncertainty.
+     *
+     * @return Uncertainty of the latitude in degrees.
+     */
+    public double getLatitudeUncertainty() {
+        return mLatitudeUncertainty;
+    }
+
+    /**
+     * Get longitude in degrees. Values are per WGS 84 reference system. Valid values are between
+     * -180 and 180.
+     *
+     * @return Longitude in degrees.
+     */
+    public double getLongitude() {
+        return mLongitude;
+    }
+
+    /**
+     * Get the uncertainty of the longitude {@link #getLongitude()} ()} in degrees.  A value of 0
+     * indicates an unknown uncertainty.
+     *
+     * @return Uncertainty of the longitude in degrees.
+     */
+    public double getLongitudeUncertainty() {
+        return mLongitudeUncertainty;
+    }
+
+    /**
+     * Specifies the type of the altitude measurement returned by {@link #getAltitude()} and
+     * {@link #getAltitudeUncertainty()}. The possible values are:
+     * <li>{@link #ALTITUDE_UNKNOWN}: The altitude and altitude uncertainty are not provided.
+     * <li>{@link #ALTITUDE_IN_METERS}: The altitude and altitude uncertainty are provided in
+     * meters. Values are per WGS 84 reference system.
+     * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors, the altitude uncertainty
+     * is not provided.
+     *
+     * @return The type of the altitude and altitude uncertainty.
+     */
+    public @AltitudeTypes int getAltitudeType() {
+        return mAltitudeType;
+    }
+
+    /**
+     * The altitude is interpreted according to the {@link #getAltitudeType()}. The possible values
+     * are:
+     * <li>{@link #ALTITUDE_UNKNOWN}: The altitude is not provided - this method will throw an
+     * exception.
+     * <li>{@link #ALTITUDE_IN_METERS}: The altitude is provided in meters. Values are per WGS 84
+     * reference system.
+     * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors.
+     *
+     * @return Altitude value whose meaning is specified by {@link #getAltitudeType()}.
+     */
+    public double getAltitude() {
+        if (mAltitudeType == ALTITUDE_UNKNOWN) {
+            throw new IllegalStateException(
+                    "getAltitude(): invoked on an invalid type: getAltitudeType()==UNKNOWN");
+        }
+        return mAltitude;
+    }
+
+    /**
+     * Only valid if the the {@link #getAltitudeType()} is equal to {@link #ALTITUDE_IN_METERS} -
+     * otherwise this method will throw an exception.
+     * <p>
+     * Get the uncertainty of the altitude {@link #getAltitude()} in meters.  A value of 0
+     * indicates an unknown uncertainty.
+     *
+     * @return Uncertainty of the altitude in meters.
+     */
+    public double getAltitudeUncertainty() {
+        if (mAltitudeType != ALTITUDE_IN_METERS) {
+            throw new IllegalStateException(
+                    "getAltitude(): invoked on an invalid type: getAltitudeType()!=IN_METERS");
+        }
+        return mAltitudeUncertainty;
+    }
+
+    /** @hide */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeDouble(mLatitude);
+        dest.writeDouble(mLatitudeUncertainty);
+        dest.writeDouble(mLongitude);
+        dest.writeDouble(mLongitudeUncertainty);
+        dest.writeInt(mAltitudeType);
+        dest.writeDouble(mAltitude);
+        dest.writeDouble(mAltitudeUncertainty);
+    }
+
+    public static final Creator<LocationConfigurationInformation> CREATOR =
+            new Creator<LocationConfigurationInformation>() {
+        @Override
+        public LocationConfigurationInformation[] newArray(int size) {
+            return new LocationConfigurationInformation[size];
+        }
+
+        @Override
+        public LocationConfigurationInformation createFromParcel(Parcel in) {
+            double latitude = in.readDouble();
+            double latitudeUnc = in.readDouble();
+            double longitude = in.readDouble();
+            double longitudeUnc = in.readDouble();
+            int altitudeType = in.readInt();
+            double altitude = in.readDouble();
+            double altitudeUnc = in.readDouble();
+
+            return new LocationConfigurationInformation(latitude, latitudeUnc, longitude,
+                    longitudeUnc, altitudeType, altitude, altitudeUnc);
+        }
+    };
+
+    /** @hide */
+    @Override
+    public String toString() {
+        return new StringBuilder("LCI: latitude=").append(mLatitude).append(
+                ", latitudeUncertainty=").append(mLatitudeUncertainty).append(
+                ", longitude=").append(mLongitude).append(", longitudeUncertainty=").append(
+                mLongitudeUncertainty).append(", altitudeType=").append(mAltitudeType).append(
+                ", altitude=").append(mAltitude).append(", altitudeUncertainty=").append(
+                mAltitudeUncertainty).toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof LocationConfigurationInformation)) {
+            return false;
+        }
+
+        LocationConfigurationInformation lhs = (LocationConfigurationInformation) o;
+
+        return mLatitude == lhs.mLatitude && mLatitudeUncertainty == lhs.mLatitudeUncertainty
+                && mLongitude == lhs.mLongitude
+                && mLongitudeUncertainty == lhs.mLongitudeUncertainty
+                && mAltitudeType == lhs.mAltitudeType && mAltitude == lhs.mAltitude
+                && mAltitudeUncertainty == lhs.mAltitudeUncertainty;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLatitude, mLatitudeUncertainty, mLongitude, mLongitudeUncertainty,
+                mAltitudeType, mAltitude, mAltitudeUncertainty);
+    }
+}
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index d5ca8f7..201833b 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -65,29 +65,37 @@
     private final int mDistanceMm;
     private final int mDistanceStdDevMm;
     private final int mRssi;
+    private final LocationConfigurationInformation mLci;
+    private final LocationCivic mLcr;
     private final long mTimestamp;
 
     /** @hide */
     public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm,
-            int distanceStdDevMm, int rssi, long timestamp) {
+            int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr,
+            long timestamp) {
         mStatus = status;
         mMac = mac;
         mPeerHandle = null;
         mDistanceMm = distanceMm;
         mDistanceStdDevMm = distanceStdDevMm;
         mRssi = rssi;
+        mLci = lci;
+        mLcr = lcr;
         mTimestamp = timestamp;
     }
 
     /** @hide */
     public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm,
-            int distanceStdDevMm, int rssi, long timestamp) {
+            int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr,
+            long timestamp) {
         mStatus = status;
         mMac = null;
         mPeerHandle = peerHandle;
         mDistanceMm = distanceMm;
         mDistanceStdDevMm = distanceStdDevMm;
         mRssi = rssi;
+        mLci = lci;
+        mLcr = lcr;
         mTimestamp = timestamp;
     }
 
@@ -169,6 +177,38 @@
     }
 
     /**
+     * @return The Location Configuration Information (LCI) as self-reported by the peer.
+     * <p>
+     * Note: the information is NOT validated - use with caution. Consider validating it with
+     * other sources of information before using it.
+     */
+    @Nullable
+    public LocationConfigurationInformation getReportedLocationConfigurationInformation() {
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getReportedLocationConfigurationInformation(): invoked on an invalid result: "
+                            + "getStatus()=" + mStatus);
+        }
+        return mLci;
+    }
+
+    /**
+     * @return The Location Civic report (LCR) as self-reported by the peer.
+     * <p>
+     * Note: the information is NOT validated - use with caution. Consider validating it with
+     * other sources of information before using it.
+     */
+    @Nullable
+    public LocationCivic getReportedLocationCivic() {
+        if (mStatus != STATUS_SUCCESS) {
+            throw new IllegalStateException(
+                    "getReportedLocationCivic(): invoked on an invalid result: getStatus()="
+                            + mStatus);
+        }
+        return mLcr;
+    }
+
+    /**
      * @return The timestamp, in us since boot, at which the ranging operation was performed.
      * <p>
      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
@@ -205,6 +245,18 @@
         dest.writeInt(mDistanceMm);
         dest.writeInt(mDistanceStdDevMm);
         dest.writeInt(mRssi);
+        if (mLci == null) {
+            dest.writeBoolean(false);
+        } else {
+            dest.writeBoolean(true);
+            mLci.writeToParcel(dest, flags);
+        }
+        if (mLcr == null) {
+            dest.writeBoolean(false);
+        } else {
+            dest.writeBoolean(true);
+            mLcr.writeToParcel(dest, flags);
+        }
         dest.writeLong(mTimestamp);
     }
 
@@ -230,13 +282,23 @@
             int distanceMm = in.readInt();
             int distanceStdDevMm = in.readInt();
             int rssi = in.readInt();
+            boolean lciPresent = in.readBoolean();
+            LocationConfigurationInformation lci = null;
+            if (lciPresent) {
+                lci = LocationConfigurationInformation.CREATOR.createFromParcel(in);
+            }
+            boolean lcrPresent = in.readBoolean();
+            LocationCivic lcr = null;
+            if (lcrPresent) {
+                lcr = LocationCivic.CREATOR.createFromParcel(in);
+            }
             long timestamp = in.readLong();
             if (peerHandlePresent) {
                 return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi,
-                        timestamp);
+                        lci, lcr, timestamp);
             } else {
                 return new RangingResult(status, mac, distanceMm, distanceStdDevMm, rssi,
-                        timestamp);
+                        lci, lcr, timestamp);
             }
         }
     };
@@ -248,8 +310,8 @@
                 mMac).append(", peerHandle=").append(
                 mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(", distanceMm=").append(
                 mDistanceMm).append(", distanceStdDevMm=").append(mDistanceStdDevMm).append(
-                ", rssi=").append(mRssi).append(", timestamp=").append(mTimestamp).append(
-                "]").toString();
+                ", rssi=").append(mRssi).append(", lci=").append(mLci).append(", lcr=").append(
+                mLcr).append(", timestamp=").append(mTimestamp).append("]").toString();
     }
 
     @Override
@@ -267,12 +329,13 @@
         return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals(
                 mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm
                 && mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi
+                && Objects.equals(mLci, lhs.mLci) && Objects.equals(mLcr, lhs.mLcr)
                 && mTimestamp == lhs.mTimestamp;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi,
-                mTimestamp);
+                mLci, mLcr, mTimestamp);
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 72e95b9..41c7f86 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -17,6 +17,7 @@
 package android.net.wifi.rtt;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
@@ -32,7 +33,6 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.test.TestLooper;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,7 +46,6 @@
 /**
  * Unit test harness for WifiRttManager class.
  */
-@SmallTest
 public class WifiRttManagerTest {
     private WifiRttManager mDut;
     private TestLooper mMockLooper;
@@ -80,7 +79,7 @@
         List<RangingResult> results = new ArrayList<>();
         results.add(
                 new RangingResult(RangingResult.STATUS_SUCCESS, MacAddress.BROADCAST_ADDRESS, 15, 5,
-                        10, 666));
+                        10, null, null, 666));
         RangingResultCallback callbackMock = mock(RangingResultCallback.class);
         ArgumentCaptor<IRttCallback> callbackCaptor = ArgumentCaptor.forClass(IRttCallback.class);
 
@@ -236,10 +235,23 @@
         int distanceStdDevCm = 10;
         int rssi = 5;
         long timestamp = System.currentTimeMillis();
+        double latitude = 5.5;
+        double latitudeUncertainty = 6.5;
+        double longitude = 7.5;
+        double longitudeUncertainty = 8.5;
+        int altitudeType = LocationConfigurationInformation.ALTITUDE_IN_METERS;
+        double altitude = 9.5;
+        double altitudeUncertainty = 55.5;
+        byte[] lcrData = { 0x1, 0x2, 0x3, 0xA, 0xB, 0xC };
+
+        LocationConfigurationInformation lci = new LocationConfigurationInformation(latitude,
+                latitudeUncertainty, longitude, longitudeUncertainty, altitudeType, altitude,
+                altitudeUncertainty);
+        LocationCivic lcr = new LocationCivic(lcrData);
 
         // RangingResults constructed with a MAC address
         RangingResult result = new RangingResult(status, mac, distanceCm, distanceStdDevCm, rssi,
-                timestamp);
+                lci, lcr, timestamp);
 
         Parcel parcelW = Parcel.obtain();
         result.writeToParcel(parcelW, 0);
@@ -255,7 +267,7 @@
 
         // RangingResults constructed with a PeerHandle
         result = new RangingResult(status, peerHandle, distanceCm, distanceStdDevCm, rssi,
-                timestamp);
+                null, null, timestamp);
 
         parcelW = Parcel.obtain();
         result.writeToParcel(parcelW, 0);
@@ -269,4 +281,83 @@
 
         assertEquals(result, rereadResult);
     }
+
+    /**
+     * Validate that LocationConfigurationInformation parcel works (produces same object on
+     * write/read).
+     */
+    @Test
+    public void testLciParcel() {
+        double latitude = 1.5;
+        double latitudeUncertainty = 2.5;
+        double longitude = 3.5;
+        double longitudeUncertainty = 4.5;
+        int altitudeType = LocationConfigurationInformation.ALTITUDE_IN_FLOORS;
+        double altitude = 5.5;
+        double altitudeUncertainty = 6.5;
+
+        LocationConfigurationInformation lci = new LocationConfigurationInformation(latitude,
+                latitudeUncertainty, longitude, longitudeUncertainty, altitudeType, altitude,
+                altitudeUncertainty);
+
+        Parcel parcelW = Parcel.obtain();
+        lci.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        LocationConfigurationInformation rereadLci =
+                LocationConfigurationInformation.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(lci, rereadLci);
+    }
+
+    /**
+     * Validate that the LCI throws an exception when accessing invalid fields an certain altitude
+     * types.
+     */
+    @Test
+    public void testLciInvalidAltitudeFieldAccess() {
+        boolean exceptionThrown;
+        LocationConfigurationInformation lci = new LocationConfigurationInformation(0, 0, 0, 0,
+                LocationConfigurationInformation.ALTITUDE_UNKNOWN, 0, 0);
+
+        // UNKNOWN - invalid altitude & altitude uncertainty
+        exceptionThrown = false;
+        try {
+            lci.getAltitude();
+        } catch (IllegalStateException e) {
+            exceptionThrown = true;
+        }
+        assertTrue("UNKNOWN / getAltitude()", exceptionThrown);
+
+        exceptionThrown = false;
+        try {
+            lci.getAltitudeUncertainty();
+        } catch (IllegalStateException e) {
+            exceptionThrown = true;
+        }
+        assertTrue("UNKNOWN / getAltitudeUncertainty()", exceptionThrown);
+
+        lci = new LocationConfigurationInformation(0, 0, 0, 0,
+                LocationConfigurationInformation.ALTITUDE_IN_FLOORS, 0, 0);
+
+        // FLOORS - invalid altitude uncertainty
+        exceptionThrown = false;
+        try {
+            lci.getAltitudeUncertainty();
+        } catch (IllegalStateException e) {
+            exceptionThrown = true;
+        }
+        assertTrue("FLOORS / getAltitudeUncertainty()", exceptionThrown);
+
+        // and good accesses just in case
+        lci.getAltitude();
+        lci = new LocationConfigurationInformation(0, 0, 0, 0,
+                LocationConfigurationInformation.ALTITUDE_IN_METERS, 0, 0);
+        lci.getAltitude();
+        lci.getAltitudeUncertainty();
+    }
 }