Merge "Check Settings.Global before sysprop in FeatureFlagUtils."
diff --git a/Android.mk b/Android.mk
index b847425..24e717d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,7 @@
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IAppTask.aidl \
 	core/java/android/app/IApplicationThread.aidl \
+	core/java/android/app/IAssistDataReceiver.aidl \
 	core/java/android/app/ITaskStackListener.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IEphemeralResolver.aidl \
@@ -168,7 +169,6 @@
 	core/java/android/content/pm/IPackageDataObserver.aidl \
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
 	core/java/android/content/pm/IPackageDeleteObserver2.aidl \
-	core/java/android/content/pm/IPackageInstallObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver2.aidl \
 	core/java/android/content/pm/IPackageInstaller.aidl \
 	core/java/android/content/pm/IPackageInstallerCallback.aidl \
@@ -383,7 +383,6 @@
 	core/java/android/speech/tts/ITextToSpeechService.aidl \
 	core/java/com/android/internal/app/IAppOpsCallback.aidl \
 	core/java/com/android/internal/app/IAppOpsService.aidl \
-	core/java/com/android/internal/app/IAssistDataReceiver.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
 	core/java/com/android/internal/app/ISoundTriggerService.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
@@ -638,6 +637,7 @@
     framework-protos                                     \
     android.hidl.base-V1.0-java                          \
     android.hardware.cas-V1.0-java                       \
+    android.hardware.contexthub-V1.0-java                \
     android.hardware.health-V1.0-java-constants          \
     android.hardware.thermal-V1.0-java-constants         \
     android.hardware.tv.input-V1.0-java-constants        \
@@ -931,7 +931,7 @@
 	../opt/net/voip/src/java/android/net/sip
 
 framework_base_android_test_mock_src_files := \
-	$(call all-java-files-under, test-runner/src/android/test/mock)
+	$(call all-java-files-under, test-mock/src/android/test/mock)
 
 framework_base_android_test_runner_excluding_mock_src_files := \
 	$(filter-out $(framework_base_android_test_mock_src_files), $(call all-java-files-under, test-runner/src))
diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
index a92597f..6e4c9c5 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
@@ -27,6 +27,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ParcelPerfTest {
@@ -167,4 +171,80 @@
             Parcel.obtain().recycle();
         }
     }
+
+    @Test
+    public void timeWriteException() {
+        timeWriteException(false);
+    }
+
+    @Test
+    public void timeWriteExceptionWithStackTraceParceling() {
+        timeWriteException(true);
+    }
+
+    @Test
+    public void timeReadException() {
+        timeReadException(false);
+    }
+
+    @Test
+    public void timeReadExceptionWithStackTraceParceling() {
+        timeReadException(true);
+    }
+
+    private void timeWriteException(boolean enableParceling) {
+        if (enableParceling) {
+            Parcel.setStackTraceParceling(true);
+        }
+        try {
+            final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            Parcel p = Parcel.obtain();
+            SecurityException e = new SecurityException("TestMessage");
+            while (state.keepRunning()) {
+                p.setDataPosition(0);
+                p.writeException(e);
+            }
+        } finally {
+            if (enableParceling) {
+                Parcel.setStackTraceParceling(false);
+            }
+        }
+    }
+
+    private void timeReadException(boolean enableParceling) {
+        if (enableParceling) {
+            Parcel.setStackTraceParceling(true);
+        }
+        try {
+            final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            Parcel p = Parcel.obtain();
+            String msg = "TestMessage";
+            p.writeException(new SecurityException(msg));
+            p.setDataPosition(0);
+            // First verify that remote cause is set (if parceling is enabled)
+            try {
+                p.readException();
+            } catch (SecurityException e) {
+                assertEquals(e.getMessage(), msg);
+                if (enableParceling) {
+                    assertTrue(e.getCause() instanceof RemoteException);
+                } else {
+                    assertNull(e.getCause());
+                }
+            }
+
+            while (state.keepRunning()) {
+                p.setDataPosition(0);
+                try {
+                    p.readException();
+                } catch (SecurityException expected) {
+                }
+            }
+        } finally {
+            if (enableParceling) {
+                Parcel.setStackTraceParceling(false);
+            }
+        }
+    }
+
 }
diff --git a/api/current.txt b/api/current.txt
index a1b9596..b1ca3e8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38624,7 +38624,6 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -38650,7 +38649,6 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
     method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -39227,6 +39225,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -39271,6 +39270,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -39279,6 +39280,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -39613,8 +39618,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39737,6 +39745,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39897,6 +39908,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -46073,6 +46085,7 @@
     method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -46407,6 +46420,7 @@
     method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyFallback(android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyPreIme(int, android.view.KeyEvent);
@@ -46460,6 +46474,7 @@
     method public void refreshDrawableState();
     method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void requestApplyInsets();
@@ -46878,6 +46893,10 @@
     method public abstract boolean onHover(android.view.View, android.view.MotionEvent);
   }
 
+  public static abstract interface View.OnKeyFallbackListener {
+    method public abstract boolean onKeyFallback(android.view.View, android.view.KeyEvent);
+  }
+
   public static abstract interface View.OnKeyListener {
     method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index d4656ac..592bd3d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -41928,7 +41928,6 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -41954,7 +41953,6 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
     method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -42550,6 +42548,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -42596,6 +42595,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -42604,6 +42605,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -42949,8 +42954,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -43198,6 +43206,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -43399,6 +43410,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -49818,6 +49830,7 @@
     method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -50152,6 +50165,7 @@
     method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyFallback(android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyPreIme(int, android.view.KeyEvent);
@@ -50205,6 +50219,7 @@
     method public void refreshDrawableState();
     method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void requestApplyInsets();
@@ -50623,6 +50638,10 @@
     method public abstract boolean onHover(android.view.View, android.view.MotionEvent);
   }
 
+  public static abstract interface View.OnKeyFallbackListener {
+    method public abstract boolean onKeyFallback(android.view.View, android.view.KeyEvent);
+  }
+
   public static abstract interface View.OnKeyListener {
     method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index ffcdeae..98615ee 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -38156,6 +38156,7 @@
 
   public abstract class ConditionProviderService extends android.app.Service {
     ctor public ConditionProviderService();
+    method public boolean isBound();
     method public final void notifyCondition(android.service.notification.Condition);
     method public final void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
@@ -39014,7 +39015,6 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
@@ -39040,7 +39040,6 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
     method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -39617,6 +39616,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -39661,6 +39661,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -39669,6 +39671,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -40019,8 +40025,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -40143,6 +40152,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -40303,6 +40315,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -46729,6 +46742,7 @@
     method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
+    method public void addKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -47065,6 +47079,7 @@
     method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyFallback(android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyPreIme(int, android.view.KeyEvent);
@@ -47118,6 +47133,7 @@
     method public void refreshDrawableState();
     method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
+    method public void removeKeyFallbackListener(android.view.View.OnKeyFallbackListener);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void requestApplyInsets();
@@ -47540,6 +47556,10 @@
     method public abstract boolean onHover(android.view.View, android.view.MotionEvent);
   }
 
+  public static abstract interface View.OnKeyFallbackListener {
+    method public abstract boolean onKeyFallback(android.view.View, android.view.KeyEvent);
+  }
+
   public static abstract interface View.OnKeyListener {
     method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
   }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 07b1c5c..8bc776f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -17,6 +17,7 @@
 #define DEBUG true
 #include "Log.h"
 
+#include "android-base/stringprintf.h"
 #include "StatsService.h"
 #include "config/ConfigKey.h"
 #include "config/ConfigManager.h"
@@ -25,11 +26,11 @@
 #include <android-base/file.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <dirent.h>
 #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
 #include <utils/String16.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/system_properties.h>
@@ -42,6 +43,7 @@
 namespace statsd {
 
 constexpr const char* kPermissionDump = "android.permission.DUMP";
+#define STATS_SERVICE_DIR "/data/system/stats-service"
 
 // ======================================================================
 /**
@@ -206,6 +208,10 @@
         if (!args[0].compare(String8("send-broadcast"))) {
             return cmd_trigger_broadcast(args);
         }
+
+        if (!args[0].compare(String8("clear-config"))) {
+            return cmd_remove_config_files(out);
+        }
     }
 
     print_cmd_help(out);
@@ -223,6 +229,11 @@
     fprintf(out, "  Prints the UID, app name, version mapping.\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats clear-config \n");
+    fprintf(out, "\n");
+    fprintf(out, "  Removes all configs from disk.\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
     fprintf(out, "usage: adb shell cmds stats pull-source [int] \n");
     fprintf(out, "\n");
     fprintf(out, "  Prints the output of a pulled metrics source (int indicates source)\n");
@@ -405,6 +416,27 @@
     return UNKNOWN_ERROR;
 }
 
+status_t StatsService::cmd_remove_config_files(FILE* out) {
+    fprintf(out, "Trying to remove config files...\n");
+    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+    if (dir == NULL) {
+        fprintf(out, "No existing config files found exiting...\n");
+        return NO_ERROR;
+    }
+
+    dirent* de;
+    while ((de = readdir(dir.get()))) {
+        char* name = de->d_name;
+        if (name[0] == '.') continue;
+        string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
+        fprintf(out, "Deleting file %s\n", file_name.c_str());
+        if (remove(file_name.c_str())) {
+            fprintf(out, "Error deleting file %s\n", file_name.c_str());
+        }
+    }
+    return NO_ERROR;
+}
+
 Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                       const vector<String16>& app) {
     if (DEBUG) ALOGD("StatsService::informAllUidData was called");
@@ -543,9 +575,7 @@
 
 Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
     IPCThreadState* ipc = IPCThreadState::self();
-    if (checkCallingPermission(String16(kPermissionDump),
-                               reinterpret_cast<int32_t*>(ipc->getCallingPid()),
-                               reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
+    if (checkCallingPermission(String16(kPermissionDump))) {
         // TODO: Implement this.
         return Status::ok();
     } else {
@@ -559,8 +589,7 @@
                                       bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     int32_t* uid = reinterpret_cast<int32_t*>(ipc->getCallingUid());
-    if (checkCallingPermission(String16(kPermissionDump),
-                               reinterpret_cast<int32_t*>(ipc->getCallingPid()), uid)) {
+    if (checkCallingPermission(String16(kPermissionDump))) {
         string keyString = string(String8(key).string());
         ConfigKey configKey(*uid, keyString);
         StatsdConfig cfg;
@@ -577,9 +606,7 @@
 
 Status StatsService::removeConfiguration(const String16& key, bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
-    if (checkCallingPermission(String16(kPermissionDump),
-                               reinterpret_cast<int32_t*>(ipc->getCallingPid()),
-                               reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
+    if (checkCallingPermission(String16(kPermissionDump))) {
         // TODO: Implement this.
         return Status::ok();
     } else {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fba8af7..0163f94 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -152,6 +152,11 @@
     status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
 
     /**
+     * Removes all configs stored on disk.
+     */
+    status_t cmd_remove_config_files(FILE* out);
+
+    /**
      * Update a configuration.
      */
     void set_config(int uid, const string& name, const StatsdConfig& config);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 48b85c9..ba93feb 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -102,8 +102,7 @@
 
 /*
  * *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd
- * and Westworld.
+ * Below are all of the individual atoms that are logged by Android via statsd.
  *
  * RULES:
  *   - The field ids for each atom must start at 1, and count upwards by 1.
diff --git a/cmds/statsd/src/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto
index 598c2bc..58e225a 100644
--- a/cmds/statsd/src/atoms_copy.proto
+++ b/cmds/statsd/src/atoms_copy.proto
@@ -104,8 +104,7 @@
 
 /*
  * *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd
- * and Westworld.
+ * Below are all of the individual atoms that are logged by Android via statsd.
  *
  * RULES:
  *   - The field ids for each atom must start at 1, and count upwards by 1.
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index a694dbf..60060fe 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -206,7 +206,7 @@
                                                vector<bool>& conditionChangedCache) {
     if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
         // it has been evaluated.
-        VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState);
+        VLOG("Yes, already evaluated, %s %d", mName.c_str(), conditionCache[mIndex]);
         return;
     }
 
@@ -230,8 +230,23 @@
     }
 
     if (matchedState < 0) {
+        // The event doesn't match this condition. So we just report existing condition values.
         conditionChangedCache[mIndex] = false;
-        conditionCache[mIndex] = mNonSlicedConditionState;
+        if (mSliced) {
+            // if the condition result is sliced. metrics won't directly get value from the
+            // cache, so just set any value other than kNotEvaluated.
+            conditionCache[mIndex] = ConditionState::kUnknown;
+        } else if (mSlicedConditionState.find(DEFAULT_DIMENSION_KEY) ==
+                   mSlicedConditionState.end()) {
+            // condition not sliced, but we haven't seen the matched start or stop yet. so return
+            // initial value.
+            conditionCache[mIndex] = mInitialValue;
+        } else {
+            // return the cached condition.
+            conditionCache[mIndex] = mSlicedConditionState[DEFAULT_DIMENSION_KEY] > 0
+                                             ? ConditionState::kTrue
+                                             : ConditionState::kFalse;
+        }
         return;
     }
 
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index bbf20fd..3489c43 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -78,7 +78,7 @@
 
 /**
  * A hash function for ConfigKey so it can be used for unordered_map/set.
- * Unfortunately this hast to go in std namespace because C++ is fun!
+ * Unfortunately this has to go in std namespace because C++ is fun!
  */
 namespace std {
 
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 6e8ed77..3319f6d 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -18,16 +18,23 @@
 
 #include "stats_util.h"
 
-#include <vector>
-
+#include <android-base/file.h>
+#include <dirent.h>
 #include <stdio.h>
+#include <vector>
+#include "android-base/stringprintf.h"
 
 namespace android {
 namespace os {
 namespace statsd {
 
+#define STATS_SERVICE_DIR "/data/system/stats-service"
+
 static StatsdConfig build_fake_config();
 
+using android::base::StringPrintf;
+using std::unique_ptr;
+
 ConfigManager::ConfigManager() {
 }
 
@@ -35,11 +42,10 @@
 }
 
 void ConfigManager::Startup() {
-    // TODO: Implement me -- read from storage and call onto all of the listeners.
-    // Instead, we'll just make a fake one.
+    readConfigFromDisk();
 
     // this should be called from StatsService when it receives a statsd_config
-    UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
+    UpdateConfig(ConfigKey(1000, "fake"), build_fake_config());
 }
 
 void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
@@ -52,7 +58,7 @@
     // Why doesn't this work? mConfigs.insert({key, config});
 
     // Save to disk
-    update_saved_configs();
+    update_saved_configs(key, config);
 
     // Tell everyone
     for (auto& listener : mListeners) {
@@ -74,8 +80,8 @@
         // Remove from map
         mConfigs.erase(it);
 
-        // Save to disk
-        update_saved_configs();
+        // Remove from disk
+        remove_saved_configs(key);
 
         // Tell everyone
         for (auto& listener : mListeners) {
@@ -85,6 +91,26 @@
     // If we didn't find it, just quietly ignore it.
 }
 
+void ConfigManager::remove_saved_configs(const ConfigKey& key) {
+    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+    if (dir == NULL) {
+        ALOGD("no default config on disk");
+        return;
+    }
+    string prefix = StringPrintf("%d-%s", key.GetUid(), key.GetName().c_str());
+    dirent* de;
+    while ((de = readdir(dir.get()))) {
+        char* name = de->d_name;
+        if (name[0] != '.' && strncmp(name, prefix.c_str(), prefix.size()) == 0) {
+            if (remove(StringPrintf("%s/%d-%s", STATS_SERVICE_DIR, key.GetUid(),
+                                    key.GetName().c_str())
+                               .c_str()) != 0) {
+                ALOGD("no file found");
+            }
+        }
+    }
+}
+
 void ConfigManager::RemoveConfigs(int uid) {
     vector<ConfigKey> removed;
 
@@ -118,8 +144,64 @@
     }
 }
 
-void ConfigManager::update_saved_configs() {
-    // TODO: Implement me -- write to disk.
+void ConfigManager::readConfigFromDisk() {
+    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
+    if (dir == NULL) {
+        ALOGD("no default config on disk");
+        return;
+    }
+
+    dirent* de;
+    while ((de = readdir(dir.get()))) {
+        char* name = de->d_name;
+        if (name[0] == '.') continue;
+        ALOGD("file %s", name);
+
+        int index = 0;
+        int uid = 0;
+        string configName;
+        char* substr = strtok(name, "-");
+        // Timestamp lives at index 2 but we skip parsing it as it's not needed.
+        while (substr != nullptr && index < 2) {
+            if (index) {
+                uid = atoi(substr);
+            } else {
+                configName = substr;
+            }
+            index++;
+        }
+        if (index < 2) continue;
+        string file_name = StringPrintf("%s/%s", STATS_SERVICE_DIR, name);
+        ALOGD("full file %s", file_name.c_str());
+        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+        if (fd != -1) {
+            string content;
+            if (android::base::ReadFdToString(fd, &content)) {
+                StatsdConfig config;
+                if (config.ParseFromString(content)) {
+                    mConfigs[ConfigKey(uid, configName)] = config;
+                    ALOGD("map key uid=%d|name=%s", uid, name);
+                }
+            }
+            close(fd);
+        }
+    }
+}
+
+void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
+    mkdir(STATS_SERVICE_DIR, S_IRWXU);
+    string file_name = StringPrintf("%s/%d-%s-%ld", STATS_SERVICE_DIR, key.GetUid(),
+                                    key.GetName().c_str(), time(nullptr));
+    int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+    if (fd != -1) {
+        const int numBytes = config.ByteSize();
+        vector<uint8_t> buffer(numBytes);
+        config.SerializeToArray(&buffer[0], numBytes);
+        int result = write(fd, &buffer[0], numBytes);
+        close(fd);
+        bool wroteKey = (result == numBytes);
+        ALOGD("wrote to file %d", wroteKey);
+    }
 }
 
 static StatsdConfig build_fake_config() {
@@ -212,7 +294,7 @@
     keyMatcher = durationMetric->add_dimension();
     keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
     durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
     link = durationMetric->add_links();
     link->set_condition("APP_IS_BACKGROUND");
     link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
@@ -226,7 +308,7 @@
     keyMatcher = durationMetric->add_dimension();
     keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
     durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
     link = durationMetric->add_links();
     link->set_condition("APP_IS_BACKGROUND");
     link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
@@ -238,7 +320,7 @@
     durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
     durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
     durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
-    durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+    durationMetric->set_condition("APP_IS_BACKGROUND_AND_SCREEN_ON");
     link = durationMetric->add_links();
     link->set_condition("APP_IS_BACKGROUND");
     link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index c21247f9..5b612cc 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -46,9 +46,7 @@
     virtual ~ConfigManager();
 
     /**
-     * Call to load the saved configs from disk.
-     *
-     * TODO: Implement me
+     * Initialize ConfigListener by reading from disk and get updates.
      */
     void Startup();
 
@@ -95,7 +93,12 @@
     /**
      * Save the configs to disk.
      */
-    void update_saved_configs();
+    void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);
+
+    /**
+     * Remove saved configs from disk.
+     */
+    void remove_saved_configs(const ConfigKey& key);
 
     /**
      * The Configs that have been set. Each config should
@@ -112,6 +115,11 @@
      * The ConfigListeners that will be told about changes.
      */
     vector<sp<ConfigListener>> mListeners;
+
+    /**
+     * Call to load the saved configs from disk.
+     */
+    void readConfigFromDisk();
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index e004d21..e2745d2 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -71,10 +71,9 @@
     do {
       timeMs = std::stoull(pch);
       auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ_PULLED, timestamp);
-      auto elemList = ptr->GetAndroidLogEventList();
-      *elemList << uid;
-      *elemList << idx;
-      *elemList << timeMs;
+      ptr->write(uid);
+      ptr->write(idx);
+      ptr->write(timeMs);
       ptr->init();
       data->push_back(ptr);
       VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index b84b877..e0572dc 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -66,10 +66,9 @@
     uint64_t sysTimeMs = std::stoull(pch);
 
     auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_PULLED, timestamp);
-    auto elemList = ptr->GetAndroidLogEventList();
-    *elemList << uid;
-    *elemList << userTimeMs;
-    *elemList << sysTimeMs;
+    ptr->write(uid);
+    ptr->write(userTimeMs);
+    ptr->write(sysTimeMs);
     ptr->init();
     data->push_back(ptr);
     VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs, (long long)sysTimeMs);
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
index 319feef4..3ee636d 100644
--- a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
@@ -93,11 +93,10 @@
 
                     auto statePtr = make_shared<LogEvent>(
                             android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED, timestamp);
-                    auto elemList = statePtr->GetAndroidLogEventList();
-                    *elemList << state.name;
-                    *elemList << state.residencyInMsecSinceBoot;
-                    *elemList << state.totalTransitions;
-                    *elemList << state.supportedOnlyInSuspend;
+                    statePtr->write(state.name);
+                    statePtr->write(state.residencyInMsecSinceBoot);
+                    statePtr->write(state.totalTransitions);
+                    statePtr->write(state.supportedOnlyInSuspend);
                     statePtr->init();
                     data->push_back(statePtr);
                     VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
@@ -106,11 +105,10 @@
                     for (auto voter : state.voters) {
                         auto voterPtr =
                                 make_shared<LogEvent>(android::util::POWER_STATE_VOTER_PULLED, timestamp);
-                        auto elemList = voterPtr->GetAndroidLogEventList();
-                        *elemList << state.name;
-                        *elemList << voter.name;
-                        *elemList << voter.totalTimeInMsecVotedForSinceBoot;
-                        *elemList << voter.totalNumberOfTimesVotedSinceBoot;
+                        voterPtr->write(state.name);
+                        voterPtr->write(voter.name);
+                        voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
+                        voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
                         voterPtr->init();
                         data->push_back(voterPtr);
                         VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
@@ -141,13 +139,12 @@
                                 const PowerStateSubsystemSleepState& state = subsystem.states[j];
                                 auto subsystemStatePtr = make_shared<LogEvent>(
                                         android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED, timestamp);
-                                auto elemList = subsystemStatePtr->GetAndroidLogEventList();
-                                *elemList << subsystem.name;
-                                *elemList << state.name;
-                                *elemList << state.residencyInMsecSinceBoot;
-                                *elemList << state.totalTransitions;
-                                *elemList << state.lastEntryTimestampMs;
-                                *elemList << state.supportedOnlyInSuspend;
+                                subsystemStatePtr->write(subsystem.name);
+                                subsystemStatePtr->write(state.name);
+                                subsystemStatePtr->write(state.residencyInMsecSinceBoot);
+                                subsystemStatePtr->write(state.totalTransitions);
+                                subsystemStatePtr->write(state.lastEntryTimestampMs);
+                                subsystemStatePtr->write(state.supportedOnlyInSuspend);
                                 subsystemStatePtr->init();
                                 data->push_back(subsystemStatePtr);
                                 VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 913b906..8023670 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -29,21 +29,72 @@
 using std::string;
 using android::util::ProtoOutputStream;
 
-// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
-// for strings is not cleared before we can read them.
-LogEvent::LogEvent(log_msg& msg) : mList(msg) {
-    init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
+LogEvent::LogEvent(log_msg& msg) {
+    android_log_context context =
+            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;
+    mContext = NULL;
+    init(context);
 }
 
-LogEvent::LogEvent(int tag, uint64_t timestampNs) : mList(tag), mTimestampNs(timestampNs) {
-}
-
-LogEvent::~LogEvent() {
+LogEvent::LogEvent(int32_t tagId, uint64_t timestampNs) {
+    mTimestampNs = timestampNs;
+    mTagId = tagId;
+    mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
+    if (mContext) {
+        android_log_write_int32(mContext, tagId);
+    }
 }
 
 void LogEvent::init() {
-    mList.convert_to_reader();
-    init(mTimestampNs, &mList);
+    if (mContext) {
+        const char* buffer;
+        size_t len = android_log_write_list_buffer(mContext, &buffer);
+        // turns to reader mode
+        mContext = create_android_log_parser(buffer, len);
+        init(mContext);
+    }
+}
+
+bool LogEvent::write(int32_t value) {
+    if (mContext) {
+        return android_log_write_int32(mContext, value) >= 0;
+    }
+    return false;
+}
+
+bool LogEvent::write(uint32_t value) {
+    if (mContext) {
+        return android_log_write_int32(mContext, value) >= 0;
+    }
+    return false;
+}
+
+bool LogEvent::write(uint64_t value) {
+    if (mContext) {
+        return android_log_write_int64(mContext, value) >= 0;
+    }
+    return false;
+}
+
+bool LogEvent::write(const string& value) {
+    if (mContext) {
+        return android_log_write_string8_len(mContext, value.c_str(), value.length()) >= 0;
+    }
+    return false;
+}
+
+bool LogEvent::write(float value) {
+    if (mContext) {
+        return android_log_write_float32(mContext, value) >= 0;
+    }
+    return false;
+}
+
+LogEvent::~LogEvent() {
+    if (mContext) {
+        android_log_destroy(&mContext);
+    }
 }
 
 /**
@@ -51,22 +102,25 @@
  * The goal is to do as little preprocessing as possible, because we read a tiny fraction
  * of the elements that are written to the log.
  */
-void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
-    mTimestampNs = timestampNs;
-    mTagId = reader->tag();
-
+void LogEvent::init(android_log_context context) {
     mElements.clear();
     android_log_list_element elem;
-
     // TODO: The log is actually structured inside one list.  This is convenient
     // because we'll be able to use it to put the attribution (WorkSource) block first
     // without doing our own tagging scheme.  Until that change is in, just drop the
     // list-related log elements and the order we get there is our index-keyed data
     // structure.
+    int i = 0;
     do {
-        elem = android_log_read_next(reader->context());
+        elem = android_log_read_next(context);
         switch ((int)elem.type) {
             case EVENT_TYPE_INT:
+                // elem at [0] is EVENT_TYPE_LIST, [1] is the tag id. If we add WorkSource, it would
+                // be the list starting at [2].
+                if (i == 1) {
+                    mTagId = elem.data.int32;
+                    break;
+                }
             case EVENT_TYPE_FLOAT:
             case EVENT_TYPE_STRING:
             case EVENT_TYPE_LONG:
@@ -81,13 +135,10 @@
             default:
                 break;
         }
+        i++;
     } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
 }
 
-android_log_event_list* LogEvent::GetAndroidLogEventList() {
-    return &mList;
-}
-
 int64_t LogEvent::GetLong(size_t key, status_t* err) const {
     if (key < 1 || (key - 1)  >= mElements.size()) {
         *err = BAD_INDEX;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 2984940..7e8a96b 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -21,6 +21,7 @@
 #include <android/util/ProtoOutputStream.h>
 #include <log/log_event_list.h>
 #include <log/log_read.h>
+#include <private/android_logger.h>
 #include <utils/Errors.h>
 
 #include <memory>
@@ -45,12 +46,9 @@
     explicit LogEvent(log_msg& msg);
 
     /**
-     * Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
-     * mode. Obtain this list with the getter. Make sure to call init() before attempting to read
-     * any of the values. This constructor is useful for unit-testing since we can't pass in an
-     * android_log_event_list since there is no copy constructor or assignment operator available.
+     * Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
      */
-    explicit LogEvent(int tag, uint64_t timestampNs);
+    explicit LogEvent(int32_t tagId, uint64_t timestampNs);
 
     ~LogEvent();
 
@@ -76,6 +74,17 @@
     float GetFloat(size_t key, status_t* err) const;
 
     /**
+     * Write test data to the LogEvent. This can only be used when the LogEvent is constructed
+     * using LogEvent(tagId, timestampNs). You need to call init() before you can read from it.
+     */
+    bool write(uint32_t value);
+    bool write(int32_t value);
+    bool write(uint64_t value);
+    bool write(int64_t value);
+    bool write(const string& value);
+    bool write(float value);
+
+    /**
      * Return a string representation of this event.
      */
     string ToString() const;
@@ -91,13 +100,6 @@
     KeyValuePair GetKeyValueProto(size_t key) const;
 
     /**
-     * A pointer to the contained log_event_list.
-     *
-     * @return The android_log_event_list contained within.
-     */
-    android_log_event_list* GetAndroidLogEventList();
-
-    /**
      * Used with the constructor where tag is passed in. Converts the log_event_list to read mode
      * and prepares the list for reading.
      */
@@ -113,16 +115,11 @@
     /**
      * Parses a log_msg into a LogEvent object.
      */
-    void init(const log_msg& msg);
-
-    /**
-     * Parses a log_msg into a LogEvent object.
-     */
-    void init(int64_t timestampNs, android_log_event_list* reader);
+    void init(android_log_context context);
 
     vector<android_log_list_element> mElements;
-    // Need a copy of the android_log_event_list so the strings are not cleared.
-    android_log_event_list mList;
+
+    android_log_context mContext;
 
     uint64_t mTimestampNs;
 
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a740280..41b24bc 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index cccc9b3..255165c 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -112,6 +112,7 @@
             if (err == NO_ERROR && val != NULL) {
                 if (!(cur.eq_string() == val)) {
                     allMatched = false;
+                    break;
                 }
             }
         } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt ||
@@ -126,26 +127,30 @@
                 if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt) {
                     if (!(val == cur.eq_int())) {
                         allMatched = false;
+                        break;
                     }
                 } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt) {
                     if (!(val < cur.lt_int())) {
                         allMatched = false;
+                        break;
                     }
                 } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtInt) {
                     if (!(val > cur.gt_int())) {
                         allMatched = false;
+                        break;
                     }
                 } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLteInt) {
                     if (!(val <= cur.lte_int())) {
                         allMatched = false;
+                        break;
                     }
                 } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGteInt) {
                     if (!(val >= cur.gte_int())) {
                         allMatched = false;
+                        break;
                     }
                 }
             }
-            break;
         } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) {
             // Boolean fields
             status_t err = NO_ERROR;
@@ -153,21 +158,24 @@
             if (err == NO_ERROR) {
                 if (!(cur.eq_bool() == val)) {
                     allMatched = false;
+                    break;
                 }
             }
         } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat ||
                    matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
             // Float fields
             status_t err = NO_ERROR;
-            bool val = event.GetFloat(key, &err);
+            float val = event.GetFloat(key, &err);
             if (err == NO_ERROR) {
                 if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat) {
-                    if (!(cur.lt_float() <= val)) {
+                    if (!(val < cur.lt_float())) {
                         allMatched = false;
+                        break;
                     }
                 } else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
-                    if (!(cur.gt_float() >= val)) {
+                    if (!(val > cur.gt_float())) {
                         allMatched = false;
+                        break;
                     }
                 }
             }
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index aaf3ec2..de6f365 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -233,10 +233,12 @@
     }
 
     VLOG("flushing...........");
-    for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end(); ++it) {
+    for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end();) {
         if (it->second->flushIfNeeded(eventTime)) {
             VLOG("erase bucket for key %s", it->first.c_str());
-            mCurrentSlicedDuration.erase(it);
+            it = mCurrentSlicedDuration.erase(it);
+        } else {
+            ++it;
         }
     }
 
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index c2044d8..4c63b20 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -220,6 +220,11 @@
             handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
                                        metric.links(), allConditionTrackers, conditionIndex,
                                        conditionToMetricMap);
+        } else {
+            if (metric.links_size() > 0) {
+                ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+                return false;
+            }
         }
 
         sp<MetricProducer> countProducer =
@@ -276,10 +281,15 @@
 
         int conditionIndex = -1;
 
-        if (metric.has_predicate()) {
-            handleMetricWithConditions(metric.predicate(), metricIndex, conditionTrackerMap,
+        if (metric.has_condition()) {
+            handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
                                        metric.links(), allConditionTrackers, conditionIndex,
                                        conditionToMetricMap);
+        } else {
+            if (metric.links_size() > 0) {
+                ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+                return false;
+            }
         }
 
         sp<MetricProducer> durationMetric = new DurationMetricProducer(
@@ -308,6 +318,11 @@
             handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
                                        metric.links(), allConditionTrackers, conditionIndex,
                                        conditionToMetricMap);
+        } else {
+            if (metric.links_size() > 0) {
+                ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+                return false;
+            }
         }
 
         sp<MetricProducer> eventMetric =
@@ -349,6 +364,11 @@
             handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
                                        metric.links(), allConditionTrackers, conditionIndex,
                                        conditionToMetricMap);
+        } else {
+            if (metric.links_size() > 0) {
+                ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+                return false;
+            }
         }
 
         sp<MetricProducer> valueProducer =
@@ -389,6 +409,11 @@
             handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
                                        metric.links(), allConditionTrackers, conditionIndex,
                                        conditionToMetricMap);
+        } else {
+            if (metric.links_size() > 0) {
+                ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+                return false;
+            }
         }
 
         sp<MetricProducer> gaugeProducer =
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 13e776f..5aa3db5 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 2398814..6c32d3e 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, versionCode 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index de68fbc..24eb966 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 7648a91..9a760b1 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -161,20 +161,20 @@
 
     optional string what = 2;
 
+    optional string condition = 3;
+
+    repeated EventConditionLink links = 4;
+
     enum AggregationType {
         DURATION_SUM = 1;
 
         DURATION_MAX_SPARSE = 2;
-  }
-  optional AggregationType type = 3;
+    }
+    optional AggregationType type = 5;
 
-  optional string predicate = 4;
+    repeated KeyMatcher dimension = 6;
 
-  repeated KeyMatcher dimension = 5;
-
-  optional Bucket bucket = 6;
-
-  repeated EventConditionLink links = 7;
+    optional Bucket bucket = 7;
 }
 
 message GaugeMetric {
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index d0898b0..40c0e9d 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -27,7 +27,7 @@
 using std::unordered_map;
 using std::vector;
 
-const int TAG_ID = 123;
+const int32_t TAG_ID = 123;
 const int FIELD_ID_1 = 1;
 const int FIELD_ID_2 = 2;
 const int FIELD_ID_3 = 2;
@@ -43,8 +43,6 @@
     simpleMatcher->set_tag(TAG_ID);
 
     LogEvent event(TAG_ID, 0);
-
-    // Convert to a LogEvent
     event.init();
 
     // Test
@@ -63,10 +61,8 @@
 
     // Set up the event
     LogEvent event(TAG_ID, 0);
-    auto list = event.GetAndroidLogEventList();
-    *list << true;
-    *list << false;
-
+    event.write(true);
+    event.write(false);
     // Convert to a LogEvent
     event.init();
 
@@ -99,9 +95,7 @@
 
     // Set up the event
     LogEvent event(TAG_ID, 0);
-    auto list = event.GetAndroidLogEventList();
-    *list << "some value";
-
+    event.write("some value");
     // Convert to a LogEvent
     event.init();
 
@@ -109,6 +103,38 @@
     EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
 }
 
+TEST(LogEntryMatcherTest, TestMultiFieldsMatcher) {
+    // Set up the matcher
+    LogEntryMatcher matcher;
+    auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+    simpleMatcher->set_tag(TAG_ID);
+    auto keyValue1 = simpleMatcher->add_key_value_matcher();
+    keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
+    auto keyValue2 = simpleMatcher->add_key_value_matcher();
+    keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
+
+    // Set up the event
+    LogEvent event(TAG_ID, 0);
+    event.write(2);
+    event.write(3);
+
+    // Convert to a LogEvent
+    event.init();
+
+    // Test
+    keyValue1->set_eq_int(2);
+    keyValue2->set_eq_int(3);
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+
+    keyValue1->set_eq_int(2);
+    keyValue2->set_eq_int(4);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+    keyValue1->set_eq_int(4);
+    keyValue2->set_eq_int(3);
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+}
+
 TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
@@ -120,9 +146,7 @@
 
     // Set up the event
     LogEvent event(TAG_ID, 0);
-    auto list = event.GetAndroidLogEventList();
-    *list << 11;
-
+    event.write(11);
     event.init();
 
     // Test
@@ -168,8 +192,6 @@
     EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
 }
 
-#if 0
-
 TEST(LogEntryMatcherTest, TestFloatComparisonMatcher) {
     // Set up the matcher
     LogEntryMatcher matcher;
@@ -179,22 +201,28 @@
     auto keyValue = simpleMatcher->add_key_value_matcher();
     keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
 
-    LogEvent event;
-    event.tagId = TAG_ID;
-
+    LogEvent event1(TAG_ID, 0);
     keyValue->set_lt_float(10.0);
-    event.floatMap[FIELD_ID_1] = 10.1;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
-    event.floatMap[FIELD_ID_1] = 9.9;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+    event1.write(10.1f);
+    event1.init();
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event1));
 
+    LogEvent event2(TAG_ID, 0);
+    event2.write(9.9f);
+    event2.init();
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event2));
+
+    LogEvent event3(TAG_ID, 0);
+    event3.write(10.1f);
+    event3.init();
     keyValue->set_gt_float(10.0);
-    event.floatMap[FIELD_ID_1] = 10.1;
-    EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
-    event.floatMap[FIELD_ID_1] = 9.9;
-    EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+    EXPECT_TRUE(matchesSimple(*simpleMatcher, event3));
+
+    LogEvent event4(TAG_ID, 0);
+    event4.write(9.9f);
+    event4.init();
+    EXPECT_FALSE(matchesSimple(*simpleMatcher, event4));
 }
-#endif
 
 // Helper for the composite matchers.
 void addSimpleMatcher(SimpleLogEntryMatcher* simpleMatcher, int tag, int key, int val) {
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index c64719e..4c12b03 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -36,10 +36,9 @@
     sp<UidMap> m = new UidMap();
     StatsLogProcessor p(m, nullptr);
     LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
-    android_log_event_list* list = addEvent.GetAndroidLogEventList();
-    *list << 100;  // parent UID
-    *list << 101;  // isolated UID
-    *list << 1;    // Indicates creation.
+    addEvent.write(100);  // parent UID
+    addEvent.write(101);  // isolated UID
+    addEvent.write(1);    // Indicates creation.
     addEvent.init();
 
     EXPECT_EQ(101, m->getParentUidOrSelf(101));
@@ -48,10 +47,9 @@
     EXPECT_EQ(100, m->getParentUidOrSelf(101));
 
     LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
-    list = removeEvent.GetAndroidLogEventList();
-    *list << 100;  // parent UID
-    *list << 101;  // isolated UID
-    *list << 0;    // Indicates removal.
+    removeEvent.write(100);  // parent UID
+    removeEvent.write(101);  // isolated UID
+    removeEvent.write(0);    // Indicates removal.
     removeEvent.init();
     p.OnLogEvent(removeEvent);
     EXPECT_EQ(101, m->getParentUidOrSelf(101));
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 05aad29..80a0068 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -46,10 +46,9 @@
 }
 
 void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
-    auto list = event->GetAndroidLogEventList();
-    *list << uid;  // uid
-    *list << wl;
-    *list << acquire;
+    event->write(uid);  // uid
+    event->write(wl);
+    event->write(acquire);
     event->init();
 }
 
@@ -108,6 +107,18 @@
     EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
     EXPECT_TRUE(changedCache[0]);
 
+    // match nothing.
+    matcherState.clear();
+    matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
+    conditionCache[0] = ConditionState::kNotEvaluated;
+    changedCache[0] = false;
+
+    conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+                                       changedCache);
+    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+    EXPECT_FALSE(changedCache[0]);
+
     // the case for match stop.
     matcherState.clear();
     matcherState.push_back(MatchingState::kNotMatched);
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index d07a84d..b7c9b40 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -138,15 +138,13 @@
     link->add_key_in_condition()->set_key(2);
 
     LogEvent event1(1, bucketStartTimeNs + 1);
-    auto list = event1.GetAndroidLogEventList();
-    *list << "111";  // uid
+    event1.write("111");  // uid
     event1.init();
     ConditionKey key1;
     key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
 
     LogEvent event2(1, bucketStartTimeNs + 10);
-    auto list2 = event2.GetAndroidLogEventList();
-    *list2 << "222";  // uid
+    event2.write("222");  // uid
     event2.init();
     ConditionKey key2;
     key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0971d26..18d177c 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -95,15 +95,13 @@
     link->add_key_in_condition()->set_key(2);
 
     LogEvent event1(1, bucketStartTimeNs + 1);
-    auto list = event1.GetAndroidLogEventList();
-    *list << "111";  // uid
+    event1.write("111");  // uid
     event1.init();
     ConditionKey key1;
     key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
 
     LogEvent event2(1, bucketStartTimeNs + 10);
-    auto list2 = event2.GetAndroidLogEventList();
-    *list2 << "222";  // uid
+    event2.write("222");  // uid
     event2.init();
     ConditionKey key2;
     key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 72b4194..cd647cb 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -64,9 +64,8 @@
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-    auto list = event->GetAndroidLogEventList();
-    *list << 1;
-    *list << 11;
+    event->write(1);
+    event->write(11);
     event->init();
     allData.push_back(event);
 
@@ -89,9 +88,8 @@
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-    list = event->GetAndroidLogEventList();
-    *list << 1;
-    *list << 22;
+    event->write(1);
+    event->write(22);
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData);
@@ -110,9 +108,8 @@
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-    list = event->GetAndroidLogEventList();
-    *list << 1;
-    *list << 33;
+    event->write(1);
+    event->write(33);
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData);
@@ -159,9 +156,8 @@
         int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
         data->clear();
         shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-        auto list = event->GetAndroidLogEventList();
-        *list << 1;
-        *list << 100;
+        event->write(1);
+        event->write(100);
         event->init();
         data->push_back(event);
         return true;
@@ -174,9 +170,8 @@
         int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
         data->clear();
         shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-        auto list = event->GetAndroidLogEventList();
-        *list << 1;
-        *list << 120;
+        event->write(1);
+        event->write(120);
         event->init();
         data->push_back(event);
         return true;
@@ -201,9 +196,8 @@
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-    auto list = event->GetAndroidLogEventList();
-    *list << 1;
-    *list << 110;
+    event->write(1);
+    event->write(110);
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData);
@@ -253,14 +247,12 @@
                                       bucketStartTimeNs, pullerManager);
 
     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-    auto list = event1->GetAndroidLogEventList();
-    *list << 1;
-    *list << 10;
+    event1->write(1);
+    event1->write(10);
     event1->init();
     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-    auto list2 = event2->GetAndroidLogEventList();
-    *list2 << 1;
-    *list2 << 20;
+    event2->write(1);
+    event2->write(20);
     event2->init();
     valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1, false);
     // has one slice
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ee89ca8..cc95eb6 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -254,6 +254,11 @@
     HashMap<String, PropertyValuesHolder> mValuesMap;
 
     /**
+     * If set to non-negative value, this will override {@link #sDurationScale}.
+     */
+    private float mDurationScale = -1f;
+
+    /**
      * Public constants
      */
 
@@ -579,8 +584,23 @@
         return this;
     }
 
+    /**
+     * Overrides the global duration scale by a custom value.
+     *
+     * @param durationScale The duration scale to set; or {@code -1f} to use the global duration
+     *                      scale.
+     * @hide
+     */
+    public void overrideDurationScale(float durationScale) {
+        mDurationScale = durationScale;
+    }
+
+    private float resolveDurationScale() {
+        return mDurationScale >= 0f ? mDurationScale : sDurationScale;
+    }
+
     private long getScaledDuration() {
-        return (long)(mDuration * sDurationScale);
+        return (long)(mDuration * resolveDurationScale());
     }
 
     /**
@@ -735,7 +755,10 @@
         if (mSeekFraction >= 0) {
             return (long) (mDuration * mSeekFraction);
         }
-        float durationScale = sDurationScale == 0 ? 1 : sDurationScale;
+        float durationScale = resolveDurationScale();
+        if (durationScale == 0f) {
+            durationScale = 1f;
+        }
         return (long) ((AnimationUtils.currentAnimationTimeMillis() - mStartTime) / durationScale);
     }
 
@@ -1397,7 +1420,9 @@
         if (mStartTime < 0) {
             // First frame. If there is start delay, start delay count down will happen *after* this
             // frame.
-            mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale);
+            mStartTime = mReversing
+                    ? frameTime
+                    : frameTime + (long) (mStartDelay * resolveDurationScale());
         }
 
         // Handle pause/resume
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99f3dee..03a3631 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4379,7 +4379,7 @@
             throw new IllegalArgumentException("requestCode should be >= 0");
         }
         if (mHasCurrentPermissionsRequest) {
-            Log.w(TAG, "Can reqeust only one set of permissions at a time");
+            Log.w(TAG, "Can request only one set of permissions at a time");
             // Dispatch the callback with empty arrays which means a cancellation.
             onRequestPermissionsResult(requestCode, new String[0], new int[0]);
             return;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 21e454f..95c5fb5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5380,7 +5380,7 @@
             }
         }
 
-        GraphicsEnvironment.chooseDriver(context);
+        GraphicsEnvironment.getInstance().setup(context);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index b7c1f4e..7257044 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -17,9 +17,12 @@
 package android.app;
 
 import android.os.Build;
+import android.os.GraphicsEnvironment;
 import android.os.Trace;
 import android.util.ArrayMap;
+
 import com.android.internal.os.ClassLoaderFactory;
+
 import dalvik.system.PathClassLoader;
 
 /** @hide */
@@ -72,8 +75,9 @@
 
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
-                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath");
-                setupVulkanLayerPath(classloader, librarySearchPath);
+                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths");
+                GraphicsEnvironment.getInstance().setLayerPaths(
+                        classloader, librarySearchPath, libraryPermittedPath);
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
                 mLoaders.put(cacheKey, classloader);
@@ -105,8 +109,6 @@
                               cacheKey, null /* classLoaderName */);
     }
 
-    private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath);
-
     /**
      * Adds a new path the classpath of the given loader.
      * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0eafdec..7a4c00f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -35,7 +35,6 @@
 import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
@@ -1681,21 +1680,8 @@
     }
 
     @Override
-    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
-                               String installerPackageName) {
-        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackage(Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName) {
-        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
-    }
-
-    private void installCommon(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            int userId) {
+    public void installPackage(Uri packageURI,
+            PackageInstallObserver observer, int flags, String installerPackageName) {
         if (!"file".equals(packageURI.getScheme())) {
             throw new UnsupportedOperationException("Only file:// URIs are supported");
         }
@@ -1703,7 +1689,7 @@
         final String originPath = packageURI.getPath();
         try {
             mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
-                    userId);
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index bbc90c8..4fc649e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -22,6 +22,7 @@
 import android.app.IApplicationThread;
 import android.app.IActivityController;
 import android.app.IAppTask;
+import android.app.IAssistDataReceiver;
 import android.app.IInstrumentationWatcher;
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
@@ -63,7 +64,6 @@
 import android.os.PersistableBundle;
 import android.os.StrictMode;
 import android.service.voice.IVoiceInteractionSession;
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -423,7 +423,7 @@
     int startAssistantActivity(in String callingPackage, int callingPid, int callingUid,
             in Intent intent, in String resolvedType, in Bundle options, int userId);
     int startRecentsActivity(in IAssistDataReceiver assistDataReceiver, in Bundle options,
-            int userId);
+            in Bundle activityOptions, int userId);
     int startActivityFromRecents(int taskId, in Bundle options);
     Bundle getActivityOptions(in IBinder token);
     List<IBinder> getAppTasks(in String callingPackage);
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/core/java/android/app/IAssistDataReceiver.aidl
similarity index 95%
rename from core/java/com/android/internal/app/IAssistDataReceiver.aidl
rename to core/java/android/app/IAssistDataReceiver.aidl
index 9c9ffef..2d5daf9 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/core/java/android/app/IAssistDataReceiver.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.app;
+package android.app;
 
 import android.graphics.Bitmap;
 import android.os.Bundle;
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 0d7a941..8200414 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -100,6 +100,12 @@
          */
         public static final int CHOOSER_ACTION = 9;
 
+        /**
+         * An event type denoting that a notification was viewed by the user.
+         * @hide
+         */
+        public static final int NOTIFICATION_SEEN = 10;
+
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
 
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index e3d763a..6692e13 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -350,13 +350,22 @@
      * application can be registered at time. When no longer used, application
      * should be unregistered using
      * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+     * The registration status should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
+     * to the return value of this method.
      *
      * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
+     * The HID Device SDP record is required.
      * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
+     * The Incoming QoS Settings is not required. Use null or default
+     * BluetoothHidDeviceAppQosSettings.Builder for default values.
      * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings.
+     * The Outgoing QoS Settings is not required. Use null or default
+     * BluetoothHidDeviceAppQosSettings.Builder for default values.
      * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
      * sent.
-     * @return
+     * The BluetoothHidDeviceCallback object is required.
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
             BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
@@ -394,12 +403,15 @@
      * {@link #registerApp
      * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
      * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)}
+     * The registration status should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
+     * to the return value of this method.
      *
      * @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
      * BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
      * BluetoothHidDeviceAppConfiguration,
      * boolean)}
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
         Log.v(TAG, "unregisterApp()");
@@ -426,7 +438,7 @@
      * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
      * descriptor.
      * @param data Report data, not including Report Id.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
         boolean result = false;
@@ -452,7 +464,7 @@
      * @param type Report Type, as in request.
      * @param id Report Id, as in request.
      * @param data Report data, not including Report Id.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
         Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
@@ -478,7 +490,7 @@
      * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
      *
      * @param error Error to be sent for SET_REPORT via HANDSHAKE.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean reportError(BluetoothDevice device, byte error) {
         Log.v(TAG, "reportError(): device=" + device + " error=" + error);
@@ -524,10 +536,13 @@
     }
 
     /**
-     * Initiates connection to host which currently has Virtual Cable
-     * established with device.
+     * Initiates connection to host which is currently paired with this device.
+     * If the application is not registered, #connect(BluetoothDevice) will fail.
+     * The connection state should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
+     * to the return value of this method.
      *
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean connect(BluetoothDevice device) {
         Log.v(TAG, "connect(): device=" + device);
@@ -550,8 +565,11 @@
 
     /**
      * Disconnects from currently connected host.
+     * The connection state should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
+     * to the return value of this method.
      *
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean disconnect(BluetoothDevice device) {
         Log.v(TAG, "disconnect(): device=" + device);
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index ccc3ef4..881ae98 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -45,6 +45,21 @@
 
     public static final int MAX = (int) 0xffffffff;
 
+    /**
+     * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
+     * The QoS Settings is optional.
+     * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
+     * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
+     *     https://www.bluetooth.com/specifications/profiles-overview
+     *     </a>
+     *     Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+     * @param serviceType L2CAP service type
+     * @param tokenRate L2CAP token rate
+     * @param tokenBucketSize L2CAP token bucket size
+     * @param peakBandwidth L2CAP peak bandwidth
+     * @param latency L2CAP latency
+     * @param delayVariation L2CAP delay variation
+     */
     public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
             int peakBandwidth, int latency, int delayVariation) {
         this.serviceType = serviceType;
@@ -59,7 +74,12 @@
     public boolean equals(Object o) {
         if (o instanceof BluetoothHidDeviceAppQosSettings) {
             BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
-            return false;
+            return this.serviceType == qos.serviceType
+                    && this.tokenRate == qos.tokenRate
+                    && this.tokenBucketSize == qos.tokenBucketSize
+                    && this.peakBandwidth == qos.peakBandwidth
+                    && this.latency == qos.latency
+                    && this.delayVariation == qos.delayVariation;
         }
         return false;
     }
@@ -106,4 +126,85 @@
                 serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
         };
     }
+
+    /**
+     * A helper to build the BluetoothHidDeviceAppQosSettings object.
+     */
+    public static class Builder {
+        // Optional parameters - initialized to default values
+        private int mServiceType = SERVICE_BEST_EFFORT;
+        private int mTokenRate = 0;
+        private int mTokenBucketSize = 0;
+        private int mPeakBandwidth = 0;
+        private int mLatency = MAX;
+        private int mDelayVariation = MAX;
+
+        /**
+         * Set the service type.
+         * @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
+         * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
+         */
+        public Builder serviceType(int val) {
+            mServiceType = val;
+            return this;
+        }
+        /**
+         * Set the token rate.
+         * @param val token rate
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
+         */
+        public Builder tokenRate(int val) {
+            mTokenRate = val;
+            return this;
+        }
+
+        /**
+         * Set the bucket size.
+         * @param val bucket size
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
+         */
+        public Builder tokenBucketSize(int val) {
+            mTokenBucketSize = val;
+            return this;
+        }
+
+        /**
+         * Set the peak bandwidth.
+         * @param val peak bandwidth
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
+         */
+        public Builder peakBandwidth(int val) {
+            mPeakBandwidth = val;
+            return this;
+        }
+        /**
+         * Set the latency.
+         * @param val latency
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
+         */
+        public Builder latency(int val) {
+            mLatency = val;
+            return this;
+        }
+
+        /**
+         * Set the delay variation.
+         * @param val delay variation
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
+         */
+        public Builder delayVariation(int val) {
+            mDelayVariation = val;
+            return this;
+        }
+
+        /**
+         * Build the BluetoothHidDeviceAppQosSettings object.
+         * @return BluetoothHidDeviceAppQosSettings object with current settings.
+         */
+        public BluetoothHidDeviceAppQosSettings build() {
+            return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize,
+                    mPeakBandwidth, mLatency, mDelayVariation);
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index f01c493..4669637 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+
 /**
  * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
  * HID Device application.
@@ -39,6 +41,18 @@
     public final byte subclass;
     public final byte[] descriptors;
 
+    /**
+     * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+     * @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param subclass Subclass of this Bluetooth HID device.
+     * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+     *     www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
+     * @param descriptors Descriptors of this Bluetooth HID device.
+     * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+     *     www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
+     */
     public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
             byte subclass, byte[] descriptors) {
         this.name = name;
@@ -52,7 +66,11 @@
     public boolean equals(Object o) {
         if (o instanceof BluetoothHidDeviceAppSdpSettings) {
             BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
-            return false;
+            return this.name.equals(sdp.name)
+                    && this.description.equals(sdp.description)
+                    && this.provider.equals(sdp.provider)
+                    && this.subclass == sdp.subclass
+                    && Arrays.equals(this.descriptors, sdp.descriptors);
         }
         return false;
     }
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 4b09fed..d3652e8 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -30,6 +30,11 @@
  * when they are committed to storage.  Objects that are returned from the
  * various <code>get</code> methods must be treated as immutable by the application.
  *
+ * <p>Note: This class provides strong consistency guarantees. It is using expensive operations
+ * which might slow down an app. Frequently changing properties or properties where loss can be
+ * tolerated should use other mechanisms. For more details read the comments on
+ * {@link Editor#commit()} and {@link Editor#apply()}.
+ *
  * <p><em>Note: This class does not support use across multiple processes.</em>
  *
  * <div class="special reference">
diff --git a/core/java/android/content/pm/IPackageInstallObserver.aidl b/core/java/android/content/pm/IPackageInstallObserver.aidl
deleted file mode 100644
index 6133365..0000000
--- a/core/java/android/content/pm/IPackageInstallObserver.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.content.pm;
-
-/**
- * API for installation callbacks from the Package Manager.
- * @hide
- */
-oneway interface IPackageInstallObserver {
-    void packageInstalled(in String packageName, int returnCode);
-}
-
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 86288396..77c5743 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -81,6 +81,9 @@
  * <li>All APKs must have unique split names.
  * <li>All installations must contain a single base APK.
  * </ul>
+ * <p>
+ * The ApiDemos project contains examples of using this API:
+ * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
  */
 public class PackageInstaller {
     private static final String TAG = "PackageInstaller";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 31ca198..15ea4b5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -871,8 +871,8 @@
     public static final int INSTALL_REASON_USER = 4;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} on success.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * on success.
      *
      * @hide
      */
@@ -880,8 +880,8 @@
     public static final int INSTALL_SUCCEEDED = 1;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the package is already installed.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the package is already installed.
      *
      * @hide
      */
@@ -889,8 +889,8 @@
     public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the package archive file is invalid.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the package archive file is invalid.
      *
      * @hide
      */
@@ -898,8 +898,8 @@
     public static final int INSTALL_FAILED_INVALID_APK = -2;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the URI passed in is invalid.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the URI passed in is invalid.
      *
      * @hide
      */
@@ -907,9 +907,9 @@
     public static final int INSTALL_FAILED_INVALID_URI = -3;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the package manager service found that
-     * the device didn't have enough storage space to install the app.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the package manager service found that the device didn't have enough storage space to
+     * install the app.
      *
      * @hide
      */
@@ -917,9 +917,8 @@
     public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if a package is already installed with
-     * the same name.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if a package is already installed with the same name.
      *
      * @hide
      */
@@ -927,9 +926,8 @@
     public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the requested shared user does not
-     * exist.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the requested shared user does not exist.
      *
      * @hide
      */
@@ -937,10 +935,9 @@
     public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if a previously installed package of the
-     * same name has a different signature than the new package (and the old
-     * package's data was not removed).
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if a previously installed package of the same name has a different signature than the new
+     * package (and the old package's data was not removed).
      *
      * @hide
      */
@@ -948,10 +945,9 @@
     public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package is requested a shared
-     * user which is already installed on the device and does not have matching
-     * signature.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package is requested a shared user which is already installed on the device and
+     * does not have matching signature.
      *
      * @hide
      */
@@ -959,9 +955,8 @@
     public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package uses a shared library
-     * that is not available.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package uses a shared library that is not available.
      *
      * @hide
      */
@@ -969,9 +964,8 @@
     public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package uses a shared library
-     * that is not available.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package uses a shared library that is not available.
      *
      * @hide
      */
@@ -979,10 +973,9 @@
     public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package failed while
-     * optimizing and validating its dex files, either because there was not
-     * enough storage or the validation failed.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package failed while optimizing and validating its dex files, either because there
+     * was not enough storage or the validation failed.
      *
      * @hide
      */
@@ -990,9 +983,9 @@
     public static final int INSTALL_FAILED_DEXOPT = -11;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package failed because the
-     * current SDK version is older than that required by the package.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package failed because the current SDK version is older than that required by the
+     * package.
      *
      * @hide
      */
@@ -1000,10 +993,9 @@
     public static final int INSTALL_FAILED_OLDER_SDK = -12;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package failed because it
-     * contains a content provider with the same authority as a provider already
-     * installed in the system.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package failed because it contains a content provider with the same authority as a
+     * provider already installed in the system.
      *
      * @hide
      */
@@ -1011,9 +1003,9 @@
     public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package failed because the
-     * current SDK version is newer than that required by the package.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package failed because the current SDK version is newer than that required by the
+     * package.
      *
      * @hide
      */
@@ -1021,10 +1013,9 @@
     public static final int INSTALL_FAILED_NEWER_SDK = -14;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package failed because it has
-     * specified that it is a test-only package and the caller has not supplied
-     * the {@link #INSTALL_ALLOW_TEST} flag.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package failed because it has specified that it is a test-only package and the
+     * caller has not supplied the {@link #INSTALL_ALLOW_TEST} flag.
      *
      * @hide
      */
@@ -1032,9 +1023,9 @@
     public static final int INSTALL_FAILED_TEST_ONLY = -15;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the package being installed contains
-     * native code, but none that is compatible with the device's CPU_ABI.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the package being installed contains native code, but none that is compatible with the
+     * device's CPU_ABI.
      *
      * @hide
      */
@@ -1042,9 +1033,8 @@
     public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package uses a feature that is
-     * not available.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package uses a feature that is not available.
      *
      * @hide
      */
@@ -1053,9 +1043,9 @@
 
     // ------ Errors related to sdcard
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if a secure container mount point
-     * couldn't be accessed on external media.
+     * Installation return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if a secure container mount point couldn't be
+     * accessed on external media.
      *
      * @hide
      */
@@ -1063,9 +1053,8 @@
     public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package couldn't be installed
-     * in the specified install location.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package couldn't be installed in the specified install location.
      *
      * @hide
      */
@@ -1073,9 +1062,9 @@
     public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package couldn't be installed
-     * in the specified install location because the media is not available.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package couldn't be installed in the specified install location because the media
+     * is not available.
      *
      * @hide
      */
@@ -1083,9 +1072,8 @@
     public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package couldn't be installed
-     * because the verification timed out.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package couldn't be installed because the verification timed out.
      *
      * @hide
      */
@@ -1093,9 +1081,8 @@
     public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package couldn't be installed
-     * because the verification did not succeed.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package couldn't be installed because the verification did not succeed.
      *
      * @hide
      */
@@ -1103,9 +1090,8 @@
     public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the package changed from what the
-     * calling program expected.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the package changed from what the calling program expected.
      *
      * @hide
      */
@@ -1113,28 +1099,25 @@
     public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package is assigned a
-     * different UID than it previously held.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package is assigned a different UID than it previously held.
      *
      * @hide
      */
     public static final int INSTALL_FAILED_UID_CHANGED = -24;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package has an older version
-     * code than the currently installed package.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package has an older version code than the currently installed package.
      *
      * @hide
      */
     public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the old package has target SDK high
-     * enough to support runtime permission and the new package has target SDK
-     * low enough to not support runtime permissions.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the old package has target SDK high enough to support runtime permission and the new
+     * package has target SDK low enough to not support runtime permissions.
      *
      * @hide
      */
@@ -1142,9 +1125,8 @@
     public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;
 
     /**
-     * Installation return code: this is passed to the
-     * {@link IPackageInstallObserver} if the new package attempts to downgrade the
-     * target sandbox version of the app.
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package attempts to downgrade the target sandbox version of the app.
      *
      * @hide
      */
@@ -1152,9 +1134,9 @@
     public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser was given a path that is
-     * not a file, or does not end with the expected '.apk' extension.
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser was given a path that is not a
+     * file, or does not end with the expected '.apk' extension.
      *
      * @hide
      */
@@ -1162,8 +1144,8 @@
     public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser was unable to retrieve the
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser was unable to retrieve the
      * AndroidManifest.xml file.
      *
      * @hide
@@ -1172,8 +1154,8 @@
     public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser encountered an unexpected
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser encountered an unexpected
      * exception.
      *
      * @hide
@@ -1182,9 +1164,9 @@
     public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser did not find any
-     * certificates in the .apk.
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser did not find any certificates in
+     * the .apk.
      *
      * @hide
      */
@@ -1192,9 +1174,9 @@
     public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser found inconsistent
-     * certificates on the files in the .apk.
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser found inconsistent certificates on
+     * the files in the .apk.
      *
      * @hide
      */
@@ -1202,8 +1184,8 @@
     public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser encountered a
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser encountered a
      * CertificateEncodingException in one of the files in the .apk.
      *
      * @hide
@@ -1212,9 +1194,9 @@
     public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser encountered a bad or
-     * missing package name in the manifest.
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser encountered a bad or missing
+     * package name in the manifest.
      *
      * @hide
      */
@@ -1222,9 +1204,9 @@
     public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser encountered a bad shared
-     * user id name in the manifest.
+     * Installation parse return code: tthis is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser encountered a bad shared user id
+     * name in the manifest.
      *
      * @hide
      */
@@ -1232,8 +1214,8 @@
     public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser encountered some structural
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser encountered some structural
      * problem in the manifest.
      *
      * @hide
@@ -1242,9 +1224,9 @@
     public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
 
     /**
-     * Installation parse return code: this is passed to the
-     * {@link IPackageInstallObserver} if the parser did not find any actionable
-     * tags (instrumentation or application) in the manifest.
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser did not find any actionable tags
+     * (instrumentation or application) in the manifest.
      *
      * @hide
      */
@@ -1252,9 +1234,9 @@
     public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
 
     /**
-     * Installation failed return code: this is passed to the
-     * {@link IPackageInstallObserver} if the system failed to install the
-     * package because of system issues.
+     * Installation failed return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
+     * because of system issues.
      *
      * @hide
      */
@@ -1262,24 +1244,23 @@
     public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
 
     /**
-     * Installation failed return code: this is passed to the
-     * {@link IPackageInstallObserver} if the system failed to install the
-     * package because the user is restricted from installing apps.
+     * Installation failed return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
+     * because the user is restricted from installing apps.
      *
      * @hide
      */
     public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
 
     /**
-     * Installation failed return code: this is passed to the
-     * {@link IPackageInstallObserver} if the system failed to install the
-     * package because it is attempting to define a permission that is already
-     * defined by some existing package.
+     * Installation failed return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
+     * because it is attempting to define a permission that is already defined by some existing
+     * package.
      * <p>
-     * The package name of the app which has already defined the permission is
-     * passed to a {@link PackageInstallObserver}, if any, as the
-     * {@link #EXTRA_FAILURE_EXISTING_PACKAGE} string extra; and the name of the
-     * permission being redefined is passed in the
+     * The package name of the app which has already defined the permission is passed to a
+     * {@link PackageInstallObserver}, if any, as the {@link #EXTRA_FAILURE_EXISTING_PACKAGE} string
+     * extra; and the name of the permission being redefined is passed in the
      * {@link #EXTRA_FAILURE_EXISTING_PERMISSION} string extra.
      *
      * @hide
@@ -1287,10 +1268,9 @@
     public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
 
     /**
-     * Installation failed return code: this is passed to the
-     * {@link IPackageInstallObserver} if the system failed to install the
-     * package because its packaged native code did not match any of the ABIs
-     * supported by the system.
+     * Installation failed return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
+     * because its packaged native code did not match any of the ABIs supported by the system.
      *
      * @hide
      */
@@ -4718,16 +4698,6 @@
     @Deprecated
     public abstract void installPackage(
             Uri packageURI,
-            IPackageInstallObserver observer,
-            @InstallFlags int flags,
-            String installerPackageName);
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackage(
-            Uri packageURI,
             PackageInstallObserver observer,
             @InstallFlags int flags,
             String installerPackageName);
@@ -5743,25 +5713,6 @@
     }
 
     /** {@hide} */
-    public static class LegacyPackageInstallObserver extends PackageInstallObserver {
-        private final IPackageInstallObserver mLegacy;
-
-        public LegacyPackageInstallObserver(IPackageInstallObserver legacy) {
-            mLegacy = legacy;
-        }
-
-        @Override
-        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
-                Bundle extras) {
-            if (mLegacy == null) return;
-            try {
-                mLegacy.packageInstalled(basePackageName, returnCode);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    /** {@hide} */
     public static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
         private final IPackageDeleteObserver mLegacy;
 
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index d4699a8..49f357e 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -73,7 +73,7 @@
      *     {@link #onUpgrade} will be used to upgrade the database; if the database is
      *     newer, {@link #onDowngrade} will be used to downgrade the database
      */
-    public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
+    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
             @Nullable CursorFactory factory, int version) {
         this(context, name, factory, version, null);
     }
@@ -95,7 +95,7 @@
      * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
      * corruption, or null to use the default error handler.
      */
-    public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
+    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
             @Nullable CursorFactory factory, int version,
             @Nullable DatabaseErrorHandler errorHandler) {
         this(context, name, factory, version, 0, errorHandler);
@@ -116,7 +116,7 @@
      *        Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be
      *        set when the helper opens the database
      */
-    public SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version,
+    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
             @NonNull SQLiteDatabase.OpenParams openParams) {
         this(context, name, version, 0, openParams.toBuilder());
     }
@@ -144,7 +144,7 @@
      * @see #onUpgrade(SQLiteDatabase, int, int)
      * @hide
      */
-    public SQLiteOpenHelper(@NonNull Context context, @Nullable String name,
+    public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
             @Nullable CursorFactory factory, int version,
             int minimumSupportedVersion, @Nullable DatabaseErrorHandler errorHandler) {
         this(context, name, version, minimumSupportedVersion,
@@ -153,10 +153,9 @@
         mOpenParamsBuilder.setErrorHandler(errorHandler);
     }
 
-    private SQLiteOpenHelper(@NonNull Context context, @Nullable String name, int version,
+    private SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
             int minimumSupportedVersion,
             @NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
-        Preconditions.checkNotNull(context);
         Preconditions.checkNotNull(openParamsBuilder);
         if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 46ad3f0..3a3048e 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1280,11 +1280,11 @@
      * <ul>
      * <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
      *   Typically {@link android.graphics.ImageFormat#JPEG JPEG format}.</li>
-     * <li>Raw formats: {@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}, {@link android.graphics.ImageFormat#RAW10 RAW10}, or {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
-     * <li>Processed (but not-stalling): any non-RAW format without a stall duration.
-     *   Typically {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
-     *   {@link android.graphics.ImageFormat#NV21 NV21}, or
-     *   {@link android.graphics.ImageFormat#YV12 YV12}.</li>
+     * <li>Raw formats: {@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}, {@link android.graphics.ImageFormat#RAW10 RAW10}, or
+     *   {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
+     * <li>Processed (but not-stalling): any non-RAW format without a stall duration.  Typically
+     *   {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
+     *   {@link android.graphics.ImageFormat#NV21 NV21}, or {@link android.graphics.ImageFormat#YV12 YV12}.</li>
      * </ul>
      * <p><b>Range of valid values:</b><br></p>
      * <p>For processed (and stalling) format streams, &gt;= 1.</p>
@@ -1376,8 +1376,7 @@
      * CPU resources that will consume more power. The image format for this kind of an output stream can
      * be any non-<code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
      * <p>A processed and stalling format is defined as any non-RAW format with a stallDurations
-     * &gt; 0.  Typically only the {@link android.graphics.ImageFormat#JPEG JPEG format} is a
-     * stalling format.</p>
+     * &gt; 0.  Typically only the {@link android.graphics.ImageFormat#JPEG JPEG format} is a stalling format.</p>
      * <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
      * processed format -- it will return a non-0 value for a stalling stream.</p>
      * <p>LEGACY devices will support up to 1 processing/stalling stream.</p>
@@ -1535,8 +1534,7 @@
             new Key<int[]>("android.request.availableRequestKeys", int[].class);
 
     /**
-     * <p>A list of all keys that the camera device has available
-     * to use with {@link android.hardware.camera2.CaptureResult }.</p>
+     * <p>A list of all keys that the camera device has available to use with {@link android.hardware.camera2.CaptureResult }.</p>
      * <p>Attempting to get a key from a CaptureResult that is not
      * listed here will always return a <code>null</code> value. Getting a key from
      * a CaptureResult that is listed here will generally never return a <code>null</code>
@@ -1561,8 +1559,7 @@
             new Key<int[]>("android.request.availableResultKeys", int[].class);
 
     /**
-     * <p>A list of all keys that the camera device has available
-     * to use with {@link android.hardware.camera2.CameraCharacteristics }.</p>
+     * <p>A list of all keys that the camera device has available to use with {@link android.hardware.camera2.CameraCharacteristics }.</p>
      * <p>This entry follows the same rules as
      * android.request.availableResultKeys (except that it applies for
      * CameraCharacteristics instead of CaptureResult). See above for more
@@ -1843,8 +1840,6 @@
      * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
      * android.scaler.availableStallDurations for more details about
      * calculating the max frame rate.</p>
-     * <p>(Keep in sync with
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p>This key is available on all devices.</p>
      *
@@ -1905,14 +1900,13 @@
      * <ul>
      * <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li>
      * <li>{@link android.graphics.ImageFormat#RAW10 }</li>
+     * <li>{@link android.graphics.ImageFormat#RAW12 }</li>
      * </ul>
      * <p>All other formats may or may not have an allowed stall duration on
      * a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * for more details.</p>
      * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
      * calculating the max frame rate (absent stalls).</p>
-     * <p>(Keep up to date with
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } )</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p>This key is available on all devices.</p>
      *
@@ -2195,9 +2189,9 @@
      * the raw buffers produced by this sensor.</p>
      * <p>If a camera device supports raw sensor formats, either this or
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is the maximum dimensions for the raw
-     * output formats listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} (this depends on
-     * whether or not the image sensor returns buffers containing pixels that are not
-     * part of the active array region for blacklevel calibration or other purposes).</p>
+     * output formats listed in {@link android.hardware.camera2.params.StreamConfigurationMap }
+     * (this depends on whether or not the image sensor returns buffers containing pixels that
+     * are not part of the active array region for blacklevel calibration or other purposes).</p>
      * <p>Some parts of the full pixel array may not receive light from the scene,
      * or be otherwise inactive.  The {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} key
      * defines the rectangle of active pixels that will be included in processed image
@@ -2205,7 +2199,6 @@
      * <p><b>Units</b>: Pixels</p>
      * <p>This key is available on all devices.</p>
      *
-     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
@@ -2838,7 +2831,7 @@
      * <p>See the individual level enums for full descriptions of the supported capabilities.  The
      * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a
      * finer-grain level, if needed. In addition, many controls have their available settings or
-     * ranges defined in individual {@link android.hardware.camera2.CameraCharacteristics } entries.</p>
+     * ranges defined in individual entries from {@link android.hardware.camera2.CameraCharacteristics }.</p>
      * <p>Some features are not part of any particular hardware level or capability and must be
      * queried separately. These include:</p>
      * <ul>
@@ -2973,7 +2966,6 @@
      * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
      * android.scaler.availableStallDurations for more details about
      * calculating the max frame rate.</p>
-     * <p>(Keep in sync with {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
      * <p><b>Units</b>: (format, width, height, ns) x n</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 8c8c49f..4b57018 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -587,8 +587,8 @@
      * then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at
      * least one resolution &gt;= 8 megapixels, with a minimum frame duration of &lt;= 1/20
      * s.</p>
-     * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be captured at the same rate
-     * as the maximum-size YUV_420_888 resolution is.</p>
+     * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be
+     * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
      * <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees
      * as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p>
      * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is guaranted to have a value between 0
@@ -610,25 +610,22 @@
      * following:</p>
      * <ul>
      * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
-     * <li>{@link android.graphics.ImageFormat#YUV_420_888 } is supported as an output/input format, that is,
-     *   YUV_420_888 is included in the lists of formats returned by
-     *   {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and
-     *   {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
+     * <li>{@link android.graphics.ImageFormat#YUV_420_888 } is supported as an output/input
+     *   format, that is, YUV_420_888 is included in the lists of formats returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
      * <li>{@link android.hardware.camera2.params.StreamConfigurationMap#getValidOutputFormatsForInput }
      *   returns non-empty int[] for each supported input format returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats }.</li>
      * <li>Each size returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputSizes getInputSizes(YUV_420_888)} is also included in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes getOutputSizes(YUV_420_888)}</li>
-     * <li>Using {@link android.graphics.ImageFormat#YUV_420_888 } does not cause a frame rate drop
-     *   relative to the sensor's maximum capture rate (at that resolution).</li>
+     * <li>Using {@link android.graphics.ImageFormat#YUV_420_888 } does not cause a frame rate
+     *   drop relative to the sensor's maximum capture rate (at that resolution).</li>
      * <li>{@link android.graphics.ImageFormat#YUV_420_888 } will be reprocessable into both
      *   {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li>
      * <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the
      *   maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li>
      * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
      * <li>Only the below controls are effective for reprocessing requests and will be present
-     *   in capture results. The reprocess requests are from the original capture results that
-     *   are associated with the intermediate {@link android.graphics.ImageFormat#YUV_420_888 }
-     *   output buffers.  All other controls in the reprocess requests will be ignored by the
-     *   camera device.<ul>
+     *   in capture results. The reprocess requests are from the original capture results
+     *   that are associated with the intermediate {@link android.graphics.ImageFormat#YUV_420_888 } output buffers.  All other controls in the
+     *   reprocess requests will be ignored by the camera device.<ul>
      * <li>android.jpeg.*</li>
      * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
      * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
@@ -654,13 +651,13 @@
      * <p>The camera device can produce depth measurements from its field of view.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
-     * <li>{@link android.graphics.ImageFormat#DEPTH16 } is supported as an output format.</li>
-     * <li>{@link android.graphics.ImageFormat#DEPTH_POINT_CLOUD } is optionally supported as an
-     *   output format.</li>
-     * <li>This camera device, and all camera devices with the same {@link CameraCharacteristics#LENS_FACING android.lens.facing},
-     *   will list the following calibration entries in both
-     *   {@link android.hardware.camera2.CameraCharacteristics } and
-     *   {@link android.hardware.camera2.CaptureResult }:<ul>
+     * <li>{@link android.graphics.ImageFormat#DEPTH16 } is supported as
+     *   an output format.</li>
+     * <li>{@link android.graphics.ImageFormat#DEPTH_POINT_CLOUD } is
+     *   optionally supported as an output format.</li>
+     * <li>This camera device, and all camera devices with the same {@link CameraCharacteristics#LENS_FACING android.lens.facing}, will
+     *   list the following calibration metadata entries in both {@link android.hardware.camera2.CameraCharacteristics }
+     *   and {@link android.hardware.camera2.CaptureResult }:<ul>
      * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
      * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
      * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
@@ -674,8 +671,7 @@
      * </ul>
      * <p>Generally, depth output operates at a slower frame rate than standard color capture,
      * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
-     * should be accounted for (see
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }).
+     * should be accounted for (see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }).
      * On a device that supports both depth and color-based output, to enable smooth preview,
      * using a repeating burst is recommended, where a depth-output target is only included
      * once every N frames, where N is the ratio between preview output rate and depth output
@@ -692,23 +688,19 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
 
     /**
-     * <p>The device supports constrained high speed video recording (frame rate &gt;=120fps)
-     * use case. The camera device will support high speed capture session created by
-     * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which
-     * only accepts high speed request lists created by
-     * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.</p>
-     * <p>A camera device can still support high speed video streaming by advertising the high speed
-     * FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all normal
-     * capture request per frame control and synchronization requirements will apply to
-     * the high speed fps ranges, the same as all other fps ranges. This capability describes
-     * the capability of a specialized operating mode with many limitations (see below), which
-     * is only targeted at high speed video recording.</p>
-     * <p>The supported high speed video sizes and fps ranges are specified in
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.
-     * To get desired output frame rates, the application is only allowed to select video size
-     * and FPS range combinations provided by
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.
-     * The fps range can be controlled via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p>
+     * <p>The device supports constrained high speed video recording (frame rate &gt;=120fps) use
+     * case. The camera device will support high speed capture session created by {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which
+     * only accepts high speed request lists created by {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.</p>
+     * <p>A camera device can still support high speed video streaming by advertising the high
+     * speed FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all
+     * normal capture request per frame control and synchronization requirements will apply
+     * to the high speed fps ranges, the same as all other fps ranges. This capability
+     * describes the capability of a specialized operating mode with many limitations (see
+     * below), which is only targeted at high speed video recording.</p>
+     * <p>The supported high speed video sizes and fps ranges are specified in {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.
+     * To get desired output frame rates, the application is only allowed to select video
+     * size and FPS range combinations provided by {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.  The
+     * fps range can be controlled via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p>
      * <p>In this capability, the camera device will override aeMode, awbMode, and afMode to
      * ON, AUTO, and CONTINUOUS_VIDEO, respectively. All post-processing block mode
      * controls will be overridden to be FAST. Therefore, no manual control of capture
@@ -743,19 +735,16 @@
      * frame rate. If the destination surface is from preview window, the actual preview frame
      * rate will be bounded by the screen refresh rate.</p>
      * <p>The camera device will only support up to 2 high speed simultaneous output surfaces
-     * (preview and recording surfaces)
-     * in this mode. Above controls will be effective only if all of below conditions are true:</p>
+     * (preview and recording surfaces) in this mode. Above controls will be effective only
+     * if all of below conditions are true:</p>
      * <ul>
      * <li>The application creates a camera capture session with no more than 2 surfaces via
      * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }. The
-     * targeted surfaces must be preview surface (either from
-     * {@link android.view.SurfaceView } or {@link android.graphics.SurfaceTexture }) or
-     * recording surface(either from {@link android.media.MediaRecorder#getSurface } or
-     * {@link android.media.MediaCodec#createInputSurface }).</li>
+     * targeted surfaces must be preview surface (either from {@link android.view.SurfaceView } or {@link android.graphics.SurfaceTexture }) or recording
+     * surface(either from {@link android.media.MediaRecorder#getSurface } or {@link android.media.MediaCodec#createInputSurface }).</li>
      * <li>The stream sizes are selected from the sizes reported by
      * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.</li>
-     * <li>The FPS ranges are selected from
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li>
+     * <li>The FPS ranges are selected from {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li>
      * </ul>
      * <p>When above conditions are NOT satistied,
      * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }
@@ -1038,8 +1027,7 @@
 
     /**
      * <p>This camera device is running in backward compatibility mode.</p>
-     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
-     * documentation are supported.</p>
+     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are supported.</p>
      * <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
      * post-processing, arbitrary cropping regions, and has relaxed performance constraints.
      * No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -1061,8 +1049,7 @@
      * <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
      * FULL-level capabilities.</p>
      * <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
-     * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
-     * documentation are guaranteed to be supported.</p>
+     * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
      * <p>The following additional capabilities are guaranteed to be supported:</p>
      * <ul>
      * <li><code>YUV_REPROCESSING</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
@@ -2155,12 +2142,13 @@
     public static final int EDGE_MODE_HIGH_QUALITY = 2;
 
     /**
-     * <p>Edge enhancement is applied at different levels for different output streams,
-     * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession }) or below have
-     * edge enhancement applied, while higher-resolution streams have no edge enhancement
-     * applied. The level of edge enhancement for low-resolution streams is tuned so that
-     * frame rate is not impacted, and the quality is equal to or better than FAST (since it
-     * is only applied to lower-resolution outputs, quality may improve from FAST).</p>
+     * <p>Edge enhancement is applied at different
+     * levels for different output streams, based on resolution. Streams at maximum recording
+     * resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession })
+     * or below have edge enhancement applied, while higher-resolution streams have no edge
+     * enhancement applied. The level of edge enhancement for low-resolution streams is tuned
+     * so that frame rate is not impacted, and the quality is equal to or better than FAST
+     * (since it is only applied to lower-resolution outputs, quality may improve from FAST).</p>
      * <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
      * with YUV or PRIVATE reprocessing, where the application continuously captures
      * high-resolution intermediate buffers into a circular buffer, from which a final image is
@@ -2287,12 +2275,12 @@
 
     /**
      * <p>Noise reduction is applied at different levels for different output streams,
-     * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession }) or below have noise
-     * reduction applied, while higher-resolution streams have MINIMAL (if supported) or no
-     * noise reduction applied (if MINIMAL is not supported.) The degree of noise reduction
-     * for low-resolution streams is tuned so that frame rate is not impacted, and the quality
-     * is equal to or better than FAST (since it is only applied to lower-resolution outputs,
-     * quality may improve from FAST).</p>
+     * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession })
+     * or below have noise reduction applied, while higher-resolution streams have MINIMAL (if
+     * supported) or no noise reduction applied (if MINIMAL is not supported.) The degree of
+     * noise reduction for low-resolution streams is tuned so that frame rate is not impacted,
+     * and the quality is equal to or better than FAST (since it is only applied to
+     * lower-resolution outputs, quality may improve from FAST).</p>
      * <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
      * with YUV or PRIVATE reprocessing, where the application continuously captures
      * high-resolution intermediate buffers into a circular buffer, from which a final image is
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c41fc02..0262ecb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -680,7 +680,7 @@
      * FAST or HIGH_QUALITY will yield a picture with the same white point
      * as what was produced by the camera device in the earlier frame.</p>
      * <p>The expected processing pipeline is as follows:</p>
-     * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+     * <p><img alt="White balance processing pipeline" src="/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
      * <p>The white balance is encoded by two values, a 4-channel white-balance
      * gain vector (applied in the Bayer domain), and a 3x3 color transform
      * matrix (applied after demosaic).</p>
@@ -1470,10 +1470,10 @@
      * <p>When set to AUTO, the individual algorithm controls in
      * android.control.* are in effect, such as {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
      * <p>When set to USE_SCENE_MODE, the individual controls in
-     * android.control.* are mostly disabled, and the camera device implements
-     * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
-     * as it wishes. The camera device scene mode 3A settings are provided by
-     * {@link android.hardware.camera2.CaptureResult capture results}.</p>
+     * android.control.* are mostly disabled, and the camera device
+     * implements one of the scene mode settings (such as ACTION,
+     * SUNSET, or PARTY) as it wishes. The camera device scene mode
+     * 3A settings are provided by {@link android.hardware.camera2.CaptureResult capture results}.</p>
      * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
      * is that this frame will not be used by camera device background 3A statistics
      * update, as if this frame is never captured. This mode can be used in the scenario
@@ -2268,45 +2268,35 @@
      * can run concurrently to the rest of the camera pipeline, but
      * cannot process more than 1 capture at a time.</li>
      * </ul>
-     * <p>The necessary information for the application, given the model above,
-     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+     * <p>The necessary information for the application, given the model above, is provided via
      * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
-     * These are used to determine the maximum frame rate / minimum frame
-     * duration that is possible for a given stream configuration.</p>
+     * These are used to determine the maximum frame rate / minimum frame duration that is
+     * possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
      * determine the minimum frame duration it can request from the camera
      * device:</p>
      * <ol>
-     * <li>Let the set of currently configured input/output streams
-     * be called <code>S</code>.</li>
-     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
-     * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
-     * (with its respective size/format). Let this set of frame durations be
-     * called <code>F</code>.</li>
-     * <li>For any given request <code>R</code>, the minimum frame duration allowed
-     * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
-     * used in <code>R</code> be called <code>S_r</code>.</li>
+     * <li>Let the set of currently configured input/output streams be called <code>S</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking it up in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+     * (with its respective size/format). Let this set of frame durations be called <code>F</code>.</li>
+     * <li>For any given request <code>R</code>, the minimum frame duration allowed for <code>R</code> is the maximum
+     * out of all values in <code>F</code>. Let the streams used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
      * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
-     * using its respective size/format), then the frame duration in <code>F</code>
-     * determines the steady state frame rate that the application will get
-     * if it uses <code>R</code> as a repeating request. Let this special kind of
-     * request be called <code>Rsimple</code>.</p>
-     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
-     * by a single capture of a new request <code>Rstall</code> (which has at least
-     * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
-     * same minimum frame duration this will not cause a frame rate loss
-     * if all buffers from the previous <code>Rstall</code> have already been
-     * delivered.</p>
-     * <p>For more details about stalling, see
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
+     * using its respective size/format), then the frame duration in <code>F</code> determines the steady
+     * state frame rate that the application will get if it uses <code>R</code> as a repeating request. Let
+     * this special kind of request be called <code>Rsimple</code>.</p>
+     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved by a single capture of a
+     * new request <code>Rstall</code> (which has at least one in-use stream with a non-0 stall time) and if
+     * <code>Rstall</code> has the same minimum frame duration this will not cause a frame rate loss if all
+     * buffers from the previous <code>Rstall</code> have already been delivered.</p>
+     * <p>For more details about stalling, see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: Nanoseconds</p>
      * <p><b>Range of valid values:</b><br>
-     * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration},
-     * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}. The duration
-     * is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
+     * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}, {@link android.hardware.camera2.params.StreamConfigurationMap }.
+     * The duration is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2315,7 +2305,6 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
      */
     @PublicKey
@@ -2584,11 +2573,11 @@
      * <p>Linear mapping:</p>
      * <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
      * </code></pre>
-     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
      * <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
      * </code></pre>
-     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
      * <pre><code>android.tonemap.curveRed = [
      *   0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
@@ -2596,7 +2585,7 @@
      *   0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
      *   0.8000, 0.9035, 0.8667, 0.9370, 0.9333, 0.9691, 1.0000, 1.0000 ]
      * </code></pre>
-     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
      * <pre><code>android.tonemap.curveRed = [
      *   0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
@@ -2604,7 +2593,7 @@
      *   0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
      *   0.8000, 0.9063, 0.8667, 0.9389, 0.9333, 0.9701, 1.0000, 1.0000 ]
      * </code></pre>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p><b>Range of valid values:</b><br>
      * 0-1 on both input and output coordinates, normalized
      * as a floating-point value such that 0 == black and 1 == white.</p>
@@ -2646,11 +2635,11 @@
      * <p>Linear mapping:</p>
      * <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
      * </code></pre>
-     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
      * <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
      * </code></pre>
-     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
      * <pre><code>curveRed = [
      *   (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
@@ -2658,7 +2647,7 @@
      *   (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
      *   (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
      * </code></pre>
-     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
      * <pre><code>curveRed = [
      *   (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
@@ -2666,7 +2655,7 @@
      *   (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
      *   (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
      * </code></pre>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2756,9 +2745,9 @@
      * PRESET_CURVE</p>
      * <p>The tonemap curve will be defined by specified standard.</p>
      * <p>sRGB (approximated by 16 control points):</p>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p>Rec. 709 (approximated by 16 control points):</p>
-     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
      * <p>Note that above figures show a 16 control points approximation of preset
      * curves. Camera devices may apply a different approximation to the curve.</p>
      * <p><b>Possible values:</b>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 6d80c20..cfad098 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -390,7 +390,7 @@
      * FAST or HIGH_QUALITY will yield a picture with the same white point
      * as what was produced by the camera device in the earlier frame.</p>
      * <p>The expected processing pipeline is as follows:</p>
-     * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+     * <p><img alt="White balance processing pipeline" src="/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
      * <p>The white balance is encoded by two values, a 4-channel white-balance
      * gain vector (applied in the Bayer domain), and a 3x3 color transform
      * matrix (applied after demosaic).</p>
@@ -1975,10 +1975,10 @@
      * <p>When set to AUTO, the individual algorithm controls in
      * android.control.* are in effect, such as {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
      * <p>When set to USE_SCENE_MODE, the individual controls in
-     * android.control.* are mostly disabled, and the camera device implements
-     * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
-     * as it wishes. The camera device scene mode 3A settings are provided by
-     * {@link android.hardware.camera2.CaptureResult capture results}.</p>
+     * android.control.* are mostly disabled, and the camera device
+     * implements one of the scene mode settings (such as ACTION,
+     * SUNSET, or PARTY) as it wishes. The camera device scene mode
+     * 3A settings are provided by {@link android.hardware.camera2.CaptureResult capture results}.</p>
      * <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
      * is that this frame will not be used by camera device background 3A statistics
      * update, as if this frame is never captured. This mode can be used in the scenario
@@ -3108,45 +3108,35 @@
      * can run concurrently to the rest of the camera pipeline, but
      * cannot process more than 1 capture at a time.</li>
      * </ul>
-     * <p>The necessary information for the application, given the model above,
-     * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+     * <p>The necessary information for the application, given the model above, is provided via
      * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
-     * These are used to determine the maximum frame rate / minimum frame
-     * duration that is possible for a given stream configuration.</p>
+     * These are used to determine the maximum frame rate / minimum frame duration that is
+     * possible for a given stream configuration.</p>
      * <p>Specifically, the application can use the following rules to
      * determine the minimum frame duration it can request from the camera
      * device:</p>
      * <ol>
-     * <li>Let the set of currently configured input/output streams
-     * be called <code>S</code>.</li>
-     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
-     * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
-     * (with its respective size/format). Let this set of frame durations be
-     * called <code>F</code>.</li>
-     * <li>For any given request <code>R</code>, the minimum frame duration allowed
-     * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
-     * used in <code>R</code> be called <code>S_r</code>.</li>
+     * <li>Let the set of currently configured input/output streams be called <code>S</code>.</li>
+     * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking it up in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+     * (with its respective size/format). Let this set of frame durations be called <code>F</code>.</li>
+     * <li>For any given request <code>R</code>, the minimum frame duration allowed for <code>R</code> is the maximum
+     * out of all values in <code>F</code>. Let the streams used in <code>R</code> be called <code>S_r</code>.</li>
      * </ol>
      * <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
-     * using its respective size/format), then the frame duration in <code>F</code>
-     * determines the steady state frame rate that the application will get
-     * if it uses <code>R</code> as a repeating request. Let this special kind of
-     * request be called <code>Rsimple</code>.</p>
-     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
-     * by a single capture of a new request <code>Rstall</code> (which has at least
-     * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
-     * same minimum frame duration this will not cause a frame rate loss
-     * if all buffers from the previous <code>Rstall</code> have already been
-     * delivered.</p>
-     * <p>For more details about stalling, see
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
+     * using its respective size/format), then the frame duration in <code>F</code> determines the steady
+     * state frame rate that the application will get if it uses <code>R</code> as a repeating request. Let
+     * this special kind of request be called <code>Rsimple</code>.</p>
+     * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved by a single capture of a
+     * new request <code>Rstall</code> (which has at least one in-use stream with a non-0 stall time) and if
+     * <code>Rstall</code> has the same minimum frame duration this will not cause a frame rate loss if all
+     * buffers from the previous <code>Rstall</code> have already been delivered.</p>
+     * <p>For more details about stalling, see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: Nanoseconds</p>
      * <p><b>Range of valid values:</b><br>
-     * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration},
-     * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}. The duration
-     * is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
+     * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}, {@link android.hardware.camera2.params.StreamConfigurationMap }.
+     * The duration is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -3155,7 +3145,6 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
      * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
      */
     @PublicKey
@@ -3408,9 +3397,8 @@
      * layout key (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}), i.e. the
      * nth value given corresponds to the black level offset for the nth
      * color channel listed in the CFA.</p>
-     * <p>This key will be available if {@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions} is
-     * available or the camera device advertises this key via
-     * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
+     * <p>This key will be available if {@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions} is available or the
+     * camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
      * <p><b>Range of valid values:</b><br>
      * &gt;= 0 for each.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3640,13 +3628,13 @@
      * </code></pre>
      * <p>The low-resolution scaling map images for each channel are
      * (displayed using nearest-neighbor interpolation):</p>
-     * <p><img alt="Red lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
-     * <img alt="Green (even rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
-     * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
-     * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
+     * <p><img alt="Red lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
+     * <img alt="Green (even rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
+     * <img alt="Green (odd rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
+     * <img alt="Blue lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
      * <p>As a visualization only, inverting the full-color map to recover an
      * image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
-     * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     * <p><img alt="Image of a uniform white wall (inverse shading map)" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
      * <p><b>Range of valid values:</b><br>
      * Each gain factor is &gt;= 1</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3707,14 +3695,14 @@
      * </code></pre>
      * <p>The low-resolution scaling map images for each channel are
      * (displayed using nearest-neighbor interpolation):</p>
-     * <p><img alt="Red lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
-     * <img alt="Green (even rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
-     * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
-     * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
+     * <p><img alt="Red lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
+     * <img alt="Green (even rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
+     * <img alt="Green (odd rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
+     * <img alt="Blue lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
      * <p>As a visualization only, inverting the full-color map to recover an
      * image of a gray wall (using bicubic interpolation for visual quality)
      * as captured by the sensor gives:</p>
-     * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     * <p><img alt="Image of a uniform white wall (inverse shading map)" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
      * <p>Note that the RAW image data might be subject to lens shading
      * correction not reported on this map. Query
      * {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} to see if RAW image data has subject
@@ -3947,11 +3935,11 @@
      * <p>Linear mapping:</p>
      * <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
      * </code></pre>
-     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
      * <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
      * </code></pre>
-     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
      * <pre><code>android.tonemap.curveRed = [
      *   0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
@@ -3959,7 +3947,7 @@
      *   0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
      *   0.8000, 0.9035, 0.8667, 0.9370, 0.9333, 0.9691, 1.0000, 1.0000 ]
      * </code></pre>
-     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
      * <pre><code>android.tonemap.curveRed = [
      *   0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
@@ -3967,7 +3955,7 @@
      *   0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
      *   0.8000, 0.9063, 0.8667, 0.9389, 0.9333, 0.9701, 1.0000, 1.0000 ]
      * </code></pre>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p><b>Range of valid values:</b><br>
      * 0-1 on both input and output coordinates, normalized
      * as a floating-point value such that 0 == black and 1 == white.</p>
@@ -4009,11 +3997,11 @@
      * <p>Linear mapping:</p>
      * <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
      * </code></pre>
-     * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+     * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
      * <p>Invert mapping:</p>
      * <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
      * </code></pre>
-     * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+     * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
      * <p>Gamma 1/2.2 mapping, with 16 control points:</p>
      * <pre><code>curveRed = [
      *   (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
@@ -4021,7 +4009,7 @@
      *   (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
      *   (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
      * </code></pre>
-     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+     * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
      * <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
      * <pre><code>curveRed = [
      *   (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
@@ -4029,7 +4017,7 @@
      *   (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
      *   (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
      * </code></pre>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -4119,9 +4107,9 @@
      * PRESET_CURVE</p>
      * <p>The tonemap curve will be defined by specified standard.</p>
      * <p>sRGB (approximated by 16 control points):</p>
-     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
      * <p>Rec. 709 (approximated by 16 control points):</p>
-     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
      * <p>Note that above figures show a 16 control points approximation of preset
      * curves. Camera devices may apply a different approximation to the curve.</p>
      * <p><b>Possible values:</b>
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index aaf6c57..7fc7836 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -16,6 +16,7 @@
 package android.hardware.location;
 
 import android.annotation.SystemApi;
+import android.hardware.contexthub.V1_0.ContextHub;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -31,22 +32,53 @@
     private String mVendor;
     private String mToolchain;
     private int mPlatformVersion;
-    private int mStaticSwVersion;
     private int mToolchainVersion;
     private float mPeakMips;
     private float mStoppedPowerDrawMw;
     private float mSleepPowerDrawMw;
     private float mPeakPowerDrawMw;
     private int mMaxPacketLengthBytes;
+    private byte mChreApiMajorVersion;
+    private byte mChreApiMinorVersion;
+    private short mChrePatchVersion;
+    private long mChrePlatformId;
 
     private int[] mSupportedSensors;
 
     private MemoryRegion[] mMemoryRegions;
 
+    /*
+     * TODO(b/66965339): Deprecate this constructor and the setter methods, and mark private fields
+     * as final when the ContextHubService JNI code is removed.
+     */
     public ContextHubInfo() {
     }
 
     /**
+     * @hide
+     */
+    public ContextHubInfo(ContextHub contextHub) {
+        mId = contextHub.hubId;
+        mName = contextHub.name;
+        mVendor = contextHub.vendor;
+        mToolchain = contextHub.toolchain;
+        mPlatformVersion = contextHub.platformVersion;
+        mToolchainVersion = contextHub.toolchainVersion;
+        mPeakMips = contextHub.peakMips;
+        mStoppedPowerDrawMw = contextHub.stoppedPowerDrawMw;
+        mSleepPowerDrawMw = contextHub.sleepPowerDrawMw;
+        mPeakPowerDrawMw = contextHub.peakPowerDrawMw;
+        mMaxPacketLengthBytes = contextHub.maxSupportedMsgLen;
+        mChrePlatformId = contextHub.chrePlatformId;
+        mChreApiMajorVersion = contextHub.chreApiMajorVersion;
+        mChreApiMinorVersion = contextHub.chreApiMinorVersion;
+        mChrePatchVersion = contextHub.chrePatchVersion;
+
+        mSupportedSensors = new int[0];
+        mMemoryRegions = new MemoryRegion[0];
+    }
+
+    /**
      * returns the maximum number of bytes that can be sent per message to the hub
      *
      * @return int - maximum bytes that can be transmitted in a
@@ -173,7 +205,7 @@
      * @return int - platform version number
      */
     public int getStaticSwVersion() {
-        return mStaticSwVersion;
+        return (mChreApiMajorVersion << 24) | (mChreApiMinorVersion << 16) | (mChrePatchVersion);
     }
 
     /**
@@ -183,9 +215,7 @@
      *
      * @hide
      */
-    public void setStaticSwVersion(int staticSwVersion) {
-        mStaticSwVersion = staticSwVersion;
-    }
+    public void setStaticSwVersion(int staticSwVersion) {}
 
     /**
      * get the tool chain version
@@ -345,23 +375,66 @@
         mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
     }
 
+    /**
+     * @return the CHRE platform ID as defined in chre/version.h
+     *
+     * TODO(b/67734082): Expose as public API
+     * @hide
+     */
+    public long getChrePlatformId() {
+        return mChrePlatformId;
+    }
+
+    /**
+     * @return the CHRE API's major version as defined in chre/version.h
+     *
+     * TODO(b/67734082): Expose as public API
+     * @hide
+     */
+    public byte getChreApiMajorVersion() {
+        return mChreApiMajorVersion;
+    }
+
+    /**
+     * @return the CHRE API's minor version as defined in chre/version.h
+     *
+     * TODO(b/67734082): Expose as public API
+     * @hide
+     */
+    public byte getChreApiMinorVersion() {
+        return mChreApiMinorVersion;
+    }
+
+    /**
+     * @return the CHRE patch version as defined in chre/version.h
+     *
+     * TODO(b/67734082): Expose as public API
+     * @hide
+     */
+    public short getChrePatchVersion() {
+        return mChrePatchVersion;
+    }
+
     @Override
     public String toString() {
-      String retVal = "";
-      retVal += "Id : " + mId;
-      retVal += ", Name : " + mName;
-      retVal += "\n\tVendor : " + mVendor;
-      retVal += ", ToolChain : " + mToolchain;
-      retVal += "\n\tPlatformVersion : " + mPlatformVersion;
-      retVal += ", StaticSwVersion : " + mStaticSwVersion;
-      retVal += "\n\tPeakMips : " + mPeakMips;
-      retVal += ", StoppedPowerDraw : " + mStoppedPowerDrawMw + " mW";
-      retVal += ", PeakPowerDraw : " + mPeakPowerDrawMw + " mW";
-      retVal += ", MaxPacketLength : " + mMaxPacketLengthBytes + " Bytes";
-      retVal += "\n\tSupported sensors : " + Arrays.toString(mSupportedSensors);
-      retVal += "\n\tMemory Regions : " + Arrays.toString(mMemoryRegions);
+        String retVal = "";
+        retVal += "Id : " + mId;
+        retVal += ", Name : " + mName;
+        retVal += "\n\tVendor : " + mVendor;
+        retVal += ", Toolchain : " + mToolchain;
+        retVal += ", Toolchain version: 0x" + Integer.toHexString(mToolchainVersion);
+        retVal += "\n\tPlatformVersion : 0x" + Integer.toHexString(mPlatformVersion);
+        retVal += ", SwVersion : "
+                + mChreApiMajorVersion + "." + mChreApiMinorVersion + "." + mChrePatchVersion;
+        retVal += ", CHRE platform ID: 0x" + Long.toHexString(mChrePlatformId);
+        retVal += "\n\tPeakMips : " + mPeakMips;
+        retVal += ", StoppedPowerDraw : " + mStoppedPowerDrawMw + " mW";
+        retVal += ", PeakPowerDraw : " + mPeakPowerDrawMw + " mW";
+        retVal += ", MaxPacketLength : " + mMaxPacketLengthBytes + " Bytes";
+        retVal += "\n\tSupported sensors : " + Arrays.toString(mSupportedSensors);
+        retVal += "\n\tMemory Regions : " + Arrays.toString(mMemoryRegions);
 
-      return retVal;
+        return retVal;
     }
 
     private ContextHubInfo(Parcel in) {
@@ -371,12 +444,15 @@
         mToolchain = in.readString();
         mPlatformVersion = in.readInt();
         mToolchainVersion = in.readInt();
-        mStaticSwVersion = in.readInt();
         mPeakMips = in.readFloat();
         mStoppedPowerDrawMw = in.readFloat();
         mSleepPowerDrawMw = in.readFloat();
         mPeakPowerDrawMw = in.readFloat();
         mMaxPacketLengthBytes = in.readInt();
+        mChrePlatformId = in.readLong();
+        mChreApiMajorVersion = in.readByte();
+        mChreApiMinorVersion = in.readByte();
+        mChrePatchVersion = (short) in.readInt();
 
         int numSupportedSensors = in.readInt();
         mSupportedSensors = new int[numSupportedSensors];
@@ -395,12 +471,15 @@
         out.writeString(mToolchain);
         out.writeInt(mPlatformVersion);
         out.writeInt(mToolchainVersion);
-        out.writeInt(mStaticSwVersion);
         out.writeFloat(mPeakMips);
         out.writeFloat(mStoppedPowerDrawMw);
         out.writeFloat(mSleepPowerDrawMw);
         out.writeFloat(mPeakPowerDrawMw);
         out.writeInt(mMaxPacketLengthBytes);
+        out.writeLong(mChrePlatformId);
+        out.writeByte(mChreApiMajorVersion);
+        out.writeByte(mChreApiMinorVersion);
+        out.writeInt(mChrePatchVersion);
 
         out.writeInt(mSupportedSensors.length);
         out.writeIntArray(mSupportedSensors);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 935f5f3..6ebf3b9 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -103,7 +103,7 @@
 
     /**
      * A hardware serial number, if available. Alphanumeric only, case-insensitive.
-     * For apps targeting SDK higher than {@link Build.VERSION_CODES#N_MR1} this
+     * For apps targeting SDK higher than {@link Build.VERSION_CODES#O_MR1} this
      * field is set to {@link Build#UNKNOWN}.
      *
      * @deprecated Use {@link #getSerial()} instead.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 07c6055..f2e0bdd 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -22,6 +22,7 @@
 import android.opengl.EGL14;
 import android.os.Build;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.util.Log;
 
 import dalvik.system.VMRuntime;
@@ -29,18 +30,110 @@
 import java.io.File;
 
 /** @hide */
-public final class GraphicsEnvironment {
+public class GraphicsEnvironment {
+
+    private static final GraphicsEnvironment sInstance = new GraphicsEnvironment();
+
+    /**
+     * Returns the shared {@link GraphicsEnvironment} instance.
+     */
+    public static GraphicsEnvironment getInstance() {
+        return sInstance;
+    }
 
     private static final boolean DEBUG = false;
     private static final String TAG = "GraphicsEnvironment";
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
 
+    private ClassLoader mClassLoader;
+    private String mLayerPath;
+    private String mDebugLayerPath;
+
+    /**
+     * Set up GraphicsEnvironment
+     */
+    public void setup(Context context) {
+        setupGpuLayers(context);
+        chooseDriver(context);
+    }
+
+    /**
+     * Check whether application is debuggable
+     */
+    private static boolean isDebuggable(Context context) {
+        return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
+    }
+
+    /**
+     * Store the layer paths available to the loader.
+     */
+    public void setLayerPaths(ClassLoader classLoader,
+                              String layerPath,
+                              String debugLayerPath) {
+        // We have to store these in the class because they are set up before we
+        // have access to the Context to properly set up GraphicsEnvironment
+        mClassLoader = classLoader;
+        mLayerPath = layerPath;
+        mDebugLayerPath = debugLayerPath;
+    }
+
+    /**
+     * Set up layer search paths for all apps
+     * If debuggable, check for additional debug settings
+     */
+    private void setupGpuLayers(Context context) {
+
+        String layerPaths = "";
+
+        // Only enable additional debug functionality if the following conditions are met:
+        // 1. App is debuggable
+        // 2. ENABLE_GPU_DEBUG_LAYERS is true
+        // 3. Package name is equal to GPU_DEBUG_APP
+
+        if (isDebuggable(context)) {
+
+            int enable = Settings.Global.getInt(context.getContentResolver(),
+                                                Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+
+            if (enable != 0) {
+
+                String gpuDebugApp = Settings.Global.getString(context.getContentResolver(),
+                                                               Settings.Global.GPU_DEBUG_APP);
+
+                String packageName = context.getPackageName();
+
+                if ((gpuDebugApp != null && packageName != null)
+                        && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
+                        && gpuDebugApp.equals(packageName)) {
+                    Log.i(TAG, "GPU debug layers enabled for " + packageName);
+
+                    // Prepend the debug layer path as a searchable path.
+                    // This will ensure debug layers added will take precedence over
+                    // the layers specified by the app.
+                    layerPaths = mDebugLayerPath + ":";
+
+                    String layers = Settings.Global.getString(context.getContentResolver(),
+                                                              Settings.Global.GPU_DEBUG_LAYERS);
+
+                    Log.i(TAG, "Debug layer list: " + layers);
+                    if (layers != null && !layers.isEmpty()) {
+                        setDebugLayers(layers);
+                    }
+                }
+            }
+
+        }
+
+        // Include the app's lib directory in all cases
+        layerPaths += mLayerPath;
+
+        setLayerPaths(mClassLoader, layerPaths);
+    }
+
     /**
      * Choose whether the current process should use the builtin or an updated driver.
-     *
-     * @hide
      */
-    public static void chooseDriver(Context context) {
+    private static void chooseDriver(Context context) {
         String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
         if (driverPackageName == null || driverPackageName.isEmpty()) {
             return;
@@ -99,8 +192,6 @@
      * on a separate thread, it can usually be finished well before the UI is ready to be drawn.
      *
      * Should only be called after chooseDriver().
-     *
-     * @hide
      */
     public static void earlyInitEGL() {
         Thread eglInitThread = new Thread(
@@ -124,6 +215,7 @@
         return null;
     }
 
+    private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
+    private static native void setDebugLayers(String layers);
     private static native void setDriverPath(String path);
-
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 5d96fd3..0620fa3 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,10 @@
      * DO NOT MOVE - UserManager.h depends on the ordering of this function.
      */
     int getCredentialOwnerProfile(int userHandle);
+    int getProfileParentId(int userHandle);
+    /*
+     * END OF DO NOT MOVE
+     */
 
     UserInfo createUser(in String name, int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle,
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 10adb5a..d092018 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -191,6 +191,7 @@
  * {@link #readSparseArray(ClassLoader)}.
  */
 public final class Parcel {
+
     private static final boolean DEBUG_RECYCLE = false;
     private static final boolean DEBUG_ARRAY_MAP = false;
     private static final String TAG = "Parcel";
@@ -209,6 +210,12 @@
 
     private RuntimeException mStack;
 
+    /**
+     * Whether or not to parcel the stack trace of an exception. This has a performance
+     * impact, so should only be included in specific processes and only on debug builds.
+     */
+    private static boolean sParcelExceptionStackTrace;
+
     private static final int POOL_SIZE = 6;
     private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
     private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
@@ -325,6 +332,11 @@
     private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
     private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
 
+    /** Last time exception with a stack trace was written */
+    private static volatile long sLastWriteExceptionStackTrace;
+    /** Used for throttling of writing stack trace, which is costly */
+    private static final int WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS = 1000;
+
     @CriticalNative
     private static native long nativeGetBlobAshmemSize(long nativePtr);
 
@@ -1696,6 +1708,11 @@
         }
     }
 
+    /** @hide For debugging purposes */
+    public static void setStackTraceParceling(boolean enabled) {
+        sParcelExceptionStackTrace = enabled;
+    }
+
     /**
      * Special function for writing an exception result at the header of
      * a parcel, to be used when returning an exception from a transaction.
@@ -1753,6 +1770,27 @@
             throw new RuntimeException(e);
         }
         writeString(e.getMessage());
+        final long timeNow = sParcelExceptionStackTrace ? SystemClock.elapsedRealtime() : 0;
+        if (sParcelExceptionStackTrace && (timeNow - sLastWriteExceptionStackTrace
+                > WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS)) {
+            sLastWriteExceptionStackTrace = timeNow;
+            final int sizePosition = dataPosition();
+            writeInt(0); // Header size will be filled in later
+            StackTraceElement[] stackTrace = e.getStackTrace();
+            final int truncatedSize = Math.min(stackTrace.length, 5);
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < truncatedSize; i++) {
+                sb.append("\tat ").append(stackTrace[i]);
+            }
+            writeString(sb.toString());
+            final int payloadPosition = dataPosition();
+            setDataPosition(sizePosition);
+            // Write stack trace header size. Used in native side to skip the header
+            writeInt(payloadPosition - sizePosition);
+            setDataPosition(payloadPosition);
+        } else {
+            writeInt(0);
+        }
         switch (code) {
             case EX_SERVICE_SPECIFIC:
                 writeInt(((ServiceSpecificException) e).errorCode);
@@ -1818,7 +1856,19 @@
         int code = readExceptionCode();
         if (code != 0) {
             String msg = readString();
-            readException(code, msg);
+            String remoteStackTrace = null;
+            final int remoteStackPayloadSize = readInt();
+            if (remoteStackPayloadSize > 0) {
+                remoteStackTrace = readString();
+            }
+            Exception e = createException(code, msg);
+            // Attach remote stack trace if availalble
+            if (remoteStackTrace != null) {
+                RemoteException cause = new RemoteException(
+                        "Remote stack trace:\n" + remoteStackTrace, null, false, false);
+                e.initCause(cause);
+            }
+            SneakyThrow.sneakyThrow(e);
         }
     }
 
@@ -1863,32 +1913,41 @@
      * @param msg The exception message.
      */
     public final void readException(int code, String msg) {
+        SneakyThrow.sneakyThrow(createException(code, msg));
+    }
+
+    /**
+     * Creates an exception with the given message.
+     *
+     * @param code Used to determine which exception class to throw.
+     * @param msg The exception message.
+     */
+    private Exception createException(int code, String msg) {
         switch (code) {
             case EX_PARCELABLE:
                 if (readInt() > 0) {
-                    SneakyThrow.sneakyThrow(
-                            (Exception) readParcelable(Parcelable.class.getClassLoader()));
+                    return (Exception) readParcelable(Parcelable.class.getClassLoader());
                 } else {
-                    throw new RuntimeException(msg + " [missing Parcelable]");
+                    return new RuntimeException(msg + " [missing Parcelable]");
                 }
             case EX_SECURITY:
-                throw new SecurityException(msg);
+                return new SecurityException(msg);
             case EX_BAD_PARCELABLE:
-                throw new BadParcelableException(msg);
+                return new BadParcelableException(msg);
             case EX_ILLEGAL_ARGUMENT:
-                throw new IllegalArgumentException(msg);
+                return new IllegalArgumentException(msg);
             case EX_NULL_POINTER:
-                throw new NullPointerException(msg);
+                return new NullPointerException(msg);
             case EX_ILLEGAL_STATE:
-                throw new IllegalStateException(msg);
+                return new IllegalStateException(msg);
             case EX_NETWORK_MAIN_THREAD:
-                throw new NetworkOnMainThreadException();
+                return new NetworkOnMainThreadException();
             case EX_UNSUPPORTED_OPERATION:
-                throw new UnsupportedOperationException(msg);
+                return new UnsupportedOperationException(msg);
             case EX_SERVICE_SPECIFIC:
-                throw new ServiceSpecificException(readInt(), msg);
+                return new ServiceSpecificException(readInt(), msg);
         }
-        throw new RuntimeException("Unknown exception code: " + code
+        return new RuntimeException("Unknown exception code: " + code
                 + " msg " + msg);
     }
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index dd4825e..0fce7a4 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -527,8 +527,7 @@
             ServiceType.SOUND,
             ServiceType.BATTERY_STATS,
             ServiceType.DATA_SAVER,
-            ServiceType.FORCE_ALL_APPS_STANDBY_JOBS,
-            ServiceType.FORCE_ALL_APPS_STANDBY_ALARMS,
+            ServiceType.FORCE_ALL_APPS_STANDBY,
             ServiceType.OPTIONAL_SENSORS,
     })
     public @interface ServiceType {
@@ -545,14 +544,9 @@
         int DATA_SAVER = 10;
 
         /**
-         * Whether the job scheduler should force app standby on all apps on battery saver or not.
+         * Whether to enable force-app-standby on all apps or not.
          */
-        int FORCE_ALL_APPS_STANDBY_JOBS = 11;
-
-        /**
-         * Whether the alarm manager should force app standby on all apps on battery saver or not.
-         */
-        int FORCE_ALL_APPS_STANDBY_ALARMS = 12;
+        int FORCE_ALL_APPS_STANDBY = 11;
 
         /**
          * Whether to disable non-essential sensors. (e.g. edge sensors.)
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b5d62e5..0874d93 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -151,6 +151,9 @@
      */
     public static final int OTA_UPDATE_UID = 1061;
 
+    /** {@hide} */
+    public static final int NOBODY_UID = 9999;
+
     /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index 6d25fc1..4e8b971 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -30,6 +30,12 @@
         super(message);
     }
 
+    /** @hide */
+    public RemoteException(String message, Throwable cause, boolean enableSuppression,
+            boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
     /** {@hide} */
     public RuntimeException rethrowAsRuntimeException() {
         throw new RuntimeException(this);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6decc30..9945755 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9854,6 +9854,27 @@
         public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
 
         /**
+         * Allow GPU debug layers?
+         * 0 = no
+         * 1 = yes
+         * @hide
+         */
+        public static final String ENABLE_GPU_DEBUG_LAYERS = "enable_gpu_debug_layers";
+
+        /**
+         * App allowed to load GPU debug layers
+         * @hide
+         */
+        public static final String GPU_DEBUG_APP = "gpu_debug_app";
+
+        /**
+         * Ordered GPU debug layer list
+         * i.e. <layer1>:<layer2>:...:<layerN>
+         * @hide
+         */
+        public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers";
+
+        /**
          * Control whether the process CPU usage meter should be shown.
          *
          * @deprecated This functionality is no longer available as of
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 080482b..6fc689a 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.app.INotificationManager;
 import android.app.Service;
@@ -200,7 +201,11 @@
         return mProvider;
     }
 
-    private boolean isBound() {
+    /**
+     * @hide
+     */
+    @TestApi
+    public boolean isBound() {
         if (mProvider == null) {
             Log.w(TAG, "Condition provider service not yet bound.");
             return false;
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 2c83fc4..8c90156 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -355,21 +355,21 @@
         final Locale locale = localeFromContext(context);
         final MeasureFormat measureFormat = MeasureFormat.getInstance(
                 locale, MeasureFormat.FormatWidth.SHORT);
-        if (days >= 2) {
+        if (days >= 2 || (days > 0 && hours == 0)) {
             days += (hours+12)/24;
             return measureFormat.format(new Measure(days, MeasureUnit.DAY));
         } else if (days > 0) {
             return measureFormat.formatMeasures(
                     new Measure(days, MeasureUnit.DAY),
                     new Measure(hours, MeasureUnit.HOUR));
-        } else if (hours >= 2) {
+        } else if (hours >= 2 || (hours > 0 && minutes == 0)) {
             hours += (minutes+30)/60;
             return measureFormat.format(new Measure(hours, MeasureUnit.HOUR));
         } else if (hours > 0) {
             return measureFormat.formatMeasures(
                     new Measure(hours, MeasureUnit.HOUR),
                     new Measure(minutes, MeasureUnit.MINUTE));
-        } else if (minutes >= 2) {
+        } else if (minutes >= 2 || (minutes > 0 && seconds == 0)) {
             minutes += (seconds+30)/60;
             return measureFormat.format(new Measure(minutes, MeasureUnit.MINUTE));
         } else if (minutes > 0) {
diff --git a/core/java/android/util/AndroidException.java b/core/java/android/util/AndroidException.java
index dfe00c9b..1345ddf 100644
--- a/core/java/android/util/AndroidException.java
+++ b/core/java/android/util/AndroidException.java
@@ -34,5 +34,11 @@
     public AndroidException(Exception cause) {
         super(cause);
     }
+
+    /** @hide */
+    protected AndroidException(String message, Throwable cause, boolean enableSuppression,
+            boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
 };
 
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/core/java/android/util/MutableInt.java
similarity index 64%
copy from core/java/com/android/internal/app/IAssistDataReceiver.aidl
copy to core/java/android/util/MutableInt.java
index 9c9ffef..a3d8606 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/core/java/android/util/MutableInt.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.app;
+package android.util;
 
-import android.graphics.Bitmap;
-import android.os.Bundle;
+/**
+ */
+public final class MutableInt {
+    public int value;
 
-/** @hide */
-oneway interface IAssistDataReceiver {
-    void onHandleAssistData(in Bundle resultData);
-    void onHandleAssistScreenshot(in Bitmap screenshot);
+    public MutableInt(int value) {
+        this.value = value;
+    }
 }
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/core/java/android/util/MutableLong.java
similarity index 64%
copy from core/java/com/android/internal/app/IAssistDataReceiver.aidl
copy to core/java/android/util/MutableLong.java
index 9c9ffef..575068e 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/core/java/android/util/MutableLong.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.app;
+package android.util;
 
-import android.graphics.Bitmap;
-import android.os.Bundle;
+/**
+ */
+public final class MutableLong {
+    public long value;
 
-/** @hide */
-oneway interface IAssistDataReceiver {
-    void onHandleAssistData(in Bundle resultData);
-    void onHandleAssistScreenshot(in Bitmap screenshot);
+    public MutableLong(long value) {
+        this.value = value;
+    }
 }
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index 232ff25..defa58e 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -446,49 +446,52 @@
      */
     public static String toString(int gravity) {
         final StringBuilder result = new StringBuilder();
-        if ((gravity & FILL) != 0) {
+        if ((gravity & FILL) == FILL) {
             result.append("FILL").append(' ');
         } else {
-            if ((gravity & FILL_VERTICAL) != 0) {
+            if ((gravity & FILL_VERTICAL) == FILL_VERTICAL) {
                 result.append("FILL_VERTICAL").append(' ');
             } else {
-                if ((gravity & TOP) != 0) {
+                if ((gravity & TOP) == TOP) {
                     result.append("TOP").append(' ');
                 }
-                if ((gravity & BOTTOM) != 0) {
+                if ((gravity & BOTTOM) == BOTTOM) {
                     result.append("BOTTOM").append(' ');
                 }
             }
-            if ((gravity & FILL_HORIZONTAL) != 0) {
+            if ((gravity & FILL_HORIZONTAL) == FILL_HORIZONTAL) {
                 result.append("FILL_HORIZONTAL").append(' ');
             } else {
-                if ((gravity & START) != 0) {
+                if ((gravity & START) == START) {
                     result.append("START").append(' ');
-                } else if ((gravity & LEFT) != 0) {
+                } else if ((gravity & LEFT) == LEFT) {
                     result.append("LEFT").append(' ');
                 }
-                if ((gravity & END) != 0) {
+                if ((gravity & END) == END) {
                     result.append("END").append(' ');
-                } else if ((gravity & RIGHT) != 0) {
+                } else if ((gravity & RIGHT) == RIGHT) {
                     result.append("RIGHT").append(' ');
                 }
             }
         }
-        if ((gravity & CENTER) != 0) {
+        if ((gravity & CENTER) == CENTER) {
             result.append("CENTER").append(' ');
         } else {
-            if ((gravity & CENTER_VERTICAL) != 0) {
+            if ((gravity & CENTER_VERTICAL) == CENTER_VERTICAL) {
                 result.append("CENTER_VERTICAL").append(' ');
             }
-            if ((gravity & CENTER_HORIZONTAL) != 0) {
+            if ((gravity & CENTER_HORIZONTAL) == CENTER_HORIZONTAL) {
                 result.append("CENTER_HORIZONTAL").append(' ');
             }
         }
-        if ((gravity & DISPLAY_CLIP_VERTICAL) != 0) {
+        if (result.length() == 0) {
+            result.append("NO GRAVITY").append(' ');
+        }
+        if ((gravity & DISPLAY_CLIP_VERTICAL) == DISPLAY_CLIP_VERTICAL) {
             result.append("DISPLAY_CLIP_VERTICAL").append(' ');
         }
-        if ((gravity & DISPLAY_CLIP_VERTICAL) != 0) {
-            result.append("DISPLAY_CLIP_VERTICAL").append(' ');
+        if ((gravity & DISPLAY_CLIP_HORIZONTAL) == DISPLAY_CLIP_HORIZONTAL) {
+            result.append("DISPLAY_CLIP_HORIZONTAL").append(' ');
         }
         result.deleteCharAt(result.length() - 1);
         return result.toString();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 65bde49..29032a7 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -16,13 +16,13 @@
 
 package android.view;
 
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 
+import android.app.IAssistDataReceiver;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 9515040..c4a7160 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,7 +19,6 @@
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.util.SparseIntArray;
@@ -281,12 +280,9 @@
         setTarget(mViewTarget.mRenderNode);
     }
 
-    public void setTarget(Canvas canvas) {
-        if (!(canvas instanceof DisplayListCanvas)) {
-            throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
-        }
-        final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
-        setTarget(recordingCanvas.mNode);
+    /** Sets the animation target to the owning view of the DisplayListCanvas */
+    public void setTarget(DisplayListCanvas canvas) {
+        setTarget(canvas.mNode);
     }
 
     private void setTarget(RenderNode node) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index be09fe8..19ce43f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4163,6 +4163,11 @@
      */
     private static boolean sUseDefaultFocusHighlight;
 
+    /**
+     * True if zero-sized views can be focused.
+     */
+    private static boolean sCanFocusZeroSized;
+
     private String mTransitionName;
 
     static class TintInfo {
@@ -4245,6 +4250,8 @@
         OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
 
         OnCapturedPointerListener mOnCapturedPointerListener;
+
+        private ArrayList<OnKeyFallbackListener> mKeyFallbackListeners;
     }
 
     ListenerInfo mListenerInfo;
@@ -4743,6 +4750,8 @@
             sUseDefaultFocusHighlight = context.getResources().getBoolean(
                     com.android.internal.R.bool.config_useDefaultFocusHighlight);
 
+            sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P;
+
             sCompatibilityDone = true;
         }
     }
@@ -6950,6 +6959,7 @@
     void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
         if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
             mPrivateFlags &= ~PFLAG_FOCUSED;
+            clearParentsWantFocus();
 
             if (propagate && mParent != null) {
                 mParent.clearChildFocus(this);
@@ -10931,8 +10941,9 @@
      * descendants.
      *
      * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
-     * false), or if it is focusable and it is not focusable in touch mode
-     * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
+     * false), or if it can't be focused due to other conditions (not focusable in touch mode
+     * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not
+     * enabled, or has no size).
      *
      * See also {@link #focusSearch(int)}, which is what you call to say that you
      * have focus, and you want your parent to look for the next one.
@@ -10970,17 +10981,17 @@
      */
     @TestApi
     public boolean restoreFocusNotInCluster() {
-        return requestFocus(View.FOCUS_DOWN);
+        return requestFocus();
     }
 
     /**
      * Gives focus to the default-focus view in the view hierarchy that has this view as a root.
-     * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}.
+     * If the default-focus view cannot be found, falls back to calling {@link #requestFocus()}.
      *
      * @return Whether this view or one of its descendants actually took focus
      */
     public boolean restoreDefaultFocus() {
-        return requestFocus(View.FOCUS_DOWN);
+        return requestFocus();
     }
 
     /**
@@ -11039,9 +11050,7 @@
 
     private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
         // need to be focusable
-        if ((mViewFlags & FOCUSABLE) != FOCUSABLE
-                || (mViewFlags & VISIBILITY_MASK) != VISIBLE
-                || (mViewFlags & ENABLED_MASK) != ENABLED) {
+        if (!canTakeFocus()) {
             return false;
         }
 
@@ -11056,10 +11065,21 @@
             return false;
         }
 
+        if (!isLaidOut()) {
+            mPrivateFlags |= PFLAG_WANTS_FOCUS;
+        }
+
         handleFocusGainInternal(direction, previouslyFocusedRect);
         return true;
     }
 
+    void clearParentsWantFocus() {
+        if (mParent instanceof View) {
+            ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+            ((View) mParent).clearParentsWantFocus();
+        }
+    }
+
     /**
      * Call this to try to give focus to a specific view or to one of its descendants. This is a
      * special variant of {@link #requestFocus() } that will allow views that are not focusable in
@@ -13431,6 +13451,13 @@
         mAttachInfo.mUnbufferedDispatchRequested = true;
     }
 
+    private boolean canTakeFocus() {
+        return ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
+                && ((mViewFlags & FOCUSABLE) == FOCUSABLE)
+                && ((mViewFlags & ENABLED_MASK) == ENABLED)
+                && (sCanFocusZeroSized || !isLaidOut() || (mBottom > mTop) && (mRight > mLeft));
+    }
+
     /**
      * Set flags controlling behavior of this view.
      *
@@ -13450,6 +13477,7 @@
             return;
         }
         int privateFlags = mPrivateFlags;
+        boolean shouldNotifyFocusableAvailable = false;
 
         // If focusable is auto, update the FOCUSABLE bit.
         int focusableChangedByAuto = 0;
@@ -13488,7 +13516,7 @@
                             || focusableChangedByAuto == 0
                             || viewRootImpl == null
                             || viewRootImpl.mThread == Thread.currentThread()) {
-                        mParent.focusableViewAvailable(this);
+                        shouldNotifyFocusableAvailable = true;
                     }
                 }
             }
@@ -13511,10 +13539,7 @@
                 // about in case nothing has focus.  even if this specific view
                 // isn't focusable, it may contain something that is, so let
                 // the root view try to give this focus if nothing else does.
-                if ((mParent != null) && ((mViewFlags & ENABLED_MASK) == ENABLED)
-                        && (mBottom > mTop) && (mRight > mLeft)) {
-                    mParent.focusableViewAvailable(this);
-                }
+                shouldNotifyFocusableAvailable = true;
             }
         }
 
@@ -13523,17 +13548,18 @@
                 // a view becoming enabled should notify the parent as long as the view is also
                 // visible and the parent wasn't already notified by becoming visible during this
                 // setFlags invocation.
-                if ((mViewFlags & VISIBILITY_MASK) == VISIBLE
-                        && ((changed & VISIBILITY_MASK) == 0)) {
-                    if ((mParent != null) && (mViewFlags & ENABLED_MASK) == ENABLED) {
-                        mParent.focusableViewAvailable(this);
-                    }
-                }
+                shouldNotifyFocusableAvailable = true;
             } else {
                 if (hasFocus()) clearFocus();
             }
         }
 
+        if (shouldNotifyFocusableAvailable) {
+            if (mParent != null && canTakeFocus()) {
+                mParent.focusableViewAvailable(this);
+            }
+        }
+
         /* Check if the GONE bit has changed */
         if ((changed & GONE) != 0) {
             needGlobalAttributesUpdate(false);
@@ -20032,15 +20058,58 @@
             }
         }
 
+        final boolean wasLaidOut = isLaidOut();
+
         mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
         mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
 
+        if (!wasLaidOut && isFocused()) {
+            mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+            if (canTakeFocus()) {
+                // We have a robust focus, so parents should no longer be wanting focus.
+                clearParentsWantFocus();
+            } else if (!getViewRootImpl().isInLayout()) {
+                // This is a weird case. Most-likely the user, rather than ViewRootImpl, called
+                // layout. In this case, there's no guarantee that parent layouts will be evaluated
+                // and thus the safest action is to clear focus here.
+                clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+                clearParentsWantFocus();
+            } else if (!hasParentWantsFocus()) {
+                // original requestFocus was likely on this view directly, so just clear focus
+                clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+            }
+            // otherwise, we let parents handle re-assigning focus during their layout passes.
+        } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
+            mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
+            View focused = findFocus();
+            if (focused != null) {
+                // Try to restore focus as close as possible to our starting focus.
+                if (!restoreDefaultFocus() && !hasParentWantsFocus()) {
+                    // Give up and clear focus once we've reached the top-most parent which wants
+                    // focus.
+                    focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
+                }
+            }
+        }
+
         if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
             mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
             notifyEnterOrExitForAutoFillIfNeeded(true);
         }
     }
 
+    private boolean hasParentWantsFocus() {
+        ViewParent parent = mParent;
+        while (parent instanceof ViewGroup) {
+            ViewGroup pv = (ViewGroup) parent;
+            if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
+                return true;
+            }
+            parent = pv.mParent;
+        }
+        return false;
+    }
+
     /**
      * Called from layout when this view should
      * assign a size and position to each of its children.
@@ -20147,6 +20216,23 @@
             mOverlay.getOverlayView().setRight(newWidth);
             mOverlay.getOverlayView().setBottom(newHeight);
         }
+        // If this isn't laid out yet, focus assignment will be handled during the "deferment/
+        // backtracking" of requestFocus during layout, so don't touch focus here.
+        if (!sCanFocusZeroSized && isLaidOut()) {
+            if (newWidth <= 0 || newHeight <= 0) {
+                if (hasFocus()) {
+                    clearFocus();
+                    if (mParent instanceof ViewGroup) {
+                        ((ViewGroup) mParent).clearFocusedInCluster();
+                    }
+                }
+                clearAccessibilityFocus();
+            } else if (oldWidth <= 0 || oldHeight <= 0) {
+                if (mParent != null && canTakeFocus()) {
+                    mParent.focusableViewAvailable(this);
+                }
+            }
+        }
         rebuildOutline();
     }
 
@@ -25194,6 +25280,29 @@
     }
 
     /**
+     * Interface definition for a callback to be invoked when a hardware key event is
+     * dispatched to this view during the fallback phase. This means no view in the hierarchy
+     * has handled this event.
+     */
+    public interface OnKeyFallbackListener {
+        /**
+         * Called when a hardware key is dispatched to a view in the fallback phase. This allows
+         * listeners to respond to events after the view hierarchy has had a chance to respond.
+         * <p>Key presses in software keyboards will generally NOT trigger this method,
+         * although some may elect to do so in some situations. Do not assume a
+         * software input method has to be key-based; even if it is, it may use key presses
+         * in a different way than you expect, so there is no way to reliably catch soft
+         * input key presses.
+         *
+         * @param v The view the key has been dispatched to.
+         * @param event The KeyEvent object containing full information about
+         *        the event.
+         * @return True if the listener has consumed the event, false otherwise.
+         */
+        boolean onKeyFallback(View v, KeyEvent event);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when a touch event is
      * dispatched to this view. The callback will be invoked before the touch
      * event is given to the view.
@@ -26866,4 +26975,56 @@
         }
         return mTooltipInfo.mTooltipPopup.getContentView();
     }
+
+    /**
+     * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This
+     * occurs after the normal view hierarchy dispatch, but before the window callback. By default,
+     * this will dispatch into all the listeners registered via
+     * {@link #addKeyFallbackListener(OnKeyFallbackListener)} in last-in-first-out order (most
+     * recently added will receive events first).
+     *
+     * @param event A not-previously-handled event.
+     * @return {@code true} if the event was handled, {@code false} otherwise.
+     * @see #addKeyFallbackListener
+     */
+    public boolean onKeyFallback(@NonNull KeyEvent event) {
+        if (mListenerInfo != null && mListenerInfo.mKeyFallbackListeners != null) {
+            for (int i = mListenerInfo.mKeyFallbackListeners.size() - 1; i >= 0; --i) {
+                if (mListenerInfo.mKeyFallbackListeners.get(i).onKeyFallback(this, event)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Adds a listener which will receive unhandled {@link KeyEvent}s.
+     * @param listener the receiver of fallback {@link KeyEvent}s.
+     * @see #onKeyFallback(KeyEvent)
+     */
+    public void addKeyFallbackListener(OnKeyFallbackListener listener) {
+        ArrayList<OnKeyFallbackListener> fallbacks = getListenerInfo().mKeyFallbackListeners;
+        if (fallbacks == null) {
+            fallbacks = new ArrayList<>();
+            getListenerInfo().mKeyFallbackListeners = fallbacks;
+        }
+        fallbacks.add(listener);
+    }
+
+    /**
+     * Removes a listener which will receive unhandled {@link KeyEvent}s.
+     * @param listener the receiver of fallback {@link KeyEvent}s.
+     * @see #onKeyFallback(KeyEvent)
+     */
+    public void removeKeyFallbackListener(OnKeyFallbackListener listener) {
+        if (mListenerInfo != null) {
+            if (mListenerInfo.mKeyFallbackListeners != null) {
+                mListenerInfo.mKeyFallbackListeners.remove(listener);
+                if (mListenerInfo.mKeyFallbackListeners.isEmpty()) {
+                    mListenerInfo.mKeyFallbackListeners = null;
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 929beae..d0fcc5d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3215,22 +3215,31 @@
         }
         int descendantFocusability = getDescendantFocusability();
 
+        boolean result;
         switch (descendantFocusability) {
             case FOCUS_BLOCK_DESCENDANTS:
-                return super.requestFocus(direction, previouslyFocusedRect);
+                result = super.requestFocus(direction, previouslyFocusedRect);
+                break;
             case FOCUS_BEFORE_DESCENDANTS: {
                 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
-                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
+                result = took ? took : onRequestFocusInDescendants(direction,
+                        previouslyFocusedRect);
+                break;
             }
             case FOCUS_AFTER_DESCENDANTS: {
                 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
-                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
+                result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
+                break;
             }
             default:
                 throw new IllegalStateException("descendant focusability must be "
                         + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
                         + "but is " + descendantFocusability);
         }
+        if (result && !isLaidOut() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
+            mPrivateFlags |= PFLAG_WANTS_FOCUS;
+        }
+        return result;
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e30496f..e9509b7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -73,6 +73,7 @@
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
@@ -362,6 +363,8 @@
     InputStage mFirstPostImeInputStage;
     InputStage mSyntheticInputStage;
 
+    private final KeyFallbackManager mKeyFallbackManager = new KeyFallbackManager();
+
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
 
@@ -4764,6 +4767,13 @@
         private int processKeyEvent(QueuedInputEvent q) {
             final KeyEvent event = (KeyEvent)q.mEvent;
 
+            mKeyFallbackManager.mDispatched = false;
+
+            if (mKeyFallbackManager.hasFocus()
+                    && mKeyFallbackManager.dispatchUnique(mView, event)) {
+                return FINISH_HANDLED;
+            }
+
             // Deliver the key to the view hierarchy.
             if (mView.dispatchKeyEvent(event)) {
                 return FINISH_HANDLED;
@@ -4773,6 +4783,10 @@
                 return FINISH_NOT_HANDLED;
             }
 
+            if (mKeyFallbackManager.dispatchUnique(mView, event)) {
+                return FINISH_HANDLED;
+            }
+
             int groupNavigationDirection = 0;
 
             if (event.getAction() == KeyEvent.ACTION_DOWN
@@ -7529,6 +7543,16 @@
         }
     }
 
+    /**
+     * Dispatches a KeyEvent to all registered key fallback handlers.
+     *
+     * @param event
+     * @return {@code true} if the event was handled, {@code false} otherwise.
+     */
+    public boolean dispatchKeyFallbackEvent(KeyEvent event) {
+        return mKeyFallbackManager.dispatch(mView, event);
+    }
+
     class TakenSurfaceHolder extends BaseSurfaceHolder {
         @Override
         public boolean onAllowLockCanvas() {
@@ -8093,4 +8117,92 @@
             run();
         }
     }
+
+    private static class KeyFallbackManager {
+
+        // This is used to ensure that key-fallback events are only dispatched once. We attempt
+        // to dispatch more than once in order to achieve a certain order. Specifically, if we
+        // are in an Activity or Dialog (and have a Window.Callback), the keyfallback events should
+        // be dispatched after the view hierarchy, but before the Activity. However, if we aren't
+        // in an activity, we still want key fallbacks to be dispatched.
+        boolean mDispatched = false;
+
+        SparseBooleanArray mCapturedKeys = new SparseBooleanArray();
+        WeakReference<View> mFallbackReceiver = null;
+        int mVisitCount = 0;
+
+        private void updateCaptureState(KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                mCapturedKeys.append(event.getKeyCode(), true);
+            }
+            if (event.getAction() == KeyEvent.ACTION_UP) {
+                mCapturedKeys.delete(event.getKeyCode());
+            }
+        }
+
+        boolean dispatch(View root, KeyEvent event) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "KeyFallback dispatch");
+            mDispatched = true;
+
+            updateCaptureState(event);
+
+            if (mFallbackReceiver != null) {
+                View target = mFallbackReceiver.get();
+                if (mCapturedKeys.size() == 0) {
+                    mFallbackReceiver = null;
+                }
+                if (target != null && target.isAttachedToWindow()) {
+                    return target.onKeyFallback(event);
+                }
+                // consume anyways so that we don't feed uncaptured key events to other views
+                return true;
+            }
+
+            boolean result = dispatchInZOrder(root, event);
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+            return result;
+        }
+
+        private boolean dispatchInZOrder(View view, KeyEvent evt) {
+            if (view instanceof ViewGroup) {
+                ViewGroup vg = (ViewGroup) view;
+                ArrayList<View> orderedViews = vg.buildOrderedChildList();
+                if (orderedViews != null) {
+                    try {
+                        for (int i = orderedViews.size() - 1; i >= 0; --i) {
+                            View v = orderedViews.get(i);
+                            if (dispatchInZOrder(v, evt)) {
+                                return true;
+                            }
+                        }
+                    } finally {
+                        orderedViews.clear();
+                    }
+                } else {
+                    for (int i = vg.getChildCount() - 1; i >= 0; --i) {
+                        View v = vg.getChildAt(i);
+                        if (dispatchInZOrder(v, evt)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            if (view.onKeyFallback(evt)) {
+                mFallbackReceiver = new WeakReference<>(view);
+                return true;
+            }
+            return false;
+        }
+
+        boolean hasFocus() {
+            return mFallbackReceiver != null;
+        }
+
+        boolean dispatchUnique(View root, KeyEvent event) {
+            if (mDispatched) {
+                return false;
+            }
+            return dispatch(root, event);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 85251d4..5fddfba 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -431,7 +431,11 @@
             }
         }
 
-        return super.dispatchKeyEvent(event);
+        if (super.dispatchKeyEvent(event)) {
+            return true;
+        }
+
+        return (getViewRootImpl() != null) && getViewRootImpl().dispatchKeyFallbackEvent(event);
     }
 
     public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 91bc681..22bfcc3 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -30,6 +30,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -134,6 +135,13 @@
     }
 
     /**
+     * Checks if given map is null or has zero elements.
+     */
+    public static boolean isEmpty(@Nullable Map<?, ?> map) {
+        return map == null || map.isEmpty();
+    }
+
+    /**
      * Checks if given array is null or has zero elements.
      */
     public static <T> boolean isEmpty(@Nullable T[] array) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3552e43..9d036dc 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -42,7 +42,6 @@
         "com_google_android_gles_jni_EGLImpl.cpp",
         "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
         "android_app_Activity.cpp",
-        "android_app_ApplicationLoaders.cpp",
         "android_app_NativeActivity.cpp",
         "android_app_admin_SecurityLog.cpp",
         "android_opengl_EGL14.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8977891..2a65cde 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -187,7 +187,6 @@
 extern int register_android_app_backup_FullBackup(JNIEnv *env);
 extern int register_android_app_Activity(JNIEnv *env);
 extern int register_android_app_ActivityThread(JNIEnv *env);
-extern int register_android_app_ApplicationLoaders(JNIEnv *env);
 extern int register_android_app_NativeActivity(JNIEnv *env);
 extern int register_android_media_RemoteDisplay(JNIEnv *env);
 extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
@@ -1456,7 +1455,6 @@
     REG_JNI(register_android_app_backup_FullBackup),
     REG_JNI(register_android_app_Activity),
     REG_JNI(register_android_app_ActivityThread),
-    REG_JNI(register_android_app_ApplicationLoaders),
     REG_JNI(register_android_app_NativeActivity),
     REG_JNI(register_android_util_jar_StrictJarFile),
     REG_JNI(register_android_view_InputChannel),
diff --git a/core/jni/android_app_ApplicationLoaders.cpp b/core/jni/android_app_ApplicationLoaders.cpp
deleted file mode 100644
index 8bbf24a..0000000
--- a/core/jni/android_app_ApplicationLoaders.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ApplicationLoaders"
-
-#include <nativehelper/ScopedUtfChars.h>
-#include <nativeloader/native_loader.h>
-#include <vulkan/vulkan_loader_data.h>
-
-#include "core_jni_helpers.h"
-
-static void setupVulkanLayerPath_native(JNIEnv* env, jobject clazz,
-        jobject classLoader, jstring librarySearchPath) {
-    android_namespace_t* ns = android::FindNamespaceByClassLoader(env, classLoader);
-    ScopedUtfChars layerPathChars(env, librarySearchPath);
-
-    vulkan::LoaderData& loader_data = vulkan::LoaderData::GetInstance();
-    if (loader_data.layer_path.empty()) {
-        loader_data.layer_path = layerPathChars.c_str();
-        loader_data.app_namespace = ns;
-    } else {
-        ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
-                layerPathChars.c_str(), ns);
-    }
-}
-
-static const JNINativeMethod g_methods[] = {
-    { "setupVulkanLayerPath", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
-      reinterpret_cast<void*>(setupVulkanLayerPath_native) },
-};
-
-static const char* const kApplicationLoadersName = "android/app/ApplicationLoaders";
-
-namespace android
-{
-
-int register_android_app_ApplicationLoaders(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, kApplicationLoadersName, g_methods, NELEM(g_methods));
-}
-
-} // namespace android
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index f749488..4ecfd4b 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -18,6 +18,7 @@
 
 #include <graphicsenv/GraphicsEnv.h>
 #include <nativehelper/ScopedUtfChars.h>
+#include <nativeloader/native_loader.h>
 #include "core_jni_helpers.h"
 
 namespace {
@@ -27,8 +28,23 @@
     android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
 }
 
+void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
+    android_namespace_t* appNamespace = android::FindNamespaceByClassLoader(env, classLoader);
+    ScopedUtfChars layerPathsChars(env, layerPaths);
+    android::GraphicsEnv::getInstance().setLayerPaths(appNamespace, layerPathsChars.c_str());
+}
+
+void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) {
+    if (layers != nullptr) {
+        ScopedUtfChars layersChars(env, layers);
+        android::GraphicsEnv::getInstance().setDebugLayers(layersChars.c_str());
+    }
+}
+
 const JNINativeMethod g_methods[] = {
     { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
+    { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
+    { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
 };
 
 const char* const kGraphicsEnvironmentName = "android/os/GraphicsEnvironment";
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index ac79249..4e88a83 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -120,14 +120,13 @@
 
 class Run {
     public:
-        Run(int32_t start, int32_t end) : mStart(start), mEnd(end) {}
+        Run(int32_t start, int32_t end) : mRange(start, end) {}
         virtual ~Run() {}
 
         virtual void addTo(minikin::LineBreaker* lineBreaker) = 0;
 
     protected:
-        const int32_t mStart;
-        const int32_t mEnd;
+        minikin::Range mRange;
 
     private:
         // Forbid copy and assign.
@@ -143,7 +142,7 @@
               mIsRtl(isRtl) {}
 
         void addTo(minikin::LineBreaker* lineBreaker) override {
-            lineBreaker->addStyleRun(&mPaint, mCollection, mStart, mEnd, mIsRtl);
+            lineBreaker->addStyleRun(&mPaint, mCollection, mRange, mIsRtl);
         }
 
     private:
@@ -158,7 +157,7 @@
             : Run(start, end), mWidth(width), mLocaleListId(localeListId) {}
 
         void addTo(minikin::LineBreaker* lineBreaker) override {
-            lineBreaker->addReplacement(mStart, mEnd, mWidth, mLocaleListId);
+            lineBreaker->addReplacement(mRange, mWidth, mLocaleListId);
         }
 
     private:
@@ -273,7 +272,7 @@
 
 static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
         // Inputs
-        jcharArray text,
+        jcharArray javaText,
         jint length,
         jfloat firstWidth,
         jint firstWidthLineCount,
@@ -294,11 +293,10 @@
 
     StaticLayoutNative* builder = toNative(nativePtr);
 
+    ScopedCharArrayRO text(env, javaText);
+
     // TODO: Reorganize minikin APIs.
-    minikin::LineBreaker b;
-    b.resize(length);
-    env->GetCharArrayRegion(text, 0, length, b.buffer());
-    b.setText();
+    minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length));
     if (variableTabStops == nullptr) {
         b.setTabStops(nullptr, 0, defaultTabStop);
     } else {
@@ -321,7 +319,6 @@
 
     env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths());
 
-    b.finish();
     builder->clearRuns();
 
     return static_cast<jint>(nBreaks);
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 764288c..5d5aea2 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -305,6 +305,9 @@
     optional SettingProto preferred_network_mode = 226;
     optional SettingProto debug_app = 227;
     optional SettingProto wait_for_debugger = 228;
+    optional SettingProto enable_gpu_debug_layers = 342;
+    optional SettingProto gpu_debug_app = 343;
+    optional SettingProto gpu_debug_layers = 344;
     optional SettingProto low_power_mode = 229;
     optional SettingProto low_power_mode_trigger_level = 230;
     optional SettingProto always_finish_activities = 231;
@@ -384,7 +387,7 @@
     optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
     optional SettingProto notification_snooze_options = 341;
 
-    // Next tag = 342;
+    // Next tag = 345;
 }
 
 message SecureSettingsProto {
diff --git a/core/res/Android.mk b/core/res/Android.mk
index b066929..370a01f 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -29,6 +29,9 @@
 # Framework doesn't need versioning since it IS the platform.
 LOCAL_AAPT_FLAGS += --no-auto-version
 
+# Allow overlay to add resource
+LOCAL_AAPT_FLAGS += --auto-add-overlay
+
 # Install this alongside the libraries.
 LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
 
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 01df0da..c647093 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -19,7 +19,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:zAdjustment="normal">
+     android:zAdjustment="top">
     <translate android:fromYDelta="0" android:toYDelta="5%p"
                android:duration="250"
                android:interpolator="@android:interpolator/fast_out_slow_in"/>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index fd88102..6cef47d 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -39,8 +39,8 @@
         <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
         <item name="taskCloseEnterAnimation">@null</item>
         <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
+        <item name="taskToFrontEnterAnimation">@null</item>
+        <item name="taskToFrontExitAnimation">@anim/slide_out_micro</item>
         <item name="taskToBackEnterAnimation">@null</item>
         <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
         <item name="wallpaperOpenEnterAnimation">@null</item>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d36ed63..0d35f4e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -356,6 +356,9 @@
                     Settings.Global.USE_GOOGLE_MAIL,
                     Settings.Global.VT_IMS_ENABLED,
                     Settings.Global.WAIT_FOR_DEBUGGER,
+                    Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
+                    Settings.Global.GPU_DEBUG_APP,
+                    Settings.Global.GPU_DEBUG_LAYERS,
                     Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
                     Settings.Global.WARNING_TEMPERATURE,
                     Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 24e3646..dee51dc 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -117,13 +117,13 @@
         assertEquals("2 days", Formatter.formatShortElapsedTime(mContext, 2 * DAY));
         assertEquals("1 day, 23 hr",
                 Formatter.formatShortElapsedTime(mContext, 1 * DAY + 23 * HOUR + 59 * MINUTE));
-        assertEquals("1 day, 0 hr",
+        assertEquals("1 day",
                 Formatter.formatShortElapsedTime(mContext, 1 * DAY + 59 * MINUTE));
-        assertEquals("1 day, 0 hr", Formatter.formatShortElapsedTime(mContext, 1 * DAY));
+        assertEquals("1 day", Formatter.formatShortElapsedTime(mContext, 1 * DAY));
         assertEquals("24 hr", Formatter.formatShortElapsedTime(mContext, 23 * HOUR + 30 * MINUTE));
         assertEquals("3 hr", Formatter.formatShortElapsedTime(mContext, 2 * HOUR + 30 * MINUTE));
         assertEquals("2 hr", Formatter.formatShortElapsedTime(mContext, 2 * HOUR));
-        assertEquals("1 hr, 0 min", Formatter.formatShortElapsedTime(mContext, 1 * HOUR));
+        assertEquals("1 hr", Formatter.formatShortElapsedTime(mContext, 1 * HOUR));
         assertEquals("60 min",
                 Formatter.formatShortElapsedTime(mContext, 59 * MINUTE + 30 * SECOND));
         assertEquals("59 min",
@@ -132,7 +132,7 @@
         assertEquals("2 min", Formatter.formatShortElapsedTime(mContext, 2 * MINUTE));
         assertEquals("1 min, 59 sec",
                 Formatter.formatShortElapsedTime(mContext, 1 * MINUTE + 59 * SECOND + 999));
-        assertEquals("1 min, 0 sec", Formatter.formatShortElapsedTime(mContext, 1 * MINUTE));
+        assertEquals("1 min", Formatter.formatShortElapsedTime(mContext, 1 * MINUTE));
         assertEquals("59 sec", Formatter.formatShortElapsedTime(mContext, 59 * SECOND + 999));
         assertEquals("1 sec", Formatter.formatShortElapsedTime(mContext, 1 * SECOND));
         assertEquals("0 sec", Formatter.formatShortElapsedTime(mContext, 1));
@@ -154,9 +154,9 @@
                 mContext, 2 * DAY));
         assertEquals("1 day, 23 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 1 * DAY + 23 * HOUR + 59 * MINUTE));
-        assertEquals("1 day, 0 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+        assertEquals("1 day", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 1 * DAY + 59 * MINUTE));
-        assertEquals("1 day, 0 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+        assertEquals("1 day", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 1 * DAY));
         assertEquals("24 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 23 * HOUR + 30 * MINUTE));
@@ -164,9 +164,9 @@
                 mContext, 2 * HOUR + 30 * MINUTE));
         assertEquals("2 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 2 * HOUR));
-        assertEquals("1 hr, 0 min", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+        assertEquals("1 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 1 * HOUR));
-        assertEquals("1 hr, 0 min", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+        assertEquals("1 hr", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 59 * MINUTE + 30 * SECOND));
         assertEquals("59 min", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 59 * MINUTE));
diff --git a/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png b/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
new file mode 100644
index 0000000..7578b48
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
new file mode 100644
index 0000000..7b10f6b
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
new file mode 100644
index 0000000..41972cf
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
new file mode 100644
index 0000000..d26600b
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
new file mode 100644
index 0000000..1e7208e
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
new file mode 100644
index 0000000..ecef3ae
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
new file mode 100644
index 0000000..a02fd89
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
new file mode 100644
index 0000000..c309ac5
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
new file mode 100644
index 0000000..414fad4
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
new file mode 100644
index 0000000..c147a87
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
new file mode 100644
index 0000000..4ce2125
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 3bf4f90..dea194e 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -36,138 +36,69 @@
 
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
 
-    private static final int OPACITY_ENTER_DURATION = 600;
-    private static final int OPACITY_ENTER_DURATION_FAST = 120;
-    private static final int OPACITY_EXIT_DURATION = 480;
+    private static final int OPACITY_DURATION = 80;
 
-    // Hardware rendering properties.
-    private CanvasProperty<Paint> mPropPaint;
-    private CanvasProperty<Float> mPropRadius;
-    private CanvasProperty<Float> mPropX;
-    private CanvasProperty<Float> mPropY;
+    private ObjectAnimator mAnimator;
 
-    // Software rendering properties.
     private float mOpacity = 0;
 
     /** Whether this ripple is bounded. */
     private boolean mIsBounded;
 
-    public RippleBackground(RippleDrawable owner, Rect bounds, boolean isBounded,
-            boolean forceSoftware) {
-        super(owner, bounds, forceSoftware);
+    private boolean mFocused = false;
+    private boolean mHovered = false;
+
+    public RippleBackground(RippleDrawable owner, Rect bounds, boolean isBounded) {
+        super(owner, bounds);
 
         mIsBounded = isBounded;
     }
 
     public boolean isVisible() {
-        return mOpacity > 0 || isHardwareAnimating();
+        return mOpacity > 0;
     }
 
-    @Override
-    protected boolean drawSoftware(Canvas c, Paint p) {
-        boolean hasContent = false;
-
+    public void draw(Canvas c, Paint p) {
         final int origAlpha = p.getAlpha();
-        final int alpha = (int) (origAlpha * mOpacity + 0.5f);
+        final int alpha = Math.min((int) (origAlpha * mOpacity + 0.5f), 255);
         if (alpha > 0) {
             p.setAlpha(alpha);
             c.drawCircle(0, 0, mTargetRadius, p);
             p.setAlpha(origAlpha);
-            hasContent = true;
         }
-
-        return hasContent;
     }
 
-    @Override
-    protected boolean drawHardware(DisplayListCanvas c) {
-        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
-        return true;
-    }
-
-    @Override
-    protected Animator createSoftwareEnter(boolean fast) {
-        // Linear enter based on current opacity.
-        final int maxDuration = fast ? OPACITY_ENTER_DURATION_FAST : OPACITY_ENTER_DURATION;
-        final int duration = (int) ((1 - mOpacity) * maxDuration);
-
-        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
-        opacity.setAutoCancel(true);
-        opacity.setDuration(duration);
-        opacity.setInterpolator(LINEAR_INTERPOLATOR);
-
-        return opacity;
-    }
-
-    @Override
-    protected Animator createSoftwareExit() {
-        final AnimatorSet set = new AnimatorSet();
-
-        // Linear exit after enter is completed.
-        final ObjectAnimator exit = ObjectAnimator.ofFloat(this, OPACITY, 0);
-        exit.setInterpolator(LINEAR_INTERPOLATOR);
-        exit.setDuration(OPACITY_EXIT_DURATION);
-        exit.setAutoCancel(true);
-
-        final AnimatorSet.Builder builder = set.play(exit);
-
-        // Linear "fast" enter based on current opacity.
-        final int fastEnterDuration = mIsBounded ?
-                (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0;
-        if (fastEnterDuration > 0) {
-            final ObjectAnimator enter = ObjectAnimator.ofFloat(this, OPACITY, 1);
-            enter.setInterpolator(LINEAR_INTERPOLATOR);
-            enter.setDuration(fastEnterDuration);
-            enter.setAutoCancel(true);
-
-            builder.after(enter);
+    public void setState(boolean focused, boolean hovered, boolean animateChanged) {
+        if (mHovered != hovered || mFocused != focused) {
+            mHovered = hovered;
+            mFocused = focused;
+            onStateChanged(animateChanged);
         }
-
-        return set;
     }
 
-    @Override
-    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
-        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
-
-        final int targetAlpha = p.getAlpha();
-        final int currentAlpha = (int) (mOpacity * targetAlpha + 0.5f);
-        p.setAlpha(currentAlpha);
-
-        mPropPaint = CanvasProperty.createPaint(p);
-        mPropRadius = CanvasProperty.createFloat(mTargetRadius);
-        mPropX = CanvasProperty.createFloat(0);
-        mPropY = CanvasProperty.createFloat(0);
-
-        final int fastEnterDuration = mIsBounded ?
-                (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0;
-
-        // Linear exit after enter is completed.
-        final RenderNodeAnimator exit = new RenderNodeAnimator(
-                mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-        exit.setInterpolator(LINEAR_INTERPOLATOR);
-        exit.setDuration(OPACITY_EXIT_DURATION);
-        if (fastEnterDuration > 0) {
-            exit.setStartDelay(fastEnterDuration);
-            exit.setStartValue(targetAlpha);
+    private void onStateChanged(boolean animateChanged) {
+        float newOpacity = 0.0f;
+        if (mHovered) newOpacity += 1.0f;
+        if (mFocused) newOpacity += 1.0f;
+        if (mAnimator != null) {
+            mAnimator.cancel();
+            mAnimator = null;
         }
-        set.add(exit);
-
-        // Linear "fast" enter based on current opacity.
-        if (fastEnterDuration > 0) {
-            final RenderNodeAnimator enter = new RenderNodeAnimator(
-                    mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
-            enter.setInterpolator(LINEAR_INTERPOLATOR);
-            enter.setDuration(fastEnterDuration);
-            set.add(enter);
+        if (animateChanged) {
+            mAnimator = ObjectAnimator.ofFloat(this, OPACITY, newOpacity);
+            mAnimator.setDuration(OPACITY_DURATION);
+            mAnimator.setInterpolator(LINEAR_INTERPOLATOR);
+            mAnimator.start();
+        } else {
+            mOpacity = newOpacity;
         }
-
-        return set;
     }
 
-    @Override
-    protected void jumpValuesToExit() {
-        mOpacity = 0;
+    public void jumpToFinal() {
+        if (mAnimator != null) {
+            mAnimator.end();
+            mAnimator = null;
+        }
     }
 
     private static abstract class BackgroundProperty extends FloatProperty<RippleBackground> {
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index e83513c..0e38826 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -27,23 +27,14 @@
 import java.util.ArrayList;
 
 /**
- * Abstract class that handles hardware/software hand-off and lifecycle for
- * animated ripple foreground and background components.
+ * Abstract class that handles size & positioning common to the ripple & focus states.
  */
 abstract class RippleComponent {
-    private final RippleDrawable mOwner;
+    protected final RippleDrawable mOwner;
 
     /** Bounds used for computing max radius. May be modified by the owner. */
     protected final Rect mBounds;
 
-    /** Whether we can use hardware acceleration for the exit animation. */
-    private boolean mHasDisplayListCanvas;
-
-    private boolean mHasPendingHardwareAnimator;
-    private RenderNodeAnimatorSet mHardwareAnimator;
-
-    private Animator mSoftwareAnimator;
-
     /** Whether we have an explicit maximum radius. */
     private boolean mHasMaxRadius;
 
@@ -53,16 +44,9 @@
     /** Screen density used to adjust pixel-based constants. */
     protected float mDensityScale;
 
-    /**
-     * If set, force all ripple animations to not run on RenderThread, even if it would be
-     * available.
-     */
-    private final boolean mForceSoftware;
-
-    public RippleComponent(RippleDrawable owner, Rect bounds, boolean forceSoftware) {
+    public RippleComponent(RippleDrawable owner, Rect bounds) {
         mOwner = owner;
         mBounds = bounds;
-        mForceSoftware = forceSoftware;
     }
 
     public void onBoundsChange() {
@@ -92,89 +76,6 @@
     }
 
     /**
-     * Starts a ripple enter animation.
-     *
-     * @param fast whether the ripple should enter quickly
-     */
-    public final void enter(boolean fast) {
-        cancel();
-
-        mSoftwareAnimator = createSoftwareEnter(fast);
-
-        if (mSoftwareAnimator != null) {
-            mSoftwareAnimator.start();
-        }
-    }
-
-    /**
-     * Starts a ripple exit animation.
-     */
-    public final void exit() {
-        cancel();
-
-        if (mHasDisplayListCanvas) {
-            // We don't have access to a canvas here, but we expect one on the
-            // next frame. We'll start the render thread animation then.
-            mHasPendingHardwareAnimator = true;
-
-            // Request another frame.
-            invalidateSelf();
-        } else {
-            mSoftwareAnimator = createSoftwareExit();
-            mSoftwareAnimator.start();
-        }
-    }
-
-    /**
-     * Cancels all animations. Software animation values are left in the
-     * current state, while hardware animation values jump to the end state.
-     */
-    public void cancel() {
-        cancelSoftwareAnimations();
-        endHardwareAnimations();
-    }
-
-    /**
-     * Ends all animations, jumping values to the end state.
-     */
-    public void end() {
-        endSoftwareAnimations();
-        endHardwareAnimations();
-    }
-
-    /**
-     * Draws the ripple to the canvas, inheriting the paint's color and alpha
-     * properties.
-     *
-     * @param c the canvas to which the ripple should be drawn
-     * @param p the paint used to draw the ripple
-     * @return {@code true} if something was drawn, {@code false} otherwise
-     */
-    public boolean draw(Canvas c, Paint p) {
-        final boolean hasDisplayListCanvas = !mForceSoftware && c.isHardwareAccelerated()
-                && c instanceof DisplayListCanvas;
-        if (mHasDisplayListCanvas != hasDisplayListCanvas) {
-            mHasDisplayListCanvas = hasDisplayListCanvas;
-
-            if (!hasDisplayListCanvas) {
-                // We've switched from hardware to non-hardware mode. Panic.
-                endHardwareAnimations();
-            }
-        }
-
-        if (hasDisplayListCanvas) {
-            final DisplayListCanvas hw = (DisplayListCanvas) c;
-            startPendingAnimation(hw, p);
-
-            if (mHardwareAnimator != null) {
-                return drawHardware(hw);
-            }
-        }
-
-        return drawSoftware(c, p);
-    }
-
-    /**
      * Populates {@code bounds} with the maximum drawing bounds of the ripple
      * relative to its center. The resulting bounds should be translated into
      * parent drawable coordinates before use.
@@ -186,77 +87,10 @@
         bounds.set(-r, -r, r, r);
     }
 
-    /**
-     * Starts the pending hardware animation, if available.
-     *
-     * @param hw hardware canvas on which the animation should draw
-     * @param p paint whose properties the hardware canvas should use
-     */
-    private void startPendingAnimation(DisplayListCanvas hw, Paint p) {
-        if (mHasPendingHardwareAnimator) {
-            mHasPendingHardwareAnimator = false;
-
-            mHardwareAnimator = createHardwareExit(new Paint(p));
-            mHardwareAnimator.start(hw);
-
-            // Preemptively jump the software values to the end state now that
-            // the hardware exit has read whatever values it needs.
-            jumpValuesToExit();
-        }
-    }
-
-    /**
-     * Cancels any current software animations, leaving the values in their
-     * current state.
-     */
-    private void cancelSoftwareAnimations() {
-        if (mSoftwareAnimator != null) {
-            mSoftwareAnimator.cancel();
-            mSoftwareAnimator = null;
-        }
-    }
-
-    /**
-     * Ends any current software animations, jumping the values to their end
-     * state.
-     */
-    private void endSoftwareAnimations() {
-        if (mSoftwareAnimator != null) {
-            mSoftwareAnimator.end();
-            mSoftwareAnimator = null;
-        }
-    }
-
-    /**
-     * Ends any pending or current hardware animations.
-     * <p>
-     * Hardware animations can't synchronize values back to the software
-     * thread, so there is no "cancel" equivalent.
-     */
-    private void endHardwareAnimations() {
-        if (mHardwareAnimator != null) {
-            mHardwareAnimator.end();
-            mHardwareAnimator = null;
-        }
-
-        if (mHasPendingHardwareAnimator) {
-            mHasPendingHardwareAnimator = false;
-
-            // Manually jump values to their exited state. Normally we'd do that
-            // later when starting the hardware exit, but we're aborting early.
-            jumpValuesToExit();
-        }
-    }
-
     protected final void invalidateSelf() {
         mOwner.invalidateSelf(false);
     }
 
-    protected final boolean isHardwareAnimating() {
-        return mHardwareAnimator != null && mHardwareAnimator.isRunning()
-                || mHasPendingHardwareAnimator;
-    }
-
     protected final void onHotspotBoundsChanged() {
         if (!mHasMaxRadius) {
             final float halfWidth = mBounds.width() / 2.0f;
@@ -276,76 +110,4 @@
     protected void onTargetRadiusChanged(float targetRadius) {
         // Stub.
     }
-
-    protected abstract Animator createSoftwareEnter(boolean fast);
-
-    protected abstract Animator createSoftwareExit();
-
-    protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p);
-
-    protected abstract boolean drawHardware(DisplayListCanvas c);
-
-    protected abstract boolean drawSoftware(Canvas c, Paint p);
-
-    /**
-     * Called when the hardware exit is cancelled. Jumps software values to end
-     * state to ensure that software and hardware values are synchronized.
-     */
-    protected abstract void jumpValuesToExit();
-
-    public static class RenderNodeAnimatorSet {
-        private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>();
-
-        public void add(RenderNodeAnimator anim) {
-            mAnimators.add(anim);
-        }
-
-        public void clear() {
-            mAnimators.clear();
-        }
-
-        public void start(DisplayListCanvas target) {
-            if (target == null) {
-                throw new IllegalArgumentException("Hardware canvas must be non-null");
-            }
-
-            final ArrayList<RenderNodeAnimator> animators = mAnimators;
-            final int N = animators.size();
-            for (int i = 0; i < N; i++) {
-                final RenderNodeAnimator anim = animators.get(i);
-                anim.setTarget(target);
-                anim.start();
-            }
-        }
-
-        public void cancel() {
-            final ArrayList<RenderNodeAnimator> animators = mAnimators;
-            final int N = animators.size();
-            for (int i = 0; i < N; i++) {
-                final RenderNodeAnimator anim = animators.get(i);
-                anim.cancel();
-            }
-        }
-
-        public void end() {
-            final ArrayList<RenderNodeAnimator> animators = mAnimators;
-            final int N = animators.size();
-            for (int i = 0; i < N; i++) {
-                final RenderNodeAnimator anim = animators.get(i);
-                anim.end();
-            }
-        }
-
-        public boolean isRunning() {
-            final ArrayList<RenderNodeAnimator> animators = mAnimators;
-            final int N = animators.size();
-            for (int i = 0; i < N; i++) {
-                final RenderNodeAnimator anim = animators.get(i);
-                if (anim.isRunning()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
 }
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 1727eca..8b185f2 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -16,11 +16,6 @@
 
 package android.graphics.drawable;
 
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo.Config;
@@ -42,6 +37,11 @@
 import android.graphics.Shader;
 import android.util.AttributeSet;
 
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.util.Arrays;
 
@@ -135,9 +135,6 @@
     private PorterDuffColorFilter mMaskColorFilter;
     private boolean mHasValidMask;
 
-    /** Whether we expect to draw a background when visible. */
-    private boolean mBackgroundActive;
-
     /** The current ripple. May be actively animating or pending entry. */
     private RippleForeground mRipple;
 
@@ -217,7 +214,7 @@
         }
 
         if (mBackground != null) {
-            mBackground.end();
+            mBackground.jumpToFinal();
         }
 
         cancelExitingRipples();
@@ -266,9 +263,9 @@
             }
         }
 
-        setRippleActive(focused || (enabled && pressed));
+        setRippleActive(enabled && pressed);
 
-        setBackgroundActive(hovered, hovered);
+        setBackgroundActive(hovered, focused);
         return changed;
     }
 
@@ -283,14 +280,13 @@
         }
     }
 
-    private void setBackgroundActive(boolean active, boolean focused) {
-        if (mBackgroundActive != active) {
-            mBackgroundActive = active;
-            if (active) {
-                tryBackgroundEnter(focused);
-            } else {
-                tryBackgroundExit();
-            }
+    private void setBackgroundActive(boolean hovered, boolean focused) {
+        if (mBackground == null && (hovered || focused)) {
+            mBackground = new RippleBackground(this, mHotspotBounds, isBounded());
+            mBackground.setup(mState.mMaxRadius, mDensity);
+        }
+        if (mBackground != null) {
+            mBackground.setState(focused, hovered, true);
         }
     }
 
@@ -327,10 +323,6 @@
                 tryRippleEnter();
             }
 
-            if (mBackgroundActive) {
-                tryBackgroundEnter(false);
-            }
-
             // Skip animations, just show the correct final states.
             jumpToCurrentState();
         }
@@ -546,26 +538,6 @@
     }
 
     /**
-     * Creates an active hotspot at the specified location.
-     */
-    private void tryBackgroundEnter(boolean focused) {
-        if (mBackground == null) {
-            final boolean isBounded = isBounded();
-            mBackground = new RippleBackground(this, mHotspotBounds, isBounded, mForceSoftware);
-        }
-
-        mBackground.setup(mState.mMaxRadius, mDensity);
-        mBackground.enter(focused);
-    }
-
-    private void tryBackgroundExit() {
-        if (mBackground != null) {
-            // Don't null out the background, we need it to draw!
-            mBackground.exit();
-        }
-    }
-
-    /**
      * Attempts to start an enter animation for the active hotspot. Fails if
      * there are too many animating ripples.
      */
@@ -593,7 +565,7 @@
         }
 
         mRipple.setup(mState.mMaxRadius, mDensity);
-        mRipple.enter(false);
+        mRipple.enter();
     }
 
     /**
@@ -623,9 +595,7 @@
         }
 
         if (mBackground != null) {
-            mBackground.end();
-            mBackground = null;
-            mBackgroundActive = false;
+            mBackground.setState(false, false, false);
         }
 
         cancelExitingRipples();
@@ -858,38 +828,8 @@
         final float y = mHotspotBounds.exactCenterY();
         canvas.translate(x, y);
 
-        updateMaskShaderIfNeeded();
-
-        // Position the shader to account for canvas translation.
-        if (mMaskShader != null) {
-            final Rect bounds = getBounds();
-            mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
-            mMaskShader.setLocalMatrix(mMaskMatrix);
-        }
-
-        // Grab the color for the current state and cut the alpha channel in
-        // half so that the ripple and background together yield full alpha.
-        final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
-        final int halfAlpha = (Color.alpha(color) / 2) << 24;
         final Paint p = getRipplePaint();
 
-        if (mMaskColorFilter != null) {
-            // The ripple timing depends on the paint's alpha value, so we need
-            // to push just the alpha channel into the paint and let the filter
-            // handle the full-alpha color.
-            final int fullAlphaColor = color | (0xFF << 24);
-            mMaskColorFilter.setColor(fullAlphaColor);
-
-            p.setColor(halfAlpha);
-            p.setColorFilter(mMaskColorFilter);
-            p.setShader(mMaskShader);
-        } else {
-            final int halfAlphaColor = (color & 0xFFFFFF) | halfAlpha;
-            p.setColor(halfAlphaColor);
-            p.setColorFilter(null);
-            p.setShader(null);
-        }
-
         if (background != null && background.isVisible()) {
             background.draw(canvas, p);
         }
@@ -912,13 +852,49 @@
         mMask.draw(canvas);
     }
 
-    private Paint getRipplePaint() {
+    Paint getRipplePaint() {
         if (mRipplePaint == null) {
             mRipplePaint = new Paint();
             mRipplePaint.setAntiAlias(true);
             mRipplePaint.setStyle(Paint.Style.FILL);
         }
-        return mRipplePaint;
+
+        final float x = mHotspotBounds.exactCenterX();
+        final float y = mHotspotBounds.exactCenterY();
+
+        updateMaskShaderIfNeeded();
+
+        // Position the shader to account for canvas translation.
+        if (mMaskShader != null) {
+            final Rect bounds = getBounds();
+            mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
+            mMaskShader.setLocalMatrix(mMaskMatrix);
+        }
+
+        // Grab the color for the current state and cut the alpha channel in
+        // half so that the ripple and background together yield full alpha.
+        final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
+        final int halfAlpha = (Color.alpha(color) / 2) << 24;
+        final Paint p = mRipplePaint;
+
+        if (mMaskColorFilter != null) {
+            // The ripple timing depends on the paint's alpha value, so we need
+            // to push just the alpha channel into the paint and let the filter
+            // handle the full-alpha color.
+            final int fullAlphaColor = color | (0xFF << 24);
+            mMaskColorFilter.setColor(fullAlphaColor);
+
+            p.setColor(halfAlpha);
+            p.setColorFilter(mMaskColorFilter);
+            p.setShader(mMaskShader);
+        } else {
+            final int halfAlphaColor = (color & 0xFFFFFF) | halfAlpha;
+            p.setColor(halfAlphaColor);
+            p.setColorFilter(null);
+            p.setShader(null);
+        }
+
+        return p;
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index a675eaf..0b5020c 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
@@ -29,8 +28,11 @@
 import android.util.MathUtils;
 import android.view.DisplayListCanvas;
 import android.view.RenderNodeAnimator;
+import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
 
+import java.util.ArrayList;
+
 /**
  * Draws a ripple foreground.
  */
@@ -40,7 +42,7 @@
             400f, 1.4f, 0);
 
     // Pixel-based accelerations and velocities.
-    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024;
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 2048;
     private static final float WAVE_OPACITY_DECAY_VELOCITY = 3;
 
     // Bounded ripple animation properties.
@@ -49,8 +51,9 @@
     private static final int BOUNDED_OPACITY_EXIT_DURATION = 400;
     private static final float MAX_BOUNDED_RADIUS = 350;
 
-    private static final int RIPPLE_ENTER_DELAY = 80;
-    private static final int OPACITY_ENTER_DURATION_FAST = 120;
+    private static final int OPACITY_ENTER_DURATION = 75;
+    private static final int OPACITY_EXIT_DURATION = 150;
+    private static final int OPACITY_HOLD_DURATION = OPACITY_ENTER_DURATION + 150;
 
     // Parent-relative values for starting position.
     private float mStartingX;
@@ -72,7 +75,7 @@
     private float mBoundedRadius = 0;
 
     // Software rendering properties.
-    private float mOpacity = 1;
+    private float mOpacity = 0;
 
     // Values used to tween between the start and end positions.
     private float mTweenRadius = 0;
@@ -82,6 +85,22 @@
     /** Whether this ripple has finished its exit animation. */
     private boolean mHasFinishedExit;
 
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mUsingProperties;
+
+    private long mEnterStartedAtMillis;
+
+    private ArrayList<RenderNodeAnimator> mPendingHwAnimators = new ArrayList<>();
+    private ArrayList<RenderNodeAnimator> mRunningHwAnimators = new ArrayList<>();
+
+    private ArrayList<Animator> mRunningSwAnimators = new ArrayList<>();
+
+    /**
+     * If set, force all ripple animations to not run on RenderThread, even if it would be
+     * available.
+     */
+    private final boolean mForceSoftware;
+
     /**
      * If we have a bound, don't start from 0. Start from 60% of the max out of width and height.
      */
@@ -89,8 +108,9 @@
 
     public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
             boolean isBounded, boolean forceSoftware) {
-        super(owner, bounds, forceSoftware);
+        super(owner, bounds);
 
+        mForceSoftware = forceSoftware;
         mStartingX = startingX;
         mStartingY = startingY;
 
@@ -109,10 +129,7 @@
         clampStartingPosition();
     }
 
-    @Override
-    protected boolean drawSoftware(Canvas c, Paint p) {
-        boolean hasContent = false;
-
+    private void drawSoftware(Canvas c, Paint p) {
         final int origAlpha = p.getAlpha();
         final int alpha = (int) (origAlpha * mOpacity + 0.5f);
         final float radius = getCurrentRadius();
@@ -122,16 +139,51 @@
             p.setAlpha(alpha);
             c.drawCircle(x, y, radius, p);
             p.setAlpha(origAlpha);
-            hasContent = true;
         }
-
-        return hasContent;
     }
 
-    @Override
-    protected boolean drawHardware(DisplayListCanvas c) {
-        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
-        return true;
+    private void startPending(DisplayListCanvas c) {
+        if (!mPendingHwAnimators.isEmpty()) {
+            for (int i = 0; i < mPendingHwAnimators.size(); i++) {
+                RenderNodeAnimator animator = mPendingHwAnimators.get(i);
+                animator.setTarget(c);
+                animator.start();
+                mRunningHwAnimators.add(animator);
+            }
+            mPendingHwAnimators.clear();
+        }
+    }
+
+    private void pruneHwFinished() {
+        if (!mRunningHwAnimators.isEmpty()) {
+            for (int i = mRunningHwAnimators.size() - 1; i >= 0; i--) {
+                if (!mRunningHwAnimators.get(i).isRunning()) {
+                    mRunningHwAnimators.remove(i);
+                }
+            }
+        }
+    }
+
+    private void pruneSwFinished() {
+        if (!mRunningSwAnimators.isEmpty()) {
+            for (int i = mRunningSwAnimators.size() - 1; i >= 0; i--) {
+                if (!mRunningSwAnimators.get(i).isRunning()) {
+                    mRunningSwAnimators.remove(i);
+                }
+            }
+        }
+    }
+
+    private void drawHardware(DisplayListCanvas c, Paint p) {
+        startPending(c);
+        pruneHwFinished();
+        if (mPropPaint != null) {
+            mUsingProperties = true;
+            c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+        } else {
+            mUsingProperties = false;
+            drawSoftware(c, p);
+        }
     }
 
     /**
@@ -162,31 +214,115 @@
         return mHasFinishedExit;
     }
 
-    @Override
-    protected Animator createSoftwareEnter(boolean fast) {
+    private long computeFadeOutDelay() {
+        long timeSinceEnter = AnimationUtils.currentAnimationTimeMillis() - mEnterStartedAtMillis;
+        if (timeSinceEnter > 0 && timeSinceEnter < OPACITY_HOLD_DURATION) {
+            return OPACITY_HOLD_DURATION - timeSinceEnter;
+        }
+        return 0;
+    }
+
+    private void startSoftwareEnter() {
+        for (int i = 0; i < mRunningSwAnimators.size(); i++) {
+            mRunningSwAnimators.get(i).cancel();
+        }
+        mRunningSwAnimators.clear();
+
         final int duration = getRadiusDuration();
 
         final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
-        tweenRadius.setAutoCancel(true);
         tweenRadius.setDuration(duration);
         tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
-        tweenRadius.setStartDelay(RIPPLE_ENTER_DELAY);
+        tweenRadius.start();
+        mRunningSwAnimators.add(tweenRadius);
 
         final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
-        tweenOrigin.setAutoCancel(true);
         tweenOrigin.setDuration(duration);
         tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
-        tweenOrigin.setStartDelay(RIPPLE_ENTER_DELAY);
+        tweenOrigin.start();
+        mRunningSwAnimators.add(tweenOrigin);
 
         final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
-        opacity.setAutoCancel(true);
-        opacity.setDuration(OPACITY_ENTER_DURATION_FAST);
+        opacity.setDuration(OPACITY_ENTER_DURATION);
         opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.start();
+        mRunningSwAnimators.add(opacity);
+    }
 
-        final AnimatorSet set = new AnimatorSet();
-        set.play(tweenOrigin).with(tweenRadius).with(opacity);
+    private void startSoftwareExit() {
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0);
+        opacity.setDuration(OPACITY_EXIT_DURATION);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.addListener(mAnimationListener);
+        opacity.setStartDelay(computeFadeOutDelay());
+        opacity.start();
+        mRunningSwAnimators.add(opacity);
+    }
 
-        return set;
+    private void startHardwareEnter() {
+        if (mForceSoftware) { return; }
+        mPropX = CanvasProperty.createFloat(getCurrentX());
+        mPropY = CanvasProperty.createFloat(getCurrentY());
+        mPropRadius = CanvasProperty.createFloat(getCurrentRadius());
+        final Paint paint = mOwner.getRipplePaint();
+        mPropPaint = CanvasProperty.createPaint(paint);
+
+        final int radiusDuration = getRadiusDuration();
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);
+        radius.setDuration(radiusDuration);
+        radius.setInterpolator(DECELERATE_INTERPOLATOR);
+        mPendingHwAnimators.add(radius);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
+        x.setDuration(radiusDuration);
+        x.setInterpolator(DECELERATE_INTERPOLATOR);
+        mPendingHwAnimators.add(x);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
+        y.setDuration(radiusDuration);
+        y.setInterpolator(DECELERATE_INTERPOLATOR);
+        mPendingHwAnimators.add(y);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, paint.getAlpha());
+        opacity.setDuration(OPACITY_ENTER_DURATION);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.setStartValue(0);
+        mPendingHwAnimators.add(opacity);
+
+        invalidateSelf();
+    }
+
+    private void startHardwareExit() {
+        // Only run a hardware exit if we had a hardware enter to continue from
+        if (mForceSoftware || mPropPaint == null) return;
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(OPACITY_EXIT_DURATION);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.addListener(mAnimationListener);
+        opacity.setStartDelay(computeFadeOutDelay());
+        mPendingHwAnimators.add(opacity);
+        invalidateSelf();
+    }
+
+    /**
+     * Starts a ripple enter animation.
+     */
+    public final void enter() {
+        mEnterStartedAtMillis = AnimationUtils.currentAnimationTimeMillis();
+        startSoftwareEnter();
+        startHardwareEnter();
+    }
+
+    /**
+     * Starts a ripple exit animation.
+     */
+    public final void exit() {
+        startSoftwareExit();
+        startHardwareExit();
     }
 
     private float getCurrentX() {
@@ -207,96 +343,23 @@
         return MathUtils.lerp(mStartRadius, mTargetRadius, mTweenRadius);
     }
 
-    private int getOpacityExitDuration() {
-        return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
-    }
+    /**
+     * Draws the ripple to the canvas, inheriting the paint's color and alpha
+     * properties.
+     *
+     * @param c the canvas to which the ripple should be drawn
+     * @param p the paint used to draw the ripple
+     */
+    public void draw(Canvas c, Paint p) {
+        final boolean hasDisplayListCanvas = !mForceSoftware && c instanceof DisplayListCanvas;
 
-    @Override
-    protected Animator createSoftwareExit() {
-        final int radiusDuration;
-        final int originDuration;
-        final int opacityDuration;
-
-        radiusDuration = getRadiusDuration();
-        originDuration = radiusDuration;
-        opacityDuration = getOpacityExitDuration();
-
-        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
-        tweenRadius.setAutoCancel(true);
-        tweenRadius.setDuration(radiusDuration);
-        tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
-
-        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
-        tweenOrigin.setAutoCancel(true);
-        tweenOrigin.setDuration(originDuration);
-        tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
-
-        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0);
-        opacity.setAutoCancel(true);
-        opacity.setDuration(opacityDuration);
-        opacity.setInterpolator(LINEAR_INTERPOLATOR);
-
-        final AnimatorSet set = new AnimatorSet();
-        set.play(tweenOrigin).with(tweenRadius).with(opacity);
-        set.addListener(mAnimationListener);
-
-        return set;
-    }
-
-    @Override
-    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
-        final int radiusDuration;
-        final int originDuration;
-        final int opacityDuration;
-
-        radiusDuration = getRadiusDuration();
-        originDuration = radiusDuration;
-        opacityDuration = getOpacityExitDuration();
-
-        final float startX = getCurrentX();
-        final float startY = getCurrentY();
-        final float startRadius = getCurrentRadius();
-
-        p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f));
-
-        mPropPaint = CanvasProperty.createPaint(p);
-        mPropRadius = CanvasProperty.createFloat(startRadius);
-        mPropX = CanvasProperty.createFloat(startX);
-        mPropY = CanvasProperty.createFloat(startY);
-
-        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);
-        radius.setDuration(radiusDuration);
-        radius.setInterpolator(DECELERATE_INTERPOLATOR);
-
-        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
-        x.setDuration(originDuration);
-        x.setInterpolator(DECELERATE_INTERPOLATOR);
-
-        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
-        y.setDuration(originDuration);
-        y.setInterpolator(DECELERATE_INTERPOLATOR);
-
-        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
-                RenderNodeAnimator.PAINT_ALPHA, 0);
-        opacity.setDuration(opacityDuration);
-        opacity.setInterpolator(LINEAR_INTERPOLATOR);
-        opacity.addListener(mAnimationListener);
-
-        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
-        set.add(radius);
-        set.add(opacity);
-        set.add(x);
-        set.add(y);
-
-        return set;
-    }
-
-    @Override
-    protected void jumpValuesToExit() {
-        mOpacity = 0;
-        mTweenX = 1;
-        mTweenY = 1;
-        mTweenRadius = 1;
+        pruneSwFinished();
+        if (hasDisplayListCanvas) {
+            final DisplayListCanvas hw = (DisplayListCanvas) c;
+            drawHardware(hw, p);
+        } else {
+            drawSoftware(c, p);
+        }
     }
 
     /**
@@ -319,10 +382,39 @@
         }
     }
 
+    /**
+     * Ends all animations, jumping values to the end state.
+     */
+    public void end() {
+        for (int i = 0; i < mRunningSwAnimators.size(); i++) {
+            mRunningSwAnimators.get(i).end();
+        }
+        mRunningSwAnimators.clear();
+        for (int i = 0; i < mRunningHwAnimators.size(); i++) {
+            mRunningHwAnimators.get(i).end();
+        }
+        mRunningHwAnimators.clear();
+    }
+
+    private void onAnimationPropertyChanged() {
+        if (!mUsingProperties) {
+            invalidateSelf();
+        }
+    }
+
     private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animator) {
             mHasFinishedExit = true;
+            pruneHwFinished();
+            pruneSwFinished();
+
+            if (mRunningHwAnimators.isEmpty()) {
+                mPropPaint = null;
+                mPropRadius = null;
+                mPropX = null;
+                mPropY = null;
+            }
         }
     };
 
@@ -361,7 +453,7 @@
         @Override
         public void setValue(RippleForeground object, float value) {
             object.mTweenRadius = value;
-            object.invalidateSelf();
+            object.onAnimationPropertyChanged();
         }
 
         @Override
@@ -375,18 +467,18 @@
      */
     private static final FloatProperty<RippleForeground> TWEEN_ORIGIN =
             new FloatProperty<RippleForeground>("tweenOrigin") {
-                @Override
-                public void setValue(RippleForeground object, float value) {
-                    object.mTweenX = value;
-                    object.mTweenY = value;
-                    object.invalidateSelf();
-                }
+        @Override
+        public void setValue(RippleForeground object, float value) {
+            object.mTweenX = value;
+            object.mTweenY = value;
+            object.onAnimationPropertyChanged();
+        }
 
-                @Override
-                public Float get(RippleForeground object) {
-                    return object.mTweenX;
-                }
-            };
+        @Override
+        public Float get(RippleForeground object) {
+            return object.mTweenX;
+        }
+    };
 
     /**
      * Property for animating opacity between 0 and its target value.
@@ -396,7 +488,7 @@
         @Override
         public void setValue(RippleForeground object, float value) {
             object.mOpacity = value;
-            object.invalidateSelf();
+            object.onAnimationPropertyChanged();
         }
 
         @Override
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index bec22c9..4c150c8 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -146,6 +146,7 @@
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src/android) \
     $(call all-java-files-under, ../test-runner/src/android) \
+    $(call all-java-files-under, ../test-mock/src/android) \
     $(call all-java-files-under, src/com)
 LOCAL_MODULE := legacy-android-test
 LOCAL_NO_STANDARD_LIBRARIES := true
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 24ce1e4..5c577ae 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -2,9 +2,10 @@
     name: "hwui_defaults",
     defaults: [
         "hwui_static_deps",
-        "skia_deps"
+        "skia_deps",
         //"hwui_bugreport_font_cache_usage",
         //"hwui_compile_for_perf",
+        "hwui_pgo",
     ],
 
     cpp_std: "c++17",
@@ -109,6 +110,22 @@
     include_dirs: ["frameworks/native/opengl/libs/GLES2"],
 }
 
+// Build libhwui with PGO by default.
+// Location of PGO profile data is defined in build/soong/cc/pgo.go
+// and is separate from hwui.
+// To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable
+// or set enable_profile_use property to false.
+cc_defaults {
+    name: "hwui_pgo",
+
+    pgo: {
+        instrumentation: true,
+        profile_file: "hwui/hwui.profdata",
+        benchmarks: ["hwui"],
+        enable_profile_use: false,
+    },
+}
+
 // ------------------------
 // library
 // ------------------------
@@ -255,18 +272,6 @@
         // Has moderate overhead
         "hwui_enable_opengl_validation",
     ],
-
-    // Build libhwui with PGO by default.
-    // Location of PGO profile data is defined in build/soong/cc/pgo.go
-    // and is separate from hwui.
-    // To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable
-    // or set enable_profile_use property to false.
-    pgo: {
-        instrumentation: true,
-        profile_file: "hwui/hwui.profdata",
-        benchmarks: ["hwui"],
-        enable_profile_use: false,
-    },
 }
 
 // ------------------------
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index ce41849..faea9b2 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -110,6 +110,12 @@
     void end(long long token);
 
     /**
+     * Returns how many bytes are buffered in ProtoOutputStream.
+     * Notice, this is not the actual(compact) size of the output data.
+     */
+    size_t bytesWritten();
+
+    /**
      * Flushes the protobuf data out to given fd. When the following functions are called,
      * it is not able to write to ProtoOutputStream any more since the data is compact.
      */
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 9d8ee72..1904d40 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -295,6 +295,12 @@
     }
 }
 
+size_t
+ProtoOutputStream::bytesWritten()
+{
+    return mBuffer.size();
+}
+
 bool
 ProtoOutputStream::compact() {
     if (mCompact) return true;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 1feea89..12e5744 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -91,10 +91,10 @@
  * are only decrypted when the samples are delivered to the decoder.
  * <p>
  * MediaDrm methods throw {@link android.media.MediaDrm.MediaDrmStateException}
- * when a method is called on a MediaDrm object that has had an unrecoverable failure 
- * in the DRM plugin or security hardware. 
- * {@link android.media.MediaDrm.MediaDrmStateException} extends 
- * {@link java.lang.IllegalStateException} with the addition of a developer-readable 
+ * when a method is called on a MediaDrm object that has had an unrecoverable failure
+ * in the DRM plugin or security hardware.
+ * {@link android.media.MediaDrm.MediaDrmStateException} extends
+ * {@link java.lang.IllegalStateException} with the addition of a developer-readable
  * diagnostic information string associated with the exception.
  * <p>
  * In the event of a mediaserver process crash or restart while a MediaDrm object
@@ -102,9 +102,9 @@
  * To recover, the app must release the MediaDrm object, then create and initialize
  * a new one.
  * <p>
- * As {@link android.media.MediaDrmResetException} and 
- * {@link android.media.MediaDrm.MediaDrmStateException} both extend 
- * {@link java.lang.IllegalStateException}, they should be in an earlier catch() 
+ * As {@link android.media.MediaDrmResetException} and
+ * {@link android.media.MediaDrm.MediaDrmStateException} both extend
+ * {@link java.lang.IllegalStateException}, they should be in an earlier catch()
  * block than {@link java.lang.IllegalStateException} if handled separately.
  * <p>
  * <a name="Callbacks"></a>
@@ -165,7 +165,7 @@
 
     /**
      * Query if the given scheme identified by its UUID is supported on
-     * this device, and whether the drm plugin is able to handle the
+     * this device, and whether the DRM plugin is able to handle the
      * media container format specified by mimeType.
      * @param uuid The UUID of the crypto scheme.
      * @param mimeType The MIME type of the media container, e.g. "video/mp4"
@@ -745,7 +745,7 @@
      * returned in KeyRequest.defaultUrl.
      * <p>
      * After the app has received the key request response from the server,
-     * it should deliver to the response to the DRM engine plugin using the method
+     * it should deliver to the response to the MediaDrm instance using the method
      * {@link #provideKeyResponse}.
      *
      * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
@@ -781,7 +781,7 @@
 
     /**
      * A key response is received from the license server by the app, then it is
-     * provided to the DRM engine plugin using provideKeyResponse.  When the
+     * provided to the MediaDrm instance using provideKeyResponse.  When the
      * response is for an offline key request, a keySetId is returned that can be
      * used to later restore the keys to a new session with the method
      * {@link #restoreKeys}.
@@ -829,7 +829,7 @@
      * in the form of {name, value} pairs.  Since DRM license policies vary by vendor,
      * the specific status field names are determined by each DRM vendor.  Refer to your
      * DRM provider documentation for definitions of the field names for a particular
-     * DRM engine plugin.
+     * DRM plugin.
      *
      * @param sessionId the session ID for the DRM session
      */
@@ -897,11 +897,11 @@
            @NonNull String certAuthority);
 
     /**
-     * After a provision response is received by the app, it is provided to the DRM
-     * engine plugin using this method.
+     * After a provision response is received by the app, it is provided to the
+     * MediaDrm instance using this method.
      *
      * @param response the opaque provisioning response byte array to provide to the
-     * DRM engine plugin.
+     * MediaDrm instance.
      *
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
@@ -912,7 +912,6 @@
     }
 
     @NonNull
-    /* could there be a valid response with 0-sized certificate or key? */
     private native Certificate provideProvisionResponseNative(@NonNull byte[] response)
             throws DeniedByServerException;
 
@@ -953,26 +952,26 @@
     /**
      * Remove all secure stops without requiring interaction with the server.
      */
-     public native void releaseAllSecureStops();
+    public native void releaseAllSecureStops();
 
     /**
-     * String property name: identifies the maker of the DRM engine plugin
+     * String property name: identifies the maker of the DRM plugin
      */
     public static final String PROPERTY_VENDOR = "vendor";
 
     /**
-     * String property name: identifies the version of the DRM engine plugin
+     * String property name: identifies the version of the DRM plugin
      */
     public static final String PROPERTY_VERSION = "version";
 
     /**
-     * String property name: describes the DRM engine plugin
+     * String property name: describes the DRM plugin
      */
     public static final String PROPERTY_DESCRIPTION = "description";
 
     /**
      * String property name: a comma-separated list of cipher and mac algorithms
-     * supported by CryptoSession.  The list may be empty if the DRM engine
+     * supported by CryptoSession.  The list may be empty if the DRM
      * plugin does not support CryptoSession operations.
      */
     public static final String PROPERTY_ALGORITHMS = "algorithms";
@@ -988,7 +987,7 @@
     public @interface StringProperty {}
 
     /**
-     * Read a DRM engine plugin String property value, given the property name string.
+     * Read a MediaDrm String property value, given the property name string.
      * <p>
      * Standard fields names are:
      * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
@@ -998,6 +997,13 @@
     public native String getPropertyString(@NonNull @StringProperty String propertyName);
 
     /**
+     * Set a MediaDrm String property value, given the property name string
+     * and new value for the property.
+     */
+    public native void setPropertyString(@NonNull @StringProperty String propertyName,
+            @NonNull String value);
+
+    /**
      * Byte array property name: the device unique identifier is established during
      * device provisioning and provides a means of uniquely identifying each device.
      */
@@ -1011,7 +1017,7 @@
     public @interface ArrayProperty {}
 
     /**
-     * Read a DRM engine plugin byte array property value, given the property name string.
+     * Read a MediaDrm byte array property value, given the property name string.
      * <p>
      * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
      */
@@ -1019,17 +1025,13 @@
     public native byte[] getPropertyByteArray(@ArrayProperty String propertyName);
 
     /**
-     * Set a DRM engine plugin String property value.
-     */
-    public native void setPropertyString(
-            String propertyName, @NonNull String value);
-
-    /**
-     * Set a DRM engine plugin byte array property value.
-     */
-    public native void setPropertyByteArray(
+    * Set a MediaDrm byte array property value, given the property name string
+    * and new value for the property.
+    */
+    public native void setPropertyByteArray(@NonNull @ArrayProperty
             String propertyName, @NonNull byte[] value);
 
+
     private static final native void setCipherAlgorithmNative(
             @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
 
@@ -1158,7 +1160,7 @@
      * The algorithm string conforms to JCA Standard Names for Mac
      * Algorithms and is case insensitive.  For example "HmacSHA256".
      * <p>
-     * The list of supported algorithms for a DRM engine plugin can be obtained
+     * The list of supported algorithms for a DRM plugin can be obtained
      * using the method {@link #getPropertyString} with the property name
      * "algorithms".
      */
@@ -1272,7 +1274,7 @@
      * storage, and used when invoking the signRSA method.
      *
      * @param response the opaque certificate response byte array to provide to the
-     * DRM engine plugin.
+     * MediaDrm instance.
      *
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index bdc0fda..31eb948 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -34,6 +34,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Set;
+import java.util.Objects;
 
 /**
  * Contains metadata about an item, such as the title, artist, etc.
@@ -616,6 +617,71 @@
             };
 
     /**
+     * Compares the contents of this object to another MediaMetadata object. It
+     * does not compare Bitmaps and Ratings as the media player can choose to
+     * forgo these fields depending on how you retrieve the MediaMetadata.
+     *
+     * @param o The Metadata object to compare this object against
+     * @return Whether or not the two objects have matching fields (excluding
+     * Bitmaps and Ratings)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof MediaMetadata)) {
+            return false;
+        }
+
+        final MediaMetadata m = (MediaMetadata) o;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    if (!Objects.equals(getString(key), m.getString(key))) {
+                        return false;
+                    }
+                    break;
+                case METADATA_TYPE_LONG:
+                    if (getLong(key) != m.getLong(key)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode = 17;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    hashCode = 31 * hashCode + Objects.hash(getString(key));
+                    break;
+                case METADATA_TYPE_LONG:
+                    hashCode = 31 * hashCode + Long.hashCode(getLong(key));
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return hashCode;
+    }
+
+    /**
      * Use to build MediaMetadata objects. The system defined metadata keys must
      * use the appropriate data type.
      */
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 4bb16ff..26fd750 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -732,6 +732,11 @@
     <!-- UI debug setting: profile time taken by hardware acceleration to render apps [CHAR LIMIT=25] -->
     <string name="track_frame_time">Profile GPU rendering</string>
 
+    <!-- UI debug setting: enable gpu debug layers [CHAR LIMIT=25] -->
+    <string name="enable_gpu_debug_layers">Enable GPU debug layers</string>
+    <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
+    <string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string>
+
     <!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] -->
     <string name="window_animation_scale_title">Window animation scale</string>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 41b205b..ba1c9e3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -869,6 +869,15 @@
         dumpSetting(s, p,
                 Settings.Global.WAIT_FOR_DEBUGGER,
                 GlobalSettingsProto.WAIT_FOR_DEBUGGER);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
+                GlobalSettingsProto.ENABLE_GPU_DEBUG_LAYERS);
+        dumpSetting(s, p,
+                Settings.Global.GPU_DEBUG_APP,
+                GlobalSettingsProto.GPU_DEBUG_APP);
+        dumpSetting(s, p,
+                Settings.Global.GPU_DEBUG_LAYERS,
+                GlobalSettingsProto.GPU_DEBUG_LAYERS);
         // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
         dumpSetting(s, p,
                 Settings.Global.LOW_POWER_MODE,
diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk
index e177d1d..5f75f7d 100644
--- a/packages/SystemUI/shared/Android.mk
+++ b/packages/SystemUI/shared/Android.mk
@@ -30,7 +30,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_PACKAGE_NAME := SharedDummyLib
+LOCAL_PACKAGE_NAME := SystemUISharedLib
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := SystemUISharedLib
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index d82b010..cc4bc58 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -16,8 +16,8 @@
 
 package com.android.systemui.shared.recents;
 
-import android.graphics.Bitmap;
 import android.graphics.Rect;
+import com.android.systemui.shared.system.GraphicBufferCompat;
 
 /**
  * Temporary callbacks into SystemUI.
@@ -25,9 +25,8 @@
 interface ISystemUiProxy {
 
     /**
-     * Proxies SurfaceControl.screenshot().
+     * Proxies SurfaceControl.screenshotToBuffer().
      */
-    Bitmap screenshot(in Rect sourceCrop, int width, int height,
-                      int minLayer, int maxLayer, boolean useIdentityTransform,
-                      int rotation);
+    GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
+            int maxLayer, boolean useIdentityTransform, int rotation);
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index f92509d..4834bb1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -45,6 +45,11 @@
  */
 public class RecentsTaskLoadPlan {
 
+    /** The set of conditions to preload tasks. */
+    public static class PreloadOptions {
+        public boolean loadTitles = true;
+    }
+
     /** The set of conditions to load tasks. */
     public static class Options {
         public int runningTaskId = -1;
@@ -80,7 +85,8 @@
      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
      * this call (callers should synchronize on the loader before making this call).
      */
-    public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) {
+    public void preloadPlan(PreloadOptions opts, RecentsTaskLoader loader, int runningTaskId,
+            int currentUserId) {
         Resources res = mContext.getResources();
         ArrayList<Task> allTasks = new ArrayList<>();
         if (mRawTasks == null) {
@@ -110,9 +116,12 @@
             }
 
             // Load the title, icon, and color
-            String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
-            String titleDescription = loader.getAndUpdateContentDescription(taskKey,
-                    t.taskDescription);
+            String title = opts.loadTitles
+                    ? loader.getAndUpdateActivityTitle(taskKey, t.taskDescription)
+                    : "";
+            String titleDescription = opts.loadTitles
+                    ? loader.getAndUpdateContentDescription(taskKey, t.taskDescription)
+                    : "";
             Drawable icon = isStackTask
                     ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                     : null;
@@ -153,7 +162,7 @@
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
-        ArrayList<Task> tasks = mStack.getStackTasks();
+        ArrayList<Task> tasks = mStack.getTasks();
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
             Task task = tasks.get(i);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index 9a991cf..0f68026 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -155,7 +156,7 @@
             int currentUserId) {
         try {
             Trace.beginSection("preloadPlan");
-            plan.preloadPlan(this, runningTaskId, currentUserId);
+            plan.preloadPlan(new PreloadOptions(), this, runningTaskId, currentUserId);
         } finally {
             Trace.endSection();
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
index 693379d..a369397 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
@@ -19,7 +19,6 @@
 import android.content.ComponentName;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.SparseArray;
 
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.utilities.AnimationProps;
@@ -92,7 +91,7 @@
             boolean dismissRecentsIfAllRemoved) {
         if (mStackTaskList.contains(t)) {
             mStackTaskList.remove(t);
-            Task newFrontMostTask = getStackFrontMostTask();
+            Task newFrontMostTask = getFrontMostTask();
             if (mCb != null) {
                 // Notify that a task has been removed
                 mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
@@ -183,7 +182,7 @@
 
         // Only callback for the removed tasks after the stack has updated
         int removedTaskCount = removedTasks.size();
-        Task newFrontMostTask = getStackFrontMostTask();
+        Task newFrontMostTask = getFrontMostTask();
         for (int i = 0; i < removedTaskCount; i++) {
             mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
                     AnimationProps.IMMEDIATE, false /* fromDockGesture */,
@@ -205,7 +204,7 @@
     /**
      * Gets the front-most task in the stack.
      */
-    public Task getStackFrontMostTask() {
+    public Task getFrontMostTask() {
         ArrayList<Task> stackTasks = mStackTaskList.getTasks();
         if (stackTasks.isEmpty()) {
             return null;
@@ -228,7 +227,7 @@
     /**
      * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
      */
-    public ArrayList<Task> getStackTasks() {
+    public ArrayList<Task> getTasks() {
         return mStackTaskList.getTasks();
     }
 
@@ -242,16 +241,9 @@
     }
 
     /**
-     * Returns the number of stacktasks.
-     */
-    public int getTaskCount() {
-        return mStackTaskList.size();
-    }
-
-    /**
      * Returns the number of stack tasks.
      */
-    public int getStackTaskCount() {
+    public int getTaskCount() {
         return mStackTaskList.size();
     }
 
@@ -298,7 +290,7 @@
         if (nextLaunchTarget != null) {
             return nextLaunchTarget;
         }
-        return getStackTasks().get(getTaskCount() - 1);
+        return getTasks().get(getTaskCount() - 1);
     }
 
     private Task getNextLaunchTargetRaw() {
@@ -306,15 +298,15 @@
         if (taskCount == 0) {
             return null;
         }
-        int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+        int launchTaskIndex = indexOfTask(getLaunchTarget());
         if (launchTaskIndex != -1 && launchTaskIndex > 0) {
-            return getStackTasks().get(launchTaskIndex - 1);
+            return getTasks().get(launchTaskIndex - 1);
         }
         return null;
     }
 
     /** Returns the index of this task in this current task stack */
-    public int indexOfStackTask(Task t) {
+    public int indexOfTask(Task t) {
         return mStackTaskList.indexOf(t);
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
new file mode 100644
index 0000000..0241c59
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.recents.utilities;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+/**
+ * Helper class for internal trace functions.
+ */
+public class AppTrace {
+
+    /**
+     * Begins a new async trace section with the given {@param key} and {@param cookie}.
+     */
+    public static void start(String key, int cookie) {
+        android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, cookie);
+    }
+
+    /**
+     * Begins a new async trace section with the given {@param key}.
+     */
+    public static void start(String key) {
+        android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, 0);
+    }
+
+    /**
+     * Ends an existing async trace section with the given {@param key}.
+     */
+    public static void end(String key) {
+        android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, 0);
+    }
+
+    /**
+     * Ends an existing async trace section with the given {@param key} and {@param cookie}.
+     */
+    public static void end(String key, int cookie) {
+        android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, cookie);
+    }
+
+    /**
+     * Begins a new trace section with the given {@param key}. Can be nested.
+     */
+    public static void beginSection(String key) {
+        android.os.Trace.beginSection(key);
+    }
+
+    /**
+     * Ends an existing trace section started in the last {@link #beginSection(String)}.
+     */
+    public static void endSection() {
+        android.os.Trace.endSection();
+    }
+
+    /**
+     * Traces a counter value.
+     */
+    public static void count(String name, int count) {
+        android.os.Trace.traceCounter(TRACE_TAG_APP, name, count);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
index b598ec6..45728c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.views;
+package com.android.systemui.shared.recents.view;
 
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -24,22 +24,19 @@
 
 import com.android.systemui.shared.recents.utilities.Utilities;
 
-/* An outline provider that has a clip and outline that can be animated. */
+/**
+ * An outline provider that has a clip and outline that can be animated.
+ */
 public class AnimateableViewBounds extends ViewOutlineProvider {
 
     private static final float MIN_ALPHA = 0.1f;
     private static final float MAX_ALPHA = 0.8f;
 
     protected View mSourceView;
-    @ViewDebug.ExportedProperty(category="recents")
     protected Rect mClipRect = new Rect();
-    @ViewDebug.ExportedProperty(category="recents")
     protected Rect mClipBounds = new Rect();
-    @ViewDebug.ExportedProperty(category="recents")
     protected Rect mLastClipBounds = new Rect();
-    @ViewDebug.ExportedProperty(category="recents")
     protected int mCornerRadius;
-    @ViewDebug.ExportedProperty(category="recents")
     protected float mAlpha = 1f;
 
     public AnimateableViewBounds(View source, int cornerRadius) {
@@ -73,7 +70,7 @@
     /**
      * Sets the view outline alpha.
      */
-    void setAlpha(float alpha) {
+    public void setAlpha(float alpha) {
         if (Float.compare(alpha, mAlpha) != 0) {
             mAlpha = alpha;
             // TODO, If both clip and alpha change in the same frame, only invalidate once
@@ -88,28 +85,43 @@
         return mAlpha;
     }
 
-    /** Sets the top clip. */
+    /**
+     * Sets the top clip.
+     */
     public void setClipTop(int top) {
         mClipRect.top = top;
         updateClipBounds();
     }
 
-    /** Returns the top clip. */
+    /**
+     * @return the top clip.
+     */
     public int getClipTop() {
         return mClipRect.top;
     }
 
-    /** Sets the bottom clip. */
+    /**
+     * Sets the bottom clip.
+     */
     public void setClipBottom(int bottom) {
         mClipRect.bottom = bottom;
         updateClipBounds();
     }
 
-    /** Returns the bottom clip. */
+    /**
+     * @return the bottom clip.
+     */
     public int getClipBottom() {
         return mClipRect.bottom;
     }
 
+    /**
+     * @return the clip bounds.
+     */
+    public Rect getClipBounds() {
+        return mClipBounds;
+    }
+
     protected void updateClipBounds() {
         mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top),
                 mSourceView.getWidth() - Math.max(0, mClipRect.right),
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java
new file mode 100644
index 0000000..ebdc884
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.recents.view;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.view.AppTransitionAnimationSpec;
+
+/**
+ * Wraps the internal app transition animation spec.
+ */
+public class AppTransitionAnimationSpecCompat {
+
+    private int mTaskId;
+    private Bitmap mBuffer;
+    private Rect mRect;
+
+    public AppTransitionAnimationSpecCompat(int taskId, Bitmap buffer, Rect rect) {
+        mTaskId = taskId;
+        mBuffer = buffer;
+        mRect = rect;
+    }
+
+    public AppTransitionAnimationSpec toAppTransitionAnimationSpec() {
+        return new AppTransitionAnimationSpec(mTaskId,
+                mBuffer != null ? mBuffer.createGraphicBufferHandle() : null, mRect);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
index 7a24071..85d362a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
@@ -32,10 +32,10 @@
 public abstract class AppTransitionAnimationSpecsFuture {
 
     private final Handler mHandler;
-    private FutureTask<List<AppTransitionAnimationSpec>> mComposeTask = new FutureTask<>(
-            new Callable<List<AppTransitionAnimationSpec>>() {
+    private FutureTask<List<AppTransitionAnimationSpecCompat>> mComposeTask = new FutureTask<>(
+            new Callable<List<AppTransitionAnimationSpecCompat>>() {
                 @Override
-                public List<AppTransitionAnimationSpec> call() throws Exception {
+                public List<AppTransitionAnimationSpecCompat> call() throws Exception {
                     return composeSpecs();
                 }
             });
@@ -48,13 +48,15 @@
                 if (!mComposeTask.isDone()) {
                     mHandler.post(mComposeTask);
                 }
-                List<AppTransitionAnimationSpec> specs = mComposeTask.get();
+                List<AppTransitionAnimationSpecCompat> specs = mComposeTask.get();
                 if (specs == null) {
                     return null;
                 }
 
                 AppTransitionAnimationSpec[] arr = new AppTransitionAnimationSpec[specs.size()];
-                specs.toArray(arr);
+                for (int i = 0; i < specs.size(); i++) {
+                    arr[i] = specs.get(i).toAppTransitionAnimationSpec();
+                }
                 return arr;
             } catch (Exception e) {
                 return null;
@@ -83,5 +85,5 @@
         mComposeTask.run();
     }
 
-    public abstract List<AppTransitionAnimationSpec> composeSpecs();
+    public abstract List<AppTransitionAnimationSpecCompat> composeSpecs();
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
index f8f86f0..ab89043 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
@@ -42,7 +42,7 @@
      */
     public static ActivityOptions createAspectScaleAnimation(Context context, Handler handler,
             boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture,
-            final OnAnimationStartedListener animationStartCallback) {
+            final Runnable animationStartCallback) {
         final OnAnimationStartedListener animStartedListener = new OnAnimationStartedListener() {
             private boolean mHandled;
 
@@ -56,7 +56,7 @@
                 mHandled = true;
 
                 if (animationStartCallback != null) {
-                    animationStartCallback.onAnimationStarted();
+                    animationStartCallback.run();
                 }
             }
         };
@@ -71,19 +71,14 @@
      * Wraps a animation-start callback in a binder that can be called from window manager.
      */
     public static IRemoteCallback wrapStartedListener(final Handler handler,
-            final OnAnimationStartedListener listener) {
-        if (listener == null) {
+            final Runnable animationStartCallback) {
+        if (animationStartCallback == null) {
             return null;
         }
         return new IRemoteCallback.Stub() {
             @Override
             public void sendResult(Bundle data) throws RemoteException {
-                handler.post(new Runnable() {
-                                 @Override
-                                 public void run() {
-                                     listener.onAnimationStarted();
-                                 }
-                             });
+                handler.post(animationStartCallback);
             }
         };
     }
@@ -92,9 +87,9 @@
      * @return a {@link GraphicBuffer} with the {@param view} drawn into it. Result can be null if
      *         we were unable to allocate a hardware bitmap.
      */
-    public static GraphicBuffer drawViewIntoGraphicBuffer(int width, int height, final View view,
+    public static Bitmap drawViewIntoHardwareBitmap(int width, int height, final View view,
             final float scale, final int eraseColor) {
-        final Bitmap hwBitmap = createHardwareBitmap(width, height, new Consumer<Canvas>() {
+        return createHardwareBitmap(width, height, new Consumer<Canvas>() {
             @Override
             public void accept(Canvas c) {
                 c.scale(scale, scale);
@@ -106,7 +101,6 @@
                 }
             }
         });
-        return hwBitmap != null ? hwBitmap.createGraphicBufferHandle() : null;
     }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index db1583a..f6fab86 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -29,6 +29,7 @@
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IAssistDataReceiver;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -39,7 +40,9 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
@@ -62,12 +65,14 @@
     private final PackageManager mPackageManager;
     private final IconDrawableFactory mDrawableFactory;
     private final BackgroundExecutor mBackgroundExecutor;
+    private final TaskStackChangeListeners mTaskStackChangeListeners;
 
     private ActivityManagerWrapper() {
         final Context context = AppGlobals.getInitialApplication();
         mPackageManager = context.getPackageManager();
         mDrawableFactory = IconDrawableFactory.newInstance(context);
         mBackgroundExecutor = BackgroundExecutor.get();
+        mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
     }
 
     public static ActivityManagerWrapper getInstance() {
@@ -232,13 +237,54 @@
     }
 
     /**
+     * Starts the recents activity. The caller should manage the thread on which this is called.
+     */
+    public void startRecentsActivity(AssistDataReceiverCompat assistDataReceiver, Bundle options,
+            ActivityOptions opts, int userId, Consumer<Boolean> resultCallback,
+            Handler resultCallbackHandler) {
+        Bundle activityOptions = opts != null ? opts.toBundle() : null;
+        try {
+            IAssistDataReceiver receiver = null;
+            if (assistDataReceiver != null) {
+                receiver = new IAssistDataReceiver.Stub() {
+                    public void onHandleAssistData(Bundle resultData) {
+                        assistDataReceiver.onHandleAssistData(resultData);
+                    }
+                    public void onHandleAssistScreenshot(Bitmap screenshot) {
+                        assistDataReceiver.onHandleAssistScreenshot(screenshot);
+                    }
+                };
+            }
+            ActivityManager.getService().startRecentsActivity(receiver, options, activityOptions,
+                    userId);
+            if (resultCallback != null) {
+                resultCallbackHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        resultCallback.accept(true);
+                    }
+                });
+            }
+        } catch (Exception e) {
+            if (resultCallback != null) {
+                resultCallbackHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        resultCallback.accept(false);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
      * Starts a task from Recents.
      *
-     * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
+     * @see {@link #startActivityFromRecentsAsync(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
      */
-    public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+    public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
             Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
-        startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED,
+        startActivityFromRecentsAsync(taskKey, options, WINDOWING_MODE_UNDEFINED,
                 ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
     }
 
@@ -248,7 +294,7 @@
      * @param resultCallback The result success callback
      * @param resultCallbackHandler The handler to receive the result callback
      */
-    public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+    public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
             int windowingMode, int activityType, Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
         if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -270,30 +316,66 @@
 
         // Execute this from another thread such that we can do other things (like caching the
         // bitmap for the thumbnail) while AM is busy starting our activity.
-        mBackgroundExecutor.submit(() -> {
-            try {
-                ActivityManager.getService().startActivityFromRecents(taskKey.id,
-                        finalOptions == null ? null : finalOptions.toBundle());
-                if (resultCallback != null) {
-                    resultCallbackHandler.post(() -> resultCallback.accept(true));
-                }
-            } catch (Exception e) {
-                if (resultCallback != null) {
-                    resultCallbackHandler.post(() -> resultCallback.accept(false));
+        mBackgroundExecutor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ActivityManager.getService().startActivityFromRecents(taskKey.id,
+                            finalOptions == null ? null : finalOptions.toBundle());
+                    if (resultCallback != null) {
+                        resultCallbackHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                resultCallback.accept(true);
+                            }
+                        });
+                    }
+                } catch (Exception e) {
+                    if (resultCallback != null) {
+                        resultCallbackHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                resultCallback.accept(false);
+                            }
+                        });
+                    }
                 }
             }
         });
     }
 
     /**
+     * Registers a task stack listener with the system.
+     * This should be called on the main thread.
+     */
+    public void registerTaskStackListener(TaskStackChangeListener listener) {
+        synchronized (mTaskStackChangeListeners) {
+            mTaskStackChangeListeners.addListener(ActivityManager.getService(), listener);
+        }
+    }
+
+    /**
+     * Unregisters a task stack listener with the system.
+     * This should be called on the main thread.
+     */
+    public void unregisterTaskStackListener(TaskStackChangeListener listener) {
+        synchronized (mTaskStackChangeListeners) {
+            mTaskStackChangeListeners.removeListener(listener);
+        }
+    }
+
+    /**
      * Requests that the system close any open system windows (including other SystemUI).
      */
     public void closeSystemWindows(String reason) {
-        mBackgroundExecutor.submit(() -> {
-            try {
-                ActivityManager.getService().closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to close system windows", e);
+        mBackgroundExecutor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ActivityManager.getService().closeSystemDialogs(reason);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to close system windows", e);
+                }
             }
         });
     }
@@ -302,11 +384,14 @@
      * Removes a task by id.
      */
     public void removeTask(int taskId) {
-        mBackgroundExecutor.submit(() -> {
-            try {
-                ActivityManager.getService().removeTask(taskId);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to remove task=" + taskId, e);
+        mBackgroundExecutor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ActivityManager.getService().removeTask(taskId);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to remove task=" + taskId, e);
+                }
             }
         });
     }
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
similarity index 66%
copy from core/java/com/android/internal/app/IAssistDataReceiver.aidl
copy to packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
index 9c9ffef..cd943f6 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
@@ -11,16 +11,18 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
 
-package com.android.internal.app;
+package com.android.systemui.shared.system;
 
 import android.graphics.Bitmap;
 import android.os.Bundle;
 
-/** @hide */
-oneway interface IAssistDataReceiver {
-    void onHandleAssistData(in Bundle resultData);
-    void onHandleAssistScreenshot(in Bitmap screenshot);
+/**
+ * Abstract class for assist data receivers.
+ */
+public abstract class AssistDataReceiverCompat {
+    public abstract void onHandleAssistData(Bundle resultData);
+    public abstract void onHandleAssistScreenshot(Bitmap screenshot);
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
index 26e1813..0bd89a7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shared.system;
 
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -37,9 +38,24 @@
     }
 
     /**
+     * Runs the given {@param callable} on one of the background executor threads.
+     */
+    public <T> Future<T> submit(Callable<T> callable) {
+        return mExecutorService.submit(callable);
+    }
+
+    /**
      * Runs the given {@param runnable} on one of the background executor threads.
      */
     public Future<?> submit(Runnable runnable) {
         return mExecutorService.submit(runnable);
     }
+
+    /**
+     * Runs the given {@param runnable} on one of the background executor threads. Return
+     * {@param result} when the future is resolved.
+     */
+    public <T> Future<T> submit(Runnable runnable, T result) {
+        return mExecutorService.submit(runnable, result);
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java
new file mode 100644
index 0000000..4d422bb
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.system;
+
+import static android.view.Choreographer.CALLBACK_INPUT;
+
+import android.view.Choreographer;
+
+/**
+ * Wraps the internal choreographer.
+ */
+public class ChoreographerCompat {
+
+    /**
+     * Posts an input callback to the choreographer.
+     */
+    public static void postInputFrame(Choreographer choreographer, Runnable runnable) {
+        choreographer.postCallback(CALLBACK_INPUT, runnable, null);
+    }
+}
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
similarity index 70%
copy from core/java/com/android/internal/app/IAssistDataReceiver.aidl
copy to packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
index 9c9ffef..f9450ad 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.internal.app;
+package com.android.systemui.shared.system;
 
-import android.graphics.Bitmap;
-import android.os.Bundle;
-
-/** @hide */
-oneway interface IAssistDataReceiver {
-    void onHandleAssistData(in Bundle resultData);
-    void onHandleAssistScreenshot(in Bitmap screenshot);
-}
+parcelable GraphicBufferCompat;
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
new file mode 100644
index 0000000..66b8fed
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.system;
+
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Wraps the internal graphic buffer.
+ */
+public class GraphicBufferCompat implements Parcelable {
+
+    private GraphicBuffer mBuffer;
+
+    public GraphicBufferCompat(GraphicBuffer buffer) {
+        mBuffer = buffer;
+    }
+
+    public GraphicBufferCompat(Parcel in) {
+        mBuffer = GraphicBuffer.CREATOR.createFromParcel(in);
+    }
+
+    public Bitmap toBitmap() {
+        return mBuffer != null
+                ? Bitmap.createHardwareBitmap(mBuffer)
+                : null;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        mBuffer.writeToParcel(dest, flags);
+    }
+
+    public static final Parcelable.Creator<GraphicBufferCompat> CREATOR
+            = new Parcelable.Creator<GraphicBufferCompat>() {
+        public GraphicBufferCompat createFromParcel(Parcel in) {
+            return new GraphicBufferCompat(in);
+        }
+
+        public GraphicBufferCompat[] newArray(int size) {
+            return new GraphicBufferCompat[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 36310f1..17cb0d8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -20,6 +20,8 @@
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
 /**
  * An interface to track task stack changes. Classes should implement this instead of
  * {@link android.app.ITaskStackListener} to reduce IPC calls from system services.
@@ -31,7 +33,7 @@
 
     // Main thread callbacks
     public void onTaskStackChanged() { }
-    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
+    public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
     public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
     public void onActivityUnpinned() { }
     public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 95fc96f..81c37a9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -26,6 +26,8 @@
 import android.os.Trace;
 import android.util.Log;
 
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -43,6 +45,7 @@
     private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
 
     private final Handler mHandler;
+    private boolean mRegistered;
 
     public TaskStackChangeListeners(Looper looper) {
         mHandler = new H(looper);
@@ -50,16 +53,21 @@
 
     public void addListener(IActivityManager am, TaskStackChangeListener listener) {
         mTaskStackListeners.add(listener);
-        if (mTaskStackListeners.size() == 1) {
+        if (!mRegistered) {
             // Register mTaskStackListener to IActivityManager only once if needed.
             try {
                 am.registerTaskStackListener(this);
+                mRegistered = true;
             } catch (Exception e) {
                 Log.w(TAG, "Failed to call registerTaskStackListener", e);
             }
         }
     }
 
+    public void removeListener(TaskStackChangeListener listener) {
+        mTaskStackListeners.remove(listener);
+    }
+
     @Override
     public void onTaskStackChanged() throws RemoteException {
         // Call the task changed callback for the non-ui thread listeners first
@@ -170,7 +178,7 @@
                         Trace.beginSection("onTaskSnapshotChanged");
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                             mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
-                                    (TaskSnapshot) msg.obj);
+                                    new ThumbnailData((TaskSnapshot) msg.obj));
                         }
                         Trace.endSection();
                         break;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
new file mode 100644
index 0000000..1477558
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.graphics.Rect;
+import android.view.WindowManagerGlobal;
+
+public class WindowManagerWrapper {
+
+    private static final String TAG = "WindowManagerWrapper";
+
+    private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
+
+    public static WindowManagerWrapper getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * @return the stable insets for the primary display.
+     */
+    public void getStableInsets(Rect outStableInsets) {
+        try {
+            WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
+                    outStableInsets);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 623fe53..41b007a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -78,6 +78,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import com.google.android.collect.Lists;
 
@@ -1187,7 +1188,7 @@
             mFpm.addLockoutResetCallback(mLockoutResetCallback);
         }
 
-        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         mUserManager = context.getSystemService(UserManager.class);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 2e4a5a4..22922e7 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -22,11 +22,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -36,12 +33,14 @@
 import android.util.Log;
 import android.view.SurfaceControl;
 
+import com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.shared.system.GraphicBufferCompat;
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -67,12 +66,12 @@
     private int mConnectionBackoffAttempts;
 
     private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
-        public Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
-                boolean useIdentityTransform, int rotation) {
+        public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
+                int maxLayer, boolean useIdentityTransform, int rotation) {
             long token = Binder.clearCallingIdentity();
             try {
-                return SurfaceControl.screenshot(sourceCrop, width, height, minLayer, maxLayer,
-                        useIdentityTransform, rotation);
+                return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
+                        height, minLayer, maxLayer, useIdentityTransform, rotation));
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 4119ec0..b9e9e0a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -31,6 +31,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 public class WorkLockActivityController {
     private static final String TAG = WorkLockActivityController.class.getSimpleName();
@@ -39,15 +40,15 @@
     private final IActivityManager mIam;
 
     public WorkLockActivityController(Context context) {
-        this(context, SystemServicesProxy.getInstance(context), ActivityManager.getService());
+        this(context, ActivityManagerWrapper.getInstance(), ActivityManager.getService());
     }
 
     @VisibleForTesting
-    WorkLockActivityController(Context context, SystemServicesProxy ssp, IActivityManager am) {
+    WorkLockActivityController(Context context, ActivityManagerWrapper am, IActivityManager iAm) {
         mContext = context;
-        mIam = am;
+        mIam = iAm;
 
-        ssp.registerTaskStackListener(mLockListener);
+        am.registerTaskStackListener(mLockListener);
     }
 
     private void startWorkChallengeInTask(int taskId, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 7ef0f15..2963506 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -174,7 +174,7 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
-        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
         mInputConsumerController = new InputConsumerController(mWindowManager);
         mMediaController = new PipMediaController(context, mActivityManager);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 5a91def..eef43d2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -47,6 +47,7 @@
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -234,7 +235,7 @@
 
         mActivityManager = ActivityManager.getService();
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
-        SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c666d57..9aecc68 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents;
 
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
-import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
 
 import android.app.Activity;
 import android.app.ActivityOptions;
@@ -96,7 +95,6 @@
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -471,7 +469,7 @@
         if (launchState.launchedFromApp) {
             Task launchTarget = stack.getLaunchTarget();
             int launchTaskIndexInStack = launchTarget != null
-                    ? stack.indexOfStackTask(launchTarget)
+                    ? stack.indexOfTask(launchTarget)
                     : 0;
             MetricsLogger.count(this, "overview_source_app", 1);
             // If from an app, track the stack index of the app in the stack (for affiliated tasks)
@@ -517,7 +515,7 @@
 
         // Notify of the config change
         Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this);
-        int numStackTasks = mRecentsView.getStack().getStackTaskCount();
+        int numStackTasks = mRecentsView.getStack().getTaskCount();
         EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
                 mLastConfig.orientation != newDeviceConfiguration.orientation,
                 mLastConfig.densityDpi != newDeviceConfiguration.densityDpi, numStackTasks > 0));
@@ -826,7 +824,7 @@
         loader.loadTasks(loadPlan, loadOpts);
 
         TaskStack stack = loadPlan.getTaskStack();
-        int numStackTasks = stack.getStackTaskCount();
+        int numStackTasks = stack.getTaskCount();
         boolean showDeferredAnimation = numStackTasks > 0;
 
         if (sendConfigChangedEvent) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index d2326ce..14fda95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -50,24 +50,4 @@
         launchedViaDragGesture = false;
         launchedViaDockGesture = false;
     }
-
-    /**
-     * Returns the task to focus given the current launch state.
-     */
-    public int getInitialFocusTaskIndex(int numTasks, boolean useGridLayout) {
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        if (launchedFromApp) {
-            if (useGridLayout) {
-                // If coming from another app to the grid layout, focus the front most task
-                return numTasks - 1;
-            }
-
-            // If coming from another app, focus the next task
-            return Math.max(0, numTasks - 2);
-        } else {
-            // If coming from home, focus the front most task
-            return numTasks - 1;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index d2dfbbf..3b1b2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -25,11 +25,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
-import android.app.ActivityOptions.OnAnimationStartedListener;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -40,7 +40,6 @@
 import android.util.Log;
 import android.util.MutableBoolean;
 import android.util.Pair;
-import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
@@ -85,6 +84,7 @@
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -159,7 +159,7 @@
                     mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState);
                     VisibilityReport visibilityReport =
                             mBackgroundLayoutAlgorithm.computeStackVisibilityReport(
-                                    stack.getStackTasks());
+                                    stack.getTasks());
 
                     launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
                     launchOpts.numVisibleTasks = visibilityReport.numVisibleTasks;
@@ -200,14 +200,13 @@
         }
 
         @Override
-        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+        public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
             // Check this is for the right user
             if (!checkCurrentUserId(mContext, false /* debug */)) {
                 return;
             }
 
-            EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId,
-                    new ThumbnailData(snapshot)));
+            EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, snapshot));
         }
     }
 
@@ -221,13 +220,12 @@
     // recents. In this case, we defer the toggle state until then and apply it immediately after.
     private static boolean mToggleFollowingTransitionStart = true;
 
-    private ActivityOptions.OnAnimationStartedListener mResetToggleFlagListener =
-            new OnAnimationStartedListener() {
-                @Override
-                public void onAnimationStarted() {
-                    setWaitingForTransitionStart(false);
-                }
-            };
+    private Runnable mResetToggleFlagListener = new Runnable() {
+        @Override
+        public void run() {
+            setWaitingForTransitionStart(false);
+        }
+    };
 
     protected Context mContext;
     protected Handler mHandler;
@@ -270,8 +268,7 @@
 
         // Register the task stack listener
         mTaskStackListener = new TaskStackListenerImpl();
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.registerTaskStackListener(mTaskStackListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
         // Initialize the static configuration resources
         mDummyStackView = new TaskStackView(mContext);
@@ -535,7 +532,7 @@
         boolean isRunningTaskInHomeStack =
                 runningTask.configuration.windowConfiguration.getActivityType()
                         == ACTIVITY_TYPE_HOME;
-        ArrayList<Task> tasks = focusedStack.getStackTasks();
+        ArrayList<Task> tasks = focusedStack.getTasks();
         Task toTask = null;
         ActivityOptions launchOpts = null;
         int taskCount = tasks.size();
@@ -565,7 +562,7 @@
         }
 
         // Launch the task
-        ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+        ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(toTask.key, launchOpts,
                 null /* resultCallback */, null /* resultCallbackHandler */);
     }
 
@@ -591,7 +588,7 @@
         if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) return;
 
         // Find the task in the recents list
-        ArrayList<Task> tasks = focusedStack.getStackTasks();
+        ArrayList<Task> tasks = focusedStack.getTasks();
         Task toTask = null;
         ActivityOptions launchOpts = null;
         int taskCount = tasks.size();
@@ -635,7 +632,7 @@
         MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
 
         // Launch the task
-        ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+        ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(toTask.key, launchOpts,
                 null /* resultListener */, null /* resultCallbackHandler */);
     }
 
@@ -879,12 +876,12 @@
         RectF toTaskRect = toTransform.rect;
         AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(mHandler) {
             @Override
-            public List<AppTransitionAnimationSpec> composeSpecs() {
+            public List<AppTransitionAnimationSpecCompat> composeSpecs() {
                 Rect rect = new Rect();
                 toTaskRect.round(rect);
-                GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
-                return Lists.newArrayList(new AppTransitionAnimationSpec(toTask.key.id, thumbnail,
-                        rect));
+                Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
+                return Lists.newArrayList(new AppTransitionAnimationSpecCompat(toTask.key.id,
+                        thumbnail, rect));
             }
         };
 
@@ -907,7 +904,7 @@
             runningTaskOut.copyFrom(launchTask);
         } else {
             // If no task is specified or we can not find the task just use the front most one
-            launchTask = stack.getStackFrontMostTask();
+            launchTask = stack.getFrontMostTask();
             runningTaskOut.copyFrom(launchTask);
         }
 
@@ -922,7 +919,7 @@
     /**
      * Draws the header of a task used for the window animation into a bitmap.
      */
-    private GraphicBuffer drawThumbnailTransitionBitmap(Task toTask,
+    private Bitmap drawThumbnailTransitionBitmap(Task toTask,
             TaskViewTransform toTransform) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         int width = (int) toTransform.rect.width();
@@ -932,7 +929,7 @@
                 boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
                 mHeaderBar.onTaskViewSizeChanged(width, height);
                 if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
-                    return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+                    return RecentsTransition.drawViewIntoHardwareBitmap(width, mTaskBarHeight,
                             null, 1f, 0xFFff0000);
                 } else {
                     // Workaround for b/27815919, reset the callback so that we do not trigger an
@@ -945,7 +942,7 @@
                             disabledInSafeMode);
                     mHeaderBar.onTaskDataLoaded();
                     mHeaderBar.setDimAlpha(toTransform.dimAlpha);
-                    return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+                    return RecentsTransition.drawViewIntoHardwareBitmap(width, mTaskBarHeight,
                             mHeaderBar, 1f, 0);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 5eb315e..d89bab7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -114,7 +114,6 @@
     UserManager mUm;
     Display mDisplay;
     String mRecentsPackage;
-    private TaskStackChangeListeners mTaskStackChangeListeners;
     private int mCurrentUserId;
 
     boolean mIsSafeMode;
@@ -156,7 +155,6 @@
         mRecentsPackage = context.getPackageName();
         mIsSafeMode = mPm.isSafeMode();
         mCurrentUserId = mAm.getCurrentUser();
-        mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -494,18 +492,6 @@
         }
     }
 
-    /**
-     * Registers a task stack listener with the system.
-     * This should be called on the main thread.
-     */
-    public void registerTaskStackListener(SysUiTaskStackChangeListener listener) {
-        if (mIam == null) return;
-
-        synchronized (mTaskStackChangeListeners) {
-            mTaskStackChangeListeners.addListener(mIam, listener);
-        }
-    }
-
     public void endProlongedAnimations() {
         if (mWm == null) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
index 99390ec..1c47430 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
@@ -23,14 +23,15 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.util.Log;
-import android.view.AppTransitionAnimationSpec;
 
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 
 import java.util.ArrayList;
@@ -54,9 +55,9 @@
     /**
      * Composes a single animation spec for the given {@link TaskView}
      */
-    private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
+    private static AppTransitionAnimationSpecCompat composeAnimationSpec(TaskStackView stackView,
             TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
-        GraphicBuffer b = null;
+        Bitmap b = null;
         if (addHeaderBitmap) {
             b = composeHeaderBitmap(taskView, transform);
             if (b == null) {
@@ -71,28 +72,28 @@
         // force the task thumbnail to full stackView height immediately causing the transition
         // jarring.
         if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
-                stackView.getStack().getStackFrontMostTask()) {
+                stackView.getStack().getFrontMostTask()) {
             taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
         }
-        return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
+        return new AppTransitionAnimationSpecCompat(taskView.getTask().key.id, b, taskRect);
     }
 
     /**
      * Composes the transition spec when docking a task, which includes a full task bitmap.
      */
-    public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
+    public List<AppTransitionAnimationSpecCompat> composeDockAnimationSpec(TaskView taskView,
             Rect bounds) {
         mTmpTransform.fillIn(taskView);
         Task task = taskView.getTask();
-        GraphicBuffer buffer = RecentsTransitionComposer.composeTaskBitmap(taskView, mTmpTransform);
-        return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, buffer,
+        Bitmap buffer = RecentsTransitionComposer.composeTaskBitmap(taskView, mTmpTransform);
+        return Collections.singletonList(new AppTransitionAnimationSpecCompat(task.key.id, buffer,
                 bounds));
     }
 
     /**
      * Composes the animation specs for all the tasks in the target stack.
      */
-    public List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
+    public List<AppTransitionAnimationSpecCompat> composeAnimationSpecs(final Task task,
             final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
         // Calculate the offscreen task rect (for tasks that are not backed by views)
         TaskView taskView = stackView.getChildViewForTask(task);
@@ -110,13 +111,13 @@
                 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                 || activityType == ACTIVITY_TYPE_ASSISTANT
                 || windowingMode == WINDOWING_MODE_UNDEFINED) {
-            List<AppTransitionAnimationSpec> specs = new ArrayList<>();
+            List<AppTransitionAnimationSpecCompat> specs = new ArrayList<>();
             if (taskView == null) {
                 specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
             } else {
                 mTmpTransform.fillIn(taskView);
                 stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
-                AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
+                AppTransitionAnimationSpecCompat spec = composeAnimationSpec(stackView, taskView,
                         mTmpTransform, true /* addHeaderBitmap */);
                 if (spec != null) {
                     specs.add(spec);
@@ -130,12 +131,12 @@
     /**
      * Composes a single animation spec for the given {@link Task}
      */
-    private static AppTransitionAnimationSpec composeOffscreenAnimationSpec(Task task,
+    private static AppTransitionAnimationSpecCompat composeOffscreenAnimationSpec(Task task,
             Rect taskRect) {
-        return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
+        return new AppTransitionAnimationSpecCompat(task.key.id, null, taskRect);
     }
 
-    public static GraphicBuffer composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
+    public static Bitmap composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
         float scale = transform.scale;
         int fromWidth = (int) (transform.rect.width() * scale);
         int fromHeight = (int) (transform.rect.height() * scale);
@@ -143,19 +144,19 @@
             Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
                     " at transform: " + transform);
 
-            return RecentsTransition.drawViewIntoGraphicBuffer(1, 1, null, 1f, 0x00ffffff);
+            return RecentsTransition.drawViewIntoHardwareBitmap(1, 1, null, 1f, 0x00ffffff);
         } else {
             if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
-                return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, null, 1f,
+                return RecentsTransition.drawViewIntoHardwareBitmap(fromWidth, fromHeight, null, 1f,
                         0xFFff0000);
             } else {
-                return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, taskView,
+                return RecentsTransition.drawViewIntoHardwareBitmap(fromWidth, fromHeight, taskView,
                         scale, 0);
             }
         }
     }
 
-    private static GraphicBuffer composeHeaderBitmap(TaskView taskView,
+    private static Bitmap composeHeaderBitmap(TaskView taskView,
             TaskViewTransform transform) {
         float scale = transform.scale;
         int headerWidth = (int) (transform.rect.width());
@@ -165,10 +166,10 @@
         }
 
         if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
-            return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight, null, 1f,
+            return RecentsTransition.drawViewIntoHardwareBitmap(headerWidth, headerHeight, null, 1f,
                     0xFFff0000);
         } else {
-            return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight,
+            return RecentsTransition.drawViewIntoHardwareBitmap(headerWidth, headerHeight,
                     taskView.mHeaderView, scale, 0);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index b82f15e..1440fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.recents.views;
 
-import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
 
 import android.animation.ValueAnimator;
@@ -90,6 +89,7 @@
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -296,7 +296,7 @@
      * @return True if it changed.
      */
     private boolean updateBusyness() {
-        final int taskCount = mTaskStackView.getStack().getStackTaskCount();
+        final int taskCount = mTaskStackView.getStack().getTaskCount();
         final float busyness = Math.min(taskCount, BUSY_RECENTS_TASK_COUNT)
                 / (float) BUSY_RECENTS_TASK_COUNT;
         if (mBusynessFactor == busyness) {
@@ -611,27 +611,23 @@
             // Dock the task and launch it
             SystemServicesProxy ssp = Recents.getSystemServices();
             if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
-                final OnAnimationStartedListener startedListener =
-                        new OnAnimationStartedListener() {
-                    @Override
-                    public void onAnimationStarted() {
-                        EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
-                        // Remove the task and don't bother relaying out, as all the tasks will be
-                        // relaid out when the stack changes on the multiwindow change event
-                        getStack().removeTask(event.task, null, true /* fromDockGesture */);
-                    }
+                final Runnable animStartedListener = () -> {
+                    EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
+                    // Remove the task and don't bother relaying out, as all the tasks will be
+                    // relaid out when the stack changes on the multiwindow change event
+                    getStack().removeTask(event.task, null, true /* fromDockGesture */);
                 };
 
                 final Rect taskRect = getTaskRect(event.taskView);
                 AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
                         getHandler()) {
                     @Override
-                    public List<AppTransitionAnimationSpec> composeSpecs() {
+                    public List<AppTransitionAnimationSpecCompat> composeSpecs() {
                         return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
                     }
                 };
                 ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
-                        RecentsTransition.wrapStartedListener(getHandler(), startedListener),
+                        RecentsTransition.wrapStartedListener(getHandler(), animStartedListener),
                         true /* scaleUp */);
 
                 MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
@@ -928,7 +924,7 @@
             final TaskStackView stackView, final TaskView taskView,
             final boolean screenPinningRequested, final int windowingMode, final int activityType) {
 
-        final ActivityOptions.OnAnimationStartedListener animStartedListener;
+        final Runnable animStartedListener;
         final AppTransitionAnimationSpecsFuture transitionFuture;
         if (taskView != null) {
 
@@ -937,16 +933,16 @@
             final Rect windowRect = Recents.getSystemServices().getWindowRect();
             transitionFuture = new AppTransitionAnimationSpecsFuture(stackView.getHandler()) {
                 @Override
-                public List<AppTransitionAnimationSpec> composeSpecs() {
+                public List<AppTransitionAnimationSpecCompat> composeSpecs() {
                     return mTransitionHelper.composeAnimationSpecs(task, stackView, windowingMode,
                             activityType, windowRect);
                 }
             };
-            animStartedListener = new OnAnimationStartedListener() {
+            animStartedListener = new Runnable() {
                 private boolean mHandled;
 
                 @Override
-                public void onAnimationStarted() {
+                public void run() {
                     if (mHandled) {
                         return;
                     }
@@ -975,11 +971,11 @@
         } else {
             // This is only the case if the task is not on screen (scrolled offscreen for example)
             transitionFuture = null;
-            animStartedListener = new OnAnimationStartedListener() {
+            animStartedListener = new Runnable() {
                 private boolean mHandled;
 
                 @Override
-                public void onAnimationStarted() {
+                public void run() {
                     if (mHandled) {
                         return;
                     }
@@ -1027,12 +1023,12 @@
     private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
             ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
             int windowingMode, int activityType) {
-        ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode,
-                activityType, succeeded -> {
+        ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
+                windowingMode, activityType, succeeded -> {
             if (succeeded) {
                 // Keep track of the index of the task launch
                 int taskIndexFromFront = 0;
-                int taskIndex = stack.indexOfStackTask(task);
+                int taskIndex = stack.indexOfTask(task);
                 if (taskIndex > -1) {
                     taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 0cfdbde..5c69ae3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -40,7 +40,6 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
 
 import java.util.ArrayList;
 
@@ -106,7 +105,7 @@
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
         handleTouchEvent(ev);
-        if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getStackTaskCount() == 0) {
+        if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getTaskCount() == 0) {
             EventBus.getDefault().send(new HideRecentsEvent(false, true));
         }
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 7827c59..170e39d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -154,7 +154,7 @@
 
     public final void onBusEvent(MultiWindowStateChangedEvent event) {
         mHasDockedTasks = event.inMultiWindow;
-        animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
+        animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
     }
 
     public final void onBusEvent(final DragEndEvent event) {
@@ -166,7 +166,7 @@
 
     public final void onBusEvent(final DragEndCancelledEvent event) {
         // Restore the scrims to the normal state
-        animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
+        animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 26db26f..67d0978 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -449,7 +449,7 @@
 
         // Get the current set of task transforms
         int taskViewCount = mStackView.getTaskViews().size();
-        ArrayList<Task> stackTasks = stack.getStackTasks();
+        ArrayList<Task> stackTasks = stack.getTasks();
         mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
 
         // Pick up the newly visible views after the scroll
@@ -541,7 +541,7 @@
         TaskStackViewScroller stackScroller = mStackView.getScroller();
 
         // Get the current set of task transforms
-        ArrayList<Task> stackTasks = newStack.getStackTasks();
+        ArrayList<Task> stackTasks = newStack.getTasks();
         mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
 
         // Update the stack
@@ -563,7 +563,7 @@
                 false /* ignoreTaskOverrides */, mTmpFinalTaskTransforms);
 
         // Hide the front most task view until the scroll is complete
-        Task frontMostTask = newStack.getStackFrontMostTask();
+        Task frontMostTask = newStack.getFrontMostTask();
         final TaskView frontMostTaskView = mStackView.getChildViewForTask(frontMostTask);
         final TaskViewTransform frontMostTransform = mTmpFinalTaskTransforms.get(
                 stackTasks.indexOf(frontMostTask));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index acb058c..600da04 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -438,7 +438,7 @@
         mTaskIndexMap.clear();
 
         // Return early if we have no tasks
-        ArrayList<Task> tasks = stack.getStackTasks();
+        ArrayList<Task> tasks = stack.getTasks();
         if (tasks.isEmpty()) {
             mFrontMostTaskP = 0;
             mMinScrollP = mMaxScrollP = mInitialScrollP = 0;
@@ -468,7 +468,7 @@
         // Calculate the min/max/initial scroll
         Task launchTask = stack.getLaunchTarget();
         int launchTaskIndex = launchTask != null
-                ? stack.indexOfStackTask(launchTask)
+                ? stack.indexOfTask(launchTask)
                 : mNumStackTasks - 1;
         if (getInitialFocusState() == STATE_FOCUSED) {
             int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
@@ -557,7 +557,7 @@
                 }
 
                 mUnfocusedRange.offset(0f);
-                List<Task> tasks = stack.getStackTasks();
+                List<Task> tasks = stack.getTasks();
                 int taskCount = tasks.size();
                 for (int i = taskCount - 1; i >= 0; i--) {
                     int indexFromFront = taskCount - i - 1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 428113a..1197501 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -535,7 +535,7 @@
      */
     void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
         // Get all the task transforms
-        ArrayList<Task> tasks = mStack.getStackTasks();
+        ArrayList<Task> tasks = mStack.getTasks();
         int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
                 mStackScroller.getStackScroll(), targetStackScroll, mIgnoreTasks,
                 ignoreTaskOverrides);
@@ -557,7 +557,7 @@
             // It is possible for the set of lingering TaskViews to differ from the stack if the
             // stack was updated before the relayout.  If the task view is no longer in the stack,
             // then just return it back to the view pool.
-            int taskIndex = mStack.indexOfStackTask(task);
+            int taskIndex = mStack.indexOfTask(task);
             TaskViewTransform transform = null;
             if (taskIndex != -1) {
                 transform = mCurrentTaskTransforms.get(taskIndex);
@@ -601,7 +601,7 @@
                 }
             } else {
                 // Reattach it in the right z order
-                final int taskIndex = mStack.indexOfStackTask(task);
+                final int taskIndex = mStack.indexOfTask(task);
                 final int insertIndex = findTaskViewInsertIndex(task, taskIndex);
                 if (insertIndex != getTaskViews().indexOf(tv)){
                     detachViewFromParent(tv);
@@ -663,7 +663,7 @@
                 continue;
             }
 
-            int taskIndex = mStack.indexOfStackTask(task);
+            int taskIndex = mStack.indexOfTask(task);
             TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
             if (animationOverrides != null && animationOverrides.containsKey(task)) {
                 animation = animationOverrides.get(task);
@@ -866,7 +866,7 @@
         int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
                 Utilities.clamp(focusTaskIndex, 0, mStack.getTaskCount() - 1) : -1;
         final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
-                mStack.getStackTasks().get(newFocusedTaskIndex) : null;
+                mStack.getTasks().get(newFocusedTaskIndex) : null;
 
         // Reset the last focused task state if changed
         if (mFocusedTask != null) {
@@ -953,10 +953,10 @@
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
                                        boolean cancelWindowAnimations, int timerIndicatorDuration) {
         Task focusedTask = getFocusedTask();
-        int newIndex = mStack.indexOfStackTask(focusedTask);
+        int newIndex = mStack.indexOfTask(focusedTask);
         if (focusedTask != null) {
             if (stackTasksOnly) {
-                List<Task> tasks =  mStack.getStackTasks();
+                List<Task> tasks =  mStack.getTasks();
                 // Try the next task if it is a stack task
                 int tmpNewIndex = newIndex + (forward ? -1 : 1);
                 if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
@@ -971,7 +971,7 @@
         } else {
             // We don't have a focused task
             float stackScroll = mStackScroller.getStackScroll();
-            ArrayList<Task> tasks = mStack.getStackTasks();
+            ArrayList<Task> tasks = mStack.getTasks();
             int taskCount = tasks.size();
             if (useGridLayout()) {
                 // For the grid layout, we directly set focus to the most recently used task
@@ -1060,8 +1060,8 @@
         if (taskViewCount > 0) {
             TaskView backMostTask = taskViews.get(0);
             TaskView frontMostTask = taskViews.get(taskViewCount - 1);
-            event.setFromIndex(mStack.indexOfStackTask(backMostTask.getTask()));
-            event.setToIndex(mStack.indexOfStackTask(frontMostTask.getTask()));
+            event.setFromIndex(mStack.indexOfTask(backMostTask.getTask()));
+            event.setToIndex(mStack.indexOfTask(frontMostTask.getTask()));
             event.setContentDescription(frontMostTask.getTask().title);
         }
         event.setItemCount(mStack.getTaskCount());
@@ -1080,7 +1080,7 @@
             // Find the accessibility focused task
             Task focusedTask = getAccessibilityFocusedTask();
             info.setScrollable(true);
-            int focusedTaskIndex = mStack.indexOfStackTask(focusedTask);
+            int focusedTaskIndex = mStack.indexOfTask(focusedTask);
             if (focusedTaskIndex > 0 || !mStackActionButtonVisible) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
@@ -1101,7 +1101,7 @@
             return true;
         }
         Task focusedTask = getAccessibilityFocusedTask();
-        int taskIndex = mStack.indexOfStackTask(focusedTask);
+        int taskIndex = mStack.indexOfTask(focusedTask);
         if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
             switch (action) {
                 case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
@@ -1157,7 +1157,7 @@
      * updateLayoutForStack() is called first.
      */
     public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
-        return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getStackTasks());
+        return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
     }
 
     /**
@@ -1328,10 +1328,9 @@
         // We set the initial focused task view iff the following conditions are satisfied:
         // 1. Recents is showing task views in stack layout.
         // 2. Recents is launched with ALT + TAB.
-        boolean setFocusOnFirstLayout = !useGridLayout() ||
-            Recents.getConfiguration().getLaunchState().launchedWithAltTab;
+        boolean setFocusOnFirstLayout = !useGridLayout() || launchState.launchedWithAltTab;
         if (setFocusOnFirstLayout) {
-            int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount(),
+            int focusedTaskIndex = getInitialFocusTaskIndex(launchState, mStack.getTaskCount(),
                 useGridLayout());
             if (focusedTaskIndex != -1) {
                 setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
@@ -1502,7 +1501,7 @@
     @Override
     public void onPickUpViewFromPool(TaskView tv, Task task, boolean isNewView) {
         // Find the index where this task should be placed in the stack
-        int taskIndex = mStack.indexOfStackTask(task);
+        int taskIndex = mStack.indexOfTask(task);
         int insertIndex = findTaskViewInsertIndex(task, taskIndex);
 
         // Add/attach the view to the hierarchy
@@ -1545,7 +1544,7 @@
         }
 
         // Restore the action button visibility if it is the front most task view
-        if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+        if (mScreenPinningEnabled && tv.getTask() == mStack.getFrontMostTask()) {
             tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
         }
     }
@@ -1669,7 +1668,7 @@
                 event.packageName, event.userId);
 
         // For other tasks, just remove them directly if they no longer exist
-        ArrayList<Task> tasks = mStack.getStackTasks();
+        ArrayList<Task> tasks = mStack.getTasks();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task t = tasks.get(i);
             if (removedComponents.contains(t.key.getComponent())) {
@@ -1692,7 +1691,7 @@
 
     public final void onBusEvent(LaunchMostRecentTaskRequestEvent event) {
         if (mStack.getTaskCount() > 0) {
-            Task mostRecentTask = mStack.getStackFrontMostTask();
+            Task mostRecentTask = mStack.getFrontMostTask();
             launchTask(mostRecentTask);
         }
     }
@@ -1786,7 +1785,7 @@
 
     public final void onBusEvent(final DismissAllTaskViewsEvent event) {
         // Keep track of the tasks which will have their data removed
-        ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
+        ArrayList<Task> tasks = new ArrayList<>(mStack.getTasks());
         mAnimationHelper.startDeleteAllTasksAnimation(
                 getTaskViews(), useGridLayout(), event.getAnimationTrigger());
         event.addPostAnimationCallback(new Runnable() {
@@ -1854,7 +1853,7 @@
     public final void onBusEvent(NavigateTaskViewEvent event) {
         if (useGridLayout()) {
             final int taskCount = mStack.getTaskCount();
-            final int currentIndex = mStack.indexOfStackTask(getFocusedTask());
+            final int currentIndex = mStack.indexOfTask(getFocusedTask());
             final int nextIndex = mLayoutAlgorithm.mTaskGridLayoutAlgorithm.navigateFocus(taskCount,
                     currentIndex, event.direction);
             setFocusedTask(nextIndex, false, true);
@@ -2000,7 +1999,7 @@
                 if (mFocusedTask != null) {
                     RecentsConfiguration config = Recents.getConfiguration();
                     RecentsActivityLaunchState launchState = config.getLaunchState();
-                    setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
+                    setFocusedTask(mStack.indexOfTask(mFocusedTask),
                             false /* scrollToTask */, launchState.launchedWithAltTab);
                     TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
                     if (mTouchExplorationEnabled && focusedTaskView != null) {
@@ -2131,7 +2130,7 @@
                 Task tvTask = taskViews.get(i).getTask();
                 if (tvTask == task) {
                     foundTaskView = true;
-                } else if (taskIndex < mStack.indexOfStackTask(tvTask)) {
+                } else if (taskIndex < mStack.indexOfTask(tvTask)) {
                     if (foundTaskView) {
                         return i - 1;
                     } else {
@@ -2201,6 +2200,25 @@
     }
 
     /**
+     * Returns the task to focus given the current launch state.
+     */
+    private int getInitialFocusTaskIndex(RecentsActivityLaunchState launchState, int numTasks,
+            boolean useGridLayout) {
+        if (launchState.launchedFromApp) {
+            if (useGridLayout) {
+                // If coming from another app to the grid layout, focus the front most task
+                return numTasks - 1;
+            }
+
+            // If coming from another app, focus the next task
+            return Math.max(0, numTasks - 2);
+        } else {
+            // If coming from home, focus the front most task
+            return numTasks - 1;
+        }
+    }
+
+    /**
      * Updates {@param transforms} to be the same size as {@param tasks}.
      */
     private void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index b9ca248..bfaa8cd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -446,7 +446,7 @@
         TaskView tv = (TaskView) v;
         Task task = tv.getTask();
         return !mSwipeHelperAnimations.containsKey(v) &&
-                (mSv.getStack().indexOfStackTask(task) != -1);
+                (mSv.getStack().indexOfTask(task) != -1);
     }
 
     /**
@@ -476,7 +476,7 @@
         mSv.addIgnoreTask(tv.getTask());
 
         // Determine if we are animating the other tasks while dismissing this task
-        mCurrentTasks = new ArrayList<Task>(mSv.getStack().getStackTasks());
+        mCurrentTasks = new ArrayList<Task>(mSv.getStack().getTasks());
         MutableBoolean isFrontMostTask = new MutableBoolean(false);
         Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
         TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm();
@@ -673,7 +673,7 @@
 
     /** Returns the view at the specified coordinates */
     private TaskView findViewAtPoint(int x, int y) {
-        List<Task> tasks = mSv.getStack().getStackTasks();
+        List<Task> tasks = mSv.getStack().getTasks();
         int taskCount = tasks.size();
         for (int i = taskCount - 1; i >= 0; i--) {
             TaskView tv = mSv.getChildViewForTask(tasks.get(i));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index b440847..f0278a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -55,6 +55,7 @@
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -683,7 +684,7 @@
         }
         SystemServicesProxy ssp = Recents.getSystemServices();
         boolean inBounds = false;
-        Rect clipBounds = new Rect(mViewBounds.mClipBounds);
+        Rect clipBounds = new Rect(mViewBounds.getClipBounds());
         if (!clipBounds.isEmpty()) {
             // If we are clipping the view to the bounds, manually do the hit test.
             clipBounds.scale(getScaleX());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
index a029478..3bdad31 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.views.grid;
 
 import android.view.View;
-import com.android.systemui.recents.views.AnimateableViewBounds;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
 
 /* An outline provider for grid-based task views. */
 class AnimateableGridViewBounds extends AnimateableViewBounds {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
index 8b4700c..0d51154 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import com.android.systemui.R;
-import com.android.systemui.recents.views.AnimateableViewBounds;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
 import com.android.systemui.recents.views.TaskView;
 
 public class GridTaskView extends TaskView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
index 95f1d58..fe6bafb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -125,7 +125,7 @@
             // We're returning from touch mode, set the focus to the previously focused task.
             final TaskStack stack = mSv.getStack();
             final int taskCount = stack.getTaskCount();
-            final int k = stack.indexOfStackTask(mSv.getFocusedTask());
+            final int k = stack.indexOfTask(mSv.getFocusedTask());
             final int taskIndexToFocus = k == -1 ? (taskCount - 1) : (k % taskCount);
             mSv.setFocusedTask(taskIndexToFocus, false, true);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index b2bbe30..826fa6c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -33,6 +33,7 @@
 import com.android.systemui.recents.events.component.ShowUserToastEvent;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.events.StartedDragingEvent;
 import com.android.systemui.stackdivider.events.StoppedDragingEvent;
 
@@ -75,7 +76,7 @@
     public ForcedResizableInfoActivityController(Context context) {
         mContext = context;
         EventBus.getDefault().register(this);
-        SystemServicesProxy.getInstance(context).registerTaskStackListener(
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(
                 new SysUiTaskStackChangeListener() {
                     @Override
                     public void onActivityForcedResizable(String packageName, int taskId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 41cae6b..5941af2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -85,7 +85,7 @@
     public void start() {
         super.start();
         mTaskStackListener = new TaskStackListenerImpl();
-        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         registerPackageChangeReceivers();
 
         mStackScroller.setScrollingEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 4180884..bed6d82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.Log;
@@ -76,6 +77,8 @@
     private final GestureDetector mTaskSwitcherDetector;
     private final int mScrollTouchSlop;
     private final int mMinFlingVelocity;
+    private final Matrix mTransformGlobalMatrix = new Matrix();
+    private final Matrix mTransformLocalMatrix = new Matrix();
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mDownOnRecents;
@@ -116,27 +119,30 @@
         final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
         if (overviewProxy != null) {
             mNavigationBarView.requestUnbufferedDispatch(event);
+            event.transform(mTransformGlobalMatrix);
             try {
                 overviewProxy.onMotionEvent(event);
                 return true;
             } catch (RemoteException e) {
                 Log.e(TAG, "Callback failed", e);
+            } finally {
+                event.transform(mTransformLocalMatrix);
             }
         }
         return false;
     }
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (!proxyMotionEvents(event)) {
-            // If we move more than a fixed amount, then start capturing for the
-            // task switcher detector, disabled when proxying motion events to launcher service
-            mTaskSwitcherDetector.onTouchEvent(event);
-        }
         int action = event.getAction();
+        boolean result = false;
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 mTouchDownX = (int) event.getX();
                 mTouchDownY = (int) event.getY();
+                mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
+                mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
+                mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
+                mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -147,7 +153,7 @@
                 boolean exceededTouchSlop = xDiff > mScrollTouchSlop && xDiff > yDiff
                         || yDiff > mScrollTouchSlop && yDiff > xDiff;
                 if (exceededTouchSlop) {
-                    return true;
+                    result = true;
                 }
                 break;
             }
@@ -155,7 +161,12 @@
             case MotionEvent.ACTION_UP:
                 break;
         }
-        return mDockWindowEnabled && interceptDockWindowEvent(event);
+        if (!proxyMotionEvents(event)) {
+            // If we move more than a fixed amount, then start capturing for the
+            // task switcher detector, disabled when proxying motion events to launcher service
+            mTaskSwitcherDetector.onTouchEvent(event);
+        }
+        return result || (mDockWindowEnabled && interceptDockWindowEvent(event));
     }
 
     private boolean interceptDockWindowEvent(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index ba4ff58..09fe579 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -67,6 +67,7 @@
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.BluetoothController;
@@ -249,7 +250,7 @@
         mLocationController.addCallback(this);
 
         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
-        SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
 
         // Clear out all old notifications on startup (only present in the case where sysui dies)
         NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 87d11b2..4606aee 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -235,7 +235,7 @@
                 intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
                 if (mPermissionGranted) {
                     service.grantDevicePermission(mDevice, mUid);
-                    if (mAlwaysUse.isChecked()) {
+                    if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
                         final int userId = UserHandle.getUserId(mUid);
                         service.setDevicePackage(mDevice, mPackageName, userId);
                     }
@@ -245,7 +245,7 @@
                 intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
                 if (mPermissionGranted) {
                     service.grantAccessoryPermission(mAccessory, mUid);
-                    if (mAlwaysUse.isChecked()) {
+                    if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
                         final int userId = UserHandle.getUserId(mUid);
                         service.setAccessoryPackage(mAccessory, mPackageName, userId);
                     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index d758314..cf32760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -41,7 +41,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,7 +61,7 @@
     private static final int TASK_ID = 444;
 
     private @Mock Context mContext;
-    private @Mock SystemServicesProxy mSystemServicesProxy;
+    private @Mock ActivityManagerWrapper mActivityManager;
     private @Mock IActivityManager mIActivityManager;
 
     private WorkLockActivityController mController;
@@ -77,10 +77,9 @@
         // Construct controller. Save the TaskStackListener for injecting events.
         final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor =
                 ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class);
-        mController =
-                new WorkLockActivityController(mContext, mSystemServicesProxy, mIActivityManager);
+        mController = new WorkLockActivityController(mContext, mActivityManager, mIActivityManager);
 
-        verify(mSystemServicesProxy).registerTaskStackListener(listenerCaptor.capture());
+        verify(mActivityManager).registerTaskStackListener(listenerCaptor.capture());
         mTaskStackListener = listenerCaptor.getValue();
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5823ab1..af4668a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -36,6 +36,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.IAssistDataReceiver;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.AutofillOverlay;
 import android.app.assist.AssistStructure.ViewNode;
@@ -76,7 +77,6 @@
 import android.view.autofill.IAutofillWindowPresenter;
 
 import com.android.internal.R;
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3e40dfd..bccae06 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5616,7 +5616,8 @@
     }
 
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
-        mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
+        int[] transports = nai.networkCapabilities.getTransportTypes();
+        mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
     }
 
     private static boolean toBool(int encodedBoolean) {
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
new file mode 100644
index 0000000..5dd3ee0
--- /dev/null
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.PackageOps;
+import android.app.IUidObserver;
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Class to track OP_RUN_ANY_IN_BACKGROUND, UID foreground state and "force all app standby".
+ *
+ * TODO Clean up cache when a user is deleted.
+ * TODO Add unit tests. b/68769804.
+ */
+public class ForceAppStandbyTracker {
+    private static final String TAG = "ForceAppStandbyTracker";
+
+    @GuardedBy("ForceAppStandbyTracker.class")
+    private static ForceAppStandbyTracker sInstance;
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+
+    AppOpsManager mAppOpsManager;
+    IAppOpsService mAppOpsService;
+    PowerManagerInternal mPowerManagerInternal;
+
+    private final Handler mCallbackHandler;
+
+    /**
+     * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
+     */
+    @GuardedBy("mLock")
+    final ArraySet<Pair<Integer, String>> mForcedAppStandbyUidPackages = new ArraySet<>();
+
+    @GuardedBy("mLock")
+    final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+    @GuardedBy("mLock")
+    final ArraySet<Listener> mListeners = new ArraySet<>();
+
+    @GuardedBy("mLock")
+    boolean mStarted;
+
+    @GuardedBy("mLock")
+    boolean mForceAllAppsStandby;
+
+    public static abstract class Listener {
+        public void onRestrictionChanged(int uid, @Nullable String packageName) {
+        }
+
+        public void onGlobalRestrictionChanged() {
+        }
+    }
+
+    private ForceAppStandbyTracker(Context context) {
+        mContext = context;
+        mCallbackHandler = FgThread.getHandler();
+    }
+
+    /**
+     * Get the singleton instance.
+     */
+    public static synchronized ForceAppStandbyTracker getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new ForceAppStandbyTracker(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Call it when the system is ready.
+     */
+    public void start() {
+        synchronized (mLock) {
+            if (mStarted) {
+                return;
+            }
+            mStarted = true;
+
+            mAppOpsManager = Preconditions.checkNotNull(
+                    mContext.getSystemService(AppOpsManager.class));
+            mAppOpsService = Preconditions.checkNotNull(
+                    IAppOpsService.Stub.asInterface(
+                            ServiceManager.getService(Context.APP_OPS_SERVICE)));
+            mPowerManagerInternal = Preconditions.checkNotNull(
+                    LocalServices.getService(PowerManagerInternal.class));
+
+            try {
+                ActivityManager.getService().registerUidObserver(new UidObserver(),
+                        ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
+                                | ActivityManager.UID_OBSERVER_ACTIVE,
+                        ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
+                        new AppOpsWatcher());
+            } catch (RemoteException e) {
+                // shouldn't happen.
+            }
+
+            mPowerManagerInternal.registerLowPowerModeObserver(
+                    ServiceType.FORCE_ALL_APPS_STANDBY,
+                    state -> updateForceAllAppsStandby(state.batterySaverEnabled));
+
+            updateForceAllAppsStandby(
+                    mPowerManagerInternal.getLowPowerState(ServiceType.FORCE_ALL_APPS_STANDBY)
+                            .batterySaverEnabled);
+
+            refreshForcedAppStandbyUidPackagesLocked();
+        }
+    }
+
+    /**
+     * Update {@link #mForcedAppStandbyUidPackages} with the current app ops state.
+     */
+    private void refreshForcedAppStandbyUidPackagesLocked() {
+        final int op = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
+
+        mForcedAppStandbyUidPackages.clear();
+        final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(new int[] {op});
+
+        if (ops == null) {
+            return;
+        }
+        final int size = ops.size();
+        for (int i = 0; i < size; i++) {
+            final AppOpsManager.PackageOps pkg = ops.get(i);
+            final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+
+            for (int j = 0; j < entries.size(); j++) {
+                AppOpsManager.OpEntry ent = entries.get(j);
+                if (ent.getOp() != op) {
+                    continue;
+                }
+                if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
+                    mForcedAppStandbyUidPackages.add(Pair.create(
+                            pkg.getUid(), pkg.getPackageName()));
+                }
+            }
+        }
+    }
+
+    boolean isRunAnyInBackgroundAppOpRestricted(int uid, @NonNull String packageName) {
+        try {
+            return mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+                    uid, packageName) != AppOpsManager.MODE_ALLOWED;
+        } catch (RemoteException e) {
+            return false; // shouldn't happen.
+        }
+    }
+
+    private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
+        // TODO Maybe we should switch to indexOf(Pair.create()) if the array size is too big.
+        final int size = mForcedAppStandbyUidPackages.size();
+        for (int i = 0; i < size; i++) {
+            final Pair<Integer, String> pair = mForcedAppStandbyUidPackages.valueAt(i);
+
+            if ((pair.first == uid) && packageName.equals(pair.second)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * @return whether a uid package-name pair is in mForcedAppStandbyUidPackages.
+     */
+    boolean isUidPackageRestrictedLocked(int uid, @NonNull String packageName) {
+        return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
+    }
+
+    boolean updateRestrictedUidPackageLocked(int uid, @NonNull String packageName,
+            boolean restricted) {
+        final int index =  findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
+        final boolean wasRestricted = index >= 0;
+        if (wasRestricted == restricted) {
+            return false;
+        }
+        if (restricted) {
+            mForcedAppStandbyUidPackages.add(Pair.create(uid, packageName));
+        } else {
+            mForcedAppStandbyUidPackages.removeAt(index);
+        }
+        return true;
+    }
+
+    void uidToForeground(int uid) {
+        synchronized (mLock) {
+            if (!UserHandle.isApp(uid)) {
+                return;
+            }
+            // TODO This can be optimized by calling indexOfKey and sharing the index for get and
+            // put.
+            if (mForegroundUids.get(uid)) {
+                return;
+            }
+            mForegroundUids.put(uid, true);
+            notifyForUidPackage(uid, null);
+        }
+    }
+
+    void uidToBackground(int uid, boolean remove) {
+        synchronized (mLock) {
+            if (!UserHandle.isApp(uid)) {
+                return;
+            }
+            // TODO This can be optimized by calling indexOfKey and sharing the index for get and
+            // put.
+            if (!mForegroundUids.get(uid)) {
+                return;
+            }
+            if (remove) {
+                mForegroundUids.delete(uid);
+            } else {
+                mForegroundUids.put(uid, false);
+            }
+            notifyForUidPackage(uid, null);
+        }
+    }
+
+    // Event handlers
+
+    final class UidObserver extends IUidObserver.Stub {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        }
+
+        @Override public void onUidGone(int uid, boolean disabled) {
+            uidToBackground(uid, /*remove=*/ true);
+        }
+
+        @Override public void onUidActive(int uid) {
+            uidToForeground(uid);
+        }
+
+        @Override public void onUidIdle(int uid, boolean disabled) {
+            // Just to avoid excessive memcpy, don't remove from the array in this case.
+            uidToBackground(uid, /*remove=*/ false);
+        }
+
+        @Override public void onUidCachedChanged(int uid, boolean cached) {
+        }
+    };
+
+    private final class AppOpsWatcher extends IAppOpsCallback.Stub {
+        @Override
+        public void opChanged(int op, int uid, String packageName) throws RemoteException {
+            synchronized (mLock) {
+                final boolean restricted = isRunAnyInBackgroundAppOpRestricted(uid, packageName);
+
+                if (updateRestrictedUidPackageLocked(uid, packageName, restricted)) {
+                    notifyForUidPackage(uid, packageName);
+                }
+            }
+        }
+    }
+
+    private Listener[] cloneListeners() {
+        synchronized (mLock) {
+            return mListeners.toArray(new Listener[mListeners.size()]);
+        }
+    }
+
+    void notifyForUidPackage(int uid, String packageName) {
+        mCallbackHandler.post(() -> {
+            for (Listener l : cloneListeners()) {
+                l.onRestrictionChanged(uid, packageName);
+            }
+        });
+    }
+
+    void notifyGlobal() {
+        mCallbackHandler.post(() -> {
+            for (Listener l : cloneListeners()) {
+                l.onGlobalRestrictionChanged();
+            }
+        });
+    }
+
+    void updateForceAllAppsStandby(boolean forceAllAppsStandby) {
+        synchronized (mLock) {
+            if (mForceAllAppsStandby == forceAllAppsStandby) {
+                return;
+            }
+            mForceAllAppsStandby = forceAllAppsStandby;
+            Slog.i(TAG, "Force all app standby: " + mForceAllAppsStandby);
+            notifyGlobal();
+        }
+    }
+
+    // Public interface.
+
+    /**
+     * Register a new listener.
+     */
+    public void addListener(@NonNull Listener listener) {
+        synchronized (mLock) {
+            mListeners.add(listener);
+        }
+    }
+
+    /**
+     * Whether force-app-standby is effective for a UID package-name.
+     */
+    public boolean isRestricted(int uid, @NonNull String packageName) {
+        if (isInForeground(uid)) {
+            return false;
+        }
+        synchronized (mLock) {
+            if (mForceAllAppsStandby) {
+                return true;
+            }
+            return isUidPackageRestrictedLocked(uid, packageName);
+        }
+    }
+
+    /** For dumpsys -- otherwise the callers don't need to know it. */
+    public boolean isInForeground(int uid) {
+        if (!UserHandle.isApp(uid)) {
+            return true;
+        }
+        synchronized (mLock) {
+            return mForegroundUids.get(uid);
+        }
+    }
+
+    /** For dumpsys -- otherwise the callers don't need to know it. */
+    public boolean isForceAllAppsStandbyEnabled() {
+        synchronized (mLock) {
+            return mForceAllAppsStandby;
+        }
+    }
+
+    /** For dumpsys -- otherwise the callers don't need to know it. */
+    public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
+        synchronized (mLock) {
+            return !isUidPackageRestrictedLocked(uid, packageName);
+        }
+    }
+
+    /** For dumpsys -- otherwise the callers don't need to know it. */
+    public SparseBooleanArray getForegroudUids() {
+        synchronized (mLock) {
+            return mForegroundUids.clone();
+        }
+    }
+
+    /** For dumpsys -- otherwise the callers don't need to know it. */
+    public ArraySet<Pair<Integer, String>> getRestrictedUidPackages() {
+        synchronized (mLock) {
+            return new ArraySet(mForcedAppStandbyUidPackages);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2131731..701c574 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1043,8 +1043,8 @@
                         try {
                             if (AppGlobals.getPackageManager().checkPermission(
                                     android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
-                                    r.appInfo.packageName,
-                                    r.appInfo.uid) != PackageManager.PERMISSION_GRANTED) {
+                                    r.appInfo.packageName, UserHandle.getUserId(r.appInfo.uid))
+                                            != PackageManager.PERMISSION_GRANTED) {
                                 throw new SecurityException("Instant app " + r.appInfo.packageName
                                         + " does not have permission to create foreground"
                                         + "services");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ea2d1f3..fe5c789 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -222,6 +222,7 @@
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
+import android.app.IAssistDataReceiver;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
 import android.app.IProcessObserver;
@@ -373,7 +374,6 @@
 import com.android.internal.app.DumpHeapActivity;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.SystemUserHomeActivity;
@@ -4712,8 +4712,8 @@
     }
 
     @Override
-    public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle bOptions,
-            int userId) {
+    public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle options,
+            Bundle activityOptions, int userId) {
         if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
             String msg = "Permission Denial: startRecentsActivity() from pid="
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
@@ -4747,8 +4747,9 @@
                 final Intent intent = new Intent();
                 intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
                 intent.setComponent(recentsComponent);
+                intent.putExtras(options);
                 return mActivityStarter.startActivityMayWait(null, recentsUid, recentsPackage,
-                        intent, null, null, null, null, null, 0, 0, null, null, null, bOptions,
+                        intent, null, null, null, null, null, 0, 0, null, null, null, activityOptions,
                         false, userId, null, "startRecentsActivity");
             }
         } finally {
@@ -14921,6 +14922,23 @@
                 synchronized (this) {
                     writeBroadcastsToProtoLocked(proto);
                 }
+            } else if ("provider".equals(cmd)) {
+                String[] newArgs;
+                String name;
+                if (opti >= args.length) {
+                    name = null;
+                    newArgs = EMPTY_STRING_ARRAY;
+                } else {
+                    name = args[opti];
+                    opti++;
+                    newArgs = new String[args.length - opti];
+                    if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
+                            args.length - opti);
+                }
+                if (!dumpProviderProto(fd, pw, name, newArgs)) {
+                    pw.println("No providers match: " + name);
+                    pw.println("Use -h for help.");
+                }
             } else {
                 // default option, dump everything, output is ActivityManagerServiceProto
                 synchronized (this) {
@@ -16062,6 +16080,15 @@
         return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
     }
 
+    /**
+     * Similar to the dumpProvider, but only dumps the first matching provider.
+     * The provider is responsible for dumping as proto.
+     */
+    protected boolean dumpProviderProto(FileDescriptor fd, PrintWriter pw, String name,
+            String[] args) {
+        return mProviderMap.dumpProviderProto(fd, pw, name, args);
+    }
+
     static class ItemMatcher {
         ArrayList<ComponentName> components;
         ArrayList<String> strings;
diff --git a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
index f22fe37..9991ce1 100644
--- a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
+++ b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
@@ -19,13 +19,13 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.app.IAssistDataReceiver;
 import android.graphics.Bitmap;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
 
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
 
 /**
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index a8f829f..9f7621f 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -23,6 +23,7 @@
 
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.IAssistDataReceiver;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
@@ -31,7 +32,6 @@
 import android.view.IWindowManager;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.logging.MetricsLogger;
 
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
index 32d03da..8a905f8 100644
--- a/services/core/java/com/android/server/am/ProviderMap.java
+++ b/services/core/java/com/android/server/am/ProviderMap.java
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -322,8 +323,7 @@
         return needSep;
     }
 
-    protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
-            int opti, boolean dumpAll) {
+    private ArrayList<ContentProviderRecord> getProvidersForName(String name) {
         ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>();
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
 
@@ -365,6 +365,12 @@
                 }
             }
         }
+        return providers;
+    }
+
+    protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+            int opti, boolean dumpAll) {
+        ArrayList<ContentProviderRecord> providers = getProvidersForName(name);
 
         if (providers.size() <= 0) {
             return false;
@@ -417,6 +423,33 @@
     }
 
     /**
+     * Similar to the dumpProvider, but only dumps the first matching provider.
+     * The provider is responsible for dumping as proto.
+     */
+    protected boolean dumpProviderProto(FileDescriptor fd, PrintWriter pw, String name,
+            String[] args) {
+        //add back the --proto arg, which was stripped out by PriorityDump
+        String[] newArgs = Arrays.copyOf(args, args.length + 1);
+        newArgs[args.length] = "--proto";
+
+        ArrayList<ContentProviderRecord> providers = getProvidersForName(name);
+
+        if (providers.size() <= 0) {
+            return false;
+        }
+
+        // Only dump the first provider, since we are dumping in proto format
+        for (int i = 0; i < providers.size(); i++) {
+            final ContentProviderRecord r = providers.get(i);
+            if (r.proc != null && r.proc.thread != null) {
+                dumpToTransferPipe(null, fd, pw, r, newArgs);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider without
      * any meta string (e.g., provider info, indentation) written to the file descriptor.
      */
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2df5dc9..4e3d8d2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -89,6 +89,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
 import com.android.server.pm.UserManagerService;
@@ -355,27 +356,35 @@
         // Only keep marching forward if user is actually unlocked
         if (!StorageManager.isUserKeyUnlocked(userId)) return;
         synchronized (mLock) {
-            // Bail if we ended up with a stale user
-            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
-
-            // Do not proceed if unexpected state
-            if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+            // Do not proceed if unexpected state or a stale user
+            if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
                 return;
             }
         }
-        mInjector.getUserManagerInternal().setUserState(userId, uss.state);
         uss.mUnlockProgress.start();
 
         // Prepare app storage before we go any further
         uss.mUnlockProgress.setProgress(5,
                     mInjector.getContext().getString(R.string.android_start_title));
-        mInjector.getUserManager().onBeforeUnlockUser(userId);
-        uss.mUnlockProgress.setProgress(20);
 
-        // Dispatch unlocked to system services; when fully dispatched,
-        // that calls through to the next "unlocked" phase
-        mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
-                .sendToTarget();
+        // Call onBeforeUnlockUser on a worker thread that allows disk I/O
+        FgThread.getHandler().post(() -> {
+            mInjector.getUserManager().onBeforeUnlockUser(userId);
+            synchronized (mLock) {
+                // Do not proceed if unexpected state
+                if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+                    return;
+                }
+            }
+            mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+
+            uss.mUnlockProgress.setProgress(20);
+
+            // Dispatch unlocked to system services; when fully dispatched,
+            // that calls through to the next "unlocked" phase
+            mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
+                    .sendToTarget();
+        });
     }
 
     /**
@@ -1819,7 +1828,10 @@
             case SYSTEM_USER_UNLOCK_MSG:
                 final int userId = msg.arg1;
                 mInjector.getSystemServiceManager().unlockUser(userId);
-                mInjector.loadUserRecents(userId);
+                // Loads recents on a worker thread that allows disk I/O
+                FgThread.getHandler().post(() -> {
+                    mInjector.loadUserRecents(userId);
+                });
                 if (userId == UserHandle.USER_SYSTEM) {
                     mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
                 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b549768..b9777ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -622,24 +622,15 @@
             if (disabled) {
                 cancelJobsForUid(uid, "uid gone");
             }
-            synchronized (mLock) {
-                mBackgroundJobsController.setUidActiveLocked(uid, false);
-            }
         }
 
         @Override public void onUidActive(int uid) throws RemoteException {
-            synchronized (mLock) {
-                mBackgroundJobsController.setUidActiveLocked(uid, true);
-            }
         }
 
         @Override public void onUidIdle(int uid, boolean disabled) {
             if (disabled) {
                 cancelJobsForUid(uid, "app uid idle");
             }
-            synchronized (mLock) {
-                mBackgroundJobsController.setUidActiveLocked(uid, false);
-            }
         }
 
         @Override public void onUidCachedChanged(int uid, boolean cached) {
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 78b4160..f67bd04 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,7 +16,6 @@
 
 package com.android.server.job.controllers;
 
-import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -25,19 +24,20 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.UserHandle;
-import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.ForceAppStandbyTracker;
+import com.android.server.ForceAppStandbyTracker.Listener;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobStore;
 
 import java.io.PrintWriter;
+import java.util.function.Predicate;
 
 public final class BackgroundJobsController extends StateController {
 
@@ -49,18 +49,13 @@
     private static volatile BackgroundJobsController sController;
 
     private final JobSchedulerService mJobSchedulerService;
-    private final IAppOpsService mAppOpsService;
     private final IDeviceIdleController mDeviceIdleController;
 
-    private final SparseBooleanArray mForegroundUids;
     private int[] mPowerWhitelistedUserAppIds;
     private int[] mTempWhitelistedAppIds;
-    /**
-     * Only tracks jobs for which source package app op RUN_ANY_IN_BACKGROUND is not ALLOWED.
-     * Maps jobs to the sourceUid unlike the global {@link JobSchedulerService#mJobs JobStore}
-     * which uses callingUid.
-     */
-    private SparseArray<ArraySet<JobStatus>> mTrackedJobs;
+
+    private final ForceAppStandbyTracker mForceAppStandbyTracker;
+
 
     public static BackgroundJobsController get(JobSchedulerService service) {
         synchronized (sCreationLock) {
@@ -89,9 +84,7 @@
                 } catch (RemoteException rexc) {
                     Slog.e(LOG_TAG, "Device idle controller not reachable");
                 }
-                if (checkAllTrackedJobsLocked()) {
-                    mStateChangedListener.onControllerStateChanged();
-                }
+                updateAllJobRestrictionsLocked();
             }
         }
     };
@@ -99,16 +92,12 @@
     private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
         super(service, context, lock);
         mJobSchedulerService = service;
-        mAppOpsService = IAppOpsService.Stub.asInterface(
-                ServiceManager.getService(Context.APP_OPS_SERVICE));
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
 
-        mForegroundUids = new SparseBooleanArray();
-        mTrackedJobs = new SparseArray<>();
+        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
+
         try {
-            mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
-                    new AppOpsWatcher());
             mPowerWhitelistedUserAppIds = mDeviceIdleController.getAppIdUserWhitelist();
             mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
         } catch (RemoteException rexc) {
@@ -120,184 +109,165 @@
         powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         context.registerReceiverAsUser(mDozeWhitelistReceiver, UserHandle.ALL, powerWhitelistFilter,
                 null, null);
+
+        mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
+        mForceAppStandbyTracker.start();
     }
 
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
-        final int uid = jobStatus.getSourceUid();
-        final String packageName = jobStatus.getSourcePackageName();
-        try {
-            final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
-                    uid, packageName);
-            if (mode == AppOpsManager.MODE_ALLOWED) {
-                jobStatus.setBackgroundNotRestrictedConstraintSatisfied(true);
-                return;
-            }
-        } catch (RemoteException rexc) {
-            Slog.e(LOG_TAG, "Cannot reach app ops service", rexc);
-        }
-        jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRunJobLocked(uid));
-        startTrackingJobLocked(jobStatus);
+        updateSingleJobRestrictionLocked(jobStatus);
     }
 
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
             boolean forUpdate) {
-        stopTrackingJobLocked(jobStatus);
-    }
-
-    /* Called by JobSchedulerService to report uid state changes between active and idle */
-    public void setUidActiveLocked(int uid, boolean active) {
-        final boolean changed = (active != mForegroundUids.get(uid));
-        if (!changed) {
-            return;
-        }
-        if (DEBUG) {
-            Slog.d(LOG_TAG, "uid " + uid + " going to " + (active ? "fg" : "bg"));
-        }
-        if (active) {
-            mForegroundUids.put(uid, true);
-        } else {
-            mForegroundUids.delete(uid);
-        }
-        if (checkTrackedJobsForUidLocked(uid)) {
-            mStateChangedListener.onControllerStateChanged();
-        }
     }
 
     @Override
     public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
         pw.println("BackgroundJobsController");
+
+        pw.print("Force all apps standby: ");
+        pw.println(mForceAppStandbyTracker.isForceAllAppsStandbyEnabled());
+
         pw.print("Foreground uids: [");
-        for (int i = 0; i < mForegroundUids.size(); i++) {
-            if (mForegroundUids.valueAt(i)) pw.print(mForegroundUids.keyAt(i) + " ");
+        final SparseBooleanArray foregroundUids = mForceAppStandbyTracker.getForegroudUids();
+
+        String sep = "";
+        for (int i = 0; i < foregroundUids.size(); i++) {
+            if (foregroundUids.valueAt(i)) {
+                pw.print(sep);
+                pw.print(UserHandle.formatUid(foregroundUids.keyAt(i)));
+                sep = " ";
+            }
         }
         pw.println("]");
-        mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
-            @Override
-            public void process(JobStatus jobStatus) {
-                if (!jobStatus.shouldDump(filterUid)) {
-                    return;
-                }
-                final int uid = jobStatus.getSourceUid();
-                pw.print("  #");
-                jobStatus.printUniqueId(pw);
-                pw.print(" from ");
-                UserHandle.formatUid(pw, uid);
-                pw.print(mForegroundUids.get(uid) ? " foreground" : " background");
-                if (isWhitelistedLocked(uid)) {
-                    pw.print(", whitelisted");
-                }
-                pw.print(": ");
-                pw.print(jobStatus.getSourcePackageName());
-                pw.print(" [background restrictions");
-                final ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
-                pw.print(jobsForUid != null && jobsForUid.contains(jobStatus) ? " on]" : " off]");
-                if ((jobStatus.satisfiedConstraints
-                        & JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
-                    pw.println(" RUNNABLE");
-                } else {
-                    pw.println(" WAITING");
-                }
+
+        pw.println("Restricted packages:");
+        for (Pair<Integer, String> uidAndPackage
+                : mForceAppStandbyTracker.getRestrictedUidPackages()) {
+            pw.print("  ");
+            pw.print(UserHandle.formatUid(uidAndPackage.first));
+            pw.print(" ");
+            pw.print(uidAndPackage.second);
+            pw.println();
+        }
+
+        pw.println("Job state:");
+        mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
+            if (!jobStatus.shouldDump(filterUid)) {
+                return;
+            }
+            final int uid = jobStatus.getSourceUid();
+            pw.print("  #");
+            jobStatus.printUniqueId(pw);
+            pw.print(" from ");
+            UserHandle.formatUid(pw, uid);
+            pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
+            if (isWhitelistedLocked(uid)) {
+                pw.print(", whitelisted");
+            }
+            pw.print(": ");
+            pw.print(jobStatus.getSourcePackageName());
+
+            pw.print(" [background restrictions ");
+            pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
+                    jobStatus.getSourceUid(), jobStatus.getSourcePackageName()) ? "off]" : "on]");
+
+            if ((jobStatus.satisfiedConstraints
+                    & JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
+                pw.println(" RUNNABLE");
+            } else {
+                pw.println(" WAITING");
             }
         });
     }
 
-    void startTrackingJobLocked(JobStatus jobStatus) {
+    private void updateAllJobRestrictionsLocked() {
+        updateJobRestrictionsLocked(/*filterUid=*/ -1);
+    }
+
+    private void updateJobRestrictionsForUidLocked(int uid) {
+
+        // TODO Use forEachJobForSourceUid() once we have it.
+
+        updateJobRestrictionsLocked(/*filterUid=*/ uid);
+    }
+
+    private void updateJobRestrictionsLocked(int filterUid) {
+        final UpdateJobFunctor updateTrackedJobs =
+                new UpdateJobFunctor(filterUid);
+
+        final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
+
+        mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
+
+        final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
+        if (DEBUG) {
+            Slog.d(LOG_TAG, String.format(
+                    "Job status updated: %d/%d checked/total jobs, %d us",
+                    updateTrackedJobs.mCheckedCount,
+                    updateTrackedJobs.mTotalCount,
+                    (time / 1000)
+                    ));
+        }
+
+        if (updateTrackedJobs.mChanged) {
+            mStateChangedListener.onControllerStateChanged();
+        }
+    }
+
+    private boolean isWhitelistedLocked(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        return ArrayUtils.contains(mTempWhitelistedAppIds, appId)
+                || ArrayUtils.contains(mPowerWhitelistedUserAppIds, appId);
+    }
+
+    boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
+
         final int uid = jobStatus.getSourceUid();
-        ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
-        if (jobsForUid == null) {
-            jobsForUid = new ArraySet<>();
-            mTrackedJobs.put(uid, jobsForUid);
-        }
-        jobsForUid.add(jobStatus);
+        final String packageName = jobStatus.getSourcePackageName();
+
+        final boolean canRun = isWhitelistedLocked(uid)
+                || !mForceAppStandbyTracker.isRestricted(uid, packageName);
+
+        return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
     }
 
-    void stopTrackingJobLocked(JobStatus jobStatus) {
-        final int uid = jobStatus.getSourceUid();
-        ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
-        if (jobsForUid != null) {
-            jobsForUid.remove(jobStatus);
-        }
-    }
+    private final class UpdateJobFunctor implements JobStore.JobStatusFunctor {
+        private final int mFilterUid;
 
-    boolean checkAllTrackedJobsLocked() {
-        boolean changed = false;
-        for (int i = 0; i < mTrackedJobs.size(); i++) {
-            changed |= checkTrackedJobsForUidLocked(mTrackedJobs.keyAt(i));
-        }
-        return changed;
-    }
+        boolean mChanged = false;
+        int mTotalCount = 0;
+        int mCheckedCount = 0;
 
-    private boolean checkTrackedJobsForUidLocked(int uid) {
-        final ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
-        boolean changed = false;
-        if (jobsForUid != null) {
-            for (int i = 0; i < jobsForUid.size(); i++) {
-                JobStatus jobStatus = jobsForUid.valueAt(i);
-                changed |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(
-                        canRunJobLocked(uid));
-            }
-        }
-        return changed;
-    }
-
-    boolean isWhitelistedLocked(int uid) {
-        return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid))
-                || ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
-    }
-
-    boolean canRunJobLocked(int uid) {
-        return mForegroundUids.get(uid) || isWhitelistedLocked(uid);
-    }
-
-    private final class AppOpsWatcher extends IAppOpsCallback.Stub {
-        @Override
-        public void opChanged(int op, int uid, String packageName) throws RemoteException {
-            synchronized (mLock) {
-                final int mode = mAppOpsService.checkOperation(op, uid, packageName);
-                if (DEBUG) {
-                    Slog.d(LOG_TAG,
-                            "Appop changed for " + uid + ", " + packageName + " to " + mode);
-                }
-                final boolean shouldTrack = (mode != AppOpsManager.MODE_ALLOWED);
-                UpdateTrackedJobsFunc updateTrackedJobs = new UpdateTrackedJobsFunc(uid,
-                        packageName, shouldTrack);
-                mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
-                if (updateTrackedJobs.mChanged) {
-                    mStateChangedListener.onControllerStateChanged();
-                }
-            }
-        }
-    }
-
-    private final class UpdateTrackedJobsFunc implements JobStore.JobStatusFunctor {
-        private final String mPackageName;
-        private final int mUid;
-        private final boolean mShouldTrack;
-        private boolean mChanged = false;
-
-        UpdateTrackedJobsFunc(int uid, String packageName, boolean shouldTrack) {
-            mUid = uid;
-            mPackageName = packageName;
-            mShouldTrack = shouldTrack;
+        UpdateJobFunctor(int filterUid) {
+            mFilterUid = filterUid;
         }
 
         @Override
         public void process(JobStatus jobStatus) {
-            final String packageName = jobStatus.getSourcePackageName();
-            final int uid = jobStatus.getSourceUid();
-            if (mUid != uid || !mPackageName.equals(packageName)) {
+            mTotalCount++;
+            if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
                 return;
             }
-            if (mShouldTrack) {
-                mChanged |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(
-                        canRunJobLocked(uid));
-                startTrackingJobLocked(jobStatus);
-            } else {
-                mChanged |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(true);
-                stopTrackingJobLocked(jobStatus);
+            mCheckedCount++;
+            if (updateSingleJobRestrictionLocked(jobStatus)) {
+                mChanged = true;
             }
         }
     }
+
+    private final Listener mForceAppStandbyListener = new Listener() {
+        @Override
+        public void onRestrictionChanged(int uid, String packageName) {
+            updateJobRestrictionsForUidLocked(uid);
+        }
+
+        @Override
+        public void onGlobalRestrictionChanged() {
+            updateAllJobRestrictionsLocked();
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 557ba42..eb94414 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -736,6 +736,11 @@
                 for (NotificationVisibility nv : newlyVisibleKeys) {
                     NotificationRecord r = mNotificationsByKey.get(nv.key);
                     if (r == null) continue;
+                    if (!r.isSeen()) {
+                        // Report to usage stats that notification was made visible
+                        if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
+                        reportSeen(r);
+                    }
                     r.setVisibility(true, nv.rank);
                     nv.recycle();
                 }
@@ -1643,6 +1648,14 @@
         return INotificationManager.Stub.asInterface(mService);
     }
 
+    protected void reportSeen(NotificationRecord r) {
+        final int userId = r.sbn.getUserId();
+        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
+                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
+                        : userId,
+                UsageEvents.Event.NOTIFICATION_SEEN);
+    }
+
     @VisibleForTesting
     NotificationManagerInternal getInternalService() {
         return mInternalService;
@@ -2269,10 +2282,7 @@
                             }
                             if (!r.isSeen()) {
                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
-                                mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
-                                                : userId,
-                                        UsageEvents.Event.USER_INTERACTION);
+                                reportSeen(r);
                                 r.setSeen();
                             }
                         }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 29f48ee..00cfa31 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -154,7 +154,13 @@
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         final List<String> paths = pkg.getAllCodePaths();
-        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+        int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+        if (sharedGid == -1) {
+            Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
+                    + pkg.applicationInfo.uid, new Throwable());
+            sharedGid = android.os.Process.NOBODY_UID;
+        }
 
         // Get the class loader context dependencies.
         // For each code path in the package, this array contains the class loader context that
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1152310..dbf413f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -717,6 +717,19 @@
         }
     }
 
+    @Override
+    public int getProfileParentId(int userHandle) {
+        checkManageUsersPermission("get the profile parent");
+        synchronized (mUsersLock) {
+            UserInfo profileParent = getProfileParentLU(userHandle);
+            if (profileParent == null) {
+                return userHandle;
+            }
+
+            return profileParent.id;
+        }
+    }
+
     private UserInfo getProfileParentLU(int userHandle) {
         UserInfo profile = getUserInfoLU(userHandle);
         if (profile == null) {
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 15121b8..3992f8a 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -29,16 +29,21 @@
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Class to decide whether to turn on battery saver mode for specific service
  *
+ * TODO: We should probably make {@link #mFilesForInteractive} and {@link #mFilesForNoninteractive}
+ * less flexible and just take a list of "CPU number - frequency" pairs. Being able to write
+ * anything under /sys/ and /proc/ is too loose.
+ *
  * Test: atest BatterySaverPolicyTest
  */
 public class BatterySaverPolicy extends ContentObserver {
@@ -62,12 +67,11 @@
     private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
     private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
     private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
-    private static final String KEY_FORCE_ALL_APPS_STANDBY_JOBS = "force_all_apps_standby_jobs";
-    private static final String KEY_FORCE_ALL_APPS_STANDBY_ALARMS = "force_all_apps_standby_alarms";
+    private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
     private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
 
-    private static final String KEY_SCREEN_ON_FILE_PREFIX = "file-on:";
-    private static final String KEY_SCREEN_OFF_FILE_PREFIX = "file-off:";
+    private static final String KEY_FILE_FOR_INTERACTIVE_PREFIX = "file-on:";
+    private static final String KEY_FILE_FOR_NONINTERACTIVE_PREFIX = "file-off:";
 
     private static String mSettings;
     private static String mDeviceSpecificSettings;
@@ -156,14 +160,9 @@
     private float mAdjustBrightnessFactor;
 
     /**
-     * Whether to put all apps in the stand-by mode or not for job scheduler.
+     * Whether to put all apps in the stand-by mode.
      */
-    private boolean mForceAllAppsStandbyJobs;
-
-    /**
-     * Whether to put all apps in the stand-by mode or not for alarms.
-     */
-    private boolean mForceAllAppsStandbyAlarms;
+    private boolean mForceAllAppsStandby;
 
     /**
      * Weather to show non-essential sensors (e.g. edge sensors) or not.
@@ -179,25 +178,25 @@
     private ContentResolver mContentResolver;
 
     @GuardedBy("mLock")
-    private final ArrayList<BatterySaverPolicyListener> mListeners = new ArrayList<>();
+    private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
 
     /**
      * List of [Filename -> content] that should be written when battery saver is activated
-     * and the screen is on.
+     * and the device is interactive.
      *
      * We use this to change the max CPU frequencies.
      */
     @GuardedBy("mLock")
-    private ArrayMap<String, String> mScreenOnFiles;
+    private ArrayMap<String, String> mFilesForInteractive;
 
     /**
      * List of [Filename -> content] that should be written when battery saver is activated
-     * and the screen is off.
+     * and the device is non-interactive.
      *
      * We use this to change the max CPU frequencies.
      */
     @GuardedBy("mLock")
-    private ArrayMap<String, String> mScreenOffFiles;
+    private ArrayMap<String, String> mFilesForNoninteractive;
 
     public interface BatterySaverPolicyListener {
         void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
@@ -236,11 +235,6 @@
         return R.string.config_batterySaverDeviceSpecificConfig;
     }
 
-    @VisibleForTesting
-    void onChangeForTest() {
-        onChange(true, null);
-    }
-
     @Override
     public void onChange(boolean selfChange, Uri uri) {
         final BatterySaverPolicyListener[] listeners;
@@ -297,9 +291,7 @@
         mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
         mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
         mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
-        mForceAllAppsStandbyJobs = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY_JOBS, true);
-        mForceAllAppsStandbyAlarms =
-                parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY_ALARMS, true);
+        mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
         mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
 
         // Get default value from Settings.Secure
@@ -315,8 +307,8 @@
                     + deviceSpecificSetting);
         }
 
-        mScreenOnFiles = collectParams(parser, KEY_SCREEN_ON_FILE_PREFIX);
-        mScreenOffFiles = collectParams(parser, KEY_SCREEN_OFF_FILE_PREFIX);
+        mFilesForInteractive = collectParams(parser, KEY_FILE_FOR_INTERACTIVE_PREFIX);
+        mFilesForNoninteractive = collectParams(parser, KEY_FILE_FOR_NONINTERACTIVE_PREFIX);
     }
 
     private static ArrayMap<String, String> collectParams(
@@ -330,7 +322,7 @@
             }
             final String path = key.substring(prefix.length());
 
-            if (!(path.startsWith("/sys/") || path.startsWith("/proc"))) {
+            if (!(path.startsWith("/sys/") || path.startsWith("/proc/"))) {
                 Slog.wtf(TAG, "Invalid path: " + path);
                 continue;
             }
@@ -387,12 +379,6 @@
                 case ServiceType.VIBRATION:
                     return builder.setBatterySaverEnabled(mVibrationDisabled)
                             .build();
-                case ServiceType.FORCE_ALL_APPS_STANDBY_JOBS:
-                    return builder.setBatterySaverEnabled(mForceAllAppsStandbyJobs)
-                            .build();
-                case ServiceType.FORCE_ALL_APPS_STANDBY_ALARMS:
-                    return builder.setBatterySaverEnabled(mForceAllAppsStandbyAlarms)
-                            .build();
                 case ServiceType.OPTIONAL_SENSORS:
                     return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
                             .build();
@@ -403,9 +389,9 @@
         }
     }
 
-    public ArrayMap<String, String> getFileValues(boolean screenOn) {
+    public ArrayMap<String, String> getFileValues(boolean interactive) {
         synchronized (mLock) {
-            return screenOn ? mScreenOnFiles : mScreenOffFiles;
+            return interactive ? mFilesForInteractive : mFilesForNoninteractive;
         }
     }
 
@@ -428,17 +414,16 @@
             pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
             pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
             pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
-            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY_JOBS + "=" + mForceAllAppsStandbyJobs);
-            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY_ALARMS + "=" + mForceAllAppsStandbyAlarms);
+            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
             pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
             pw.println();
 
-            pw.print("  Screen On Files:\n");
-            dumpMap(pw, "    ", mScreenOnFiles);
+            pw.print("  Interactive File values:\n");
+            dumpMap(pw, "    ", mFilesForInteractive);
             pw.println();
 
-            pw.print("  Screen Off Files:\n");
-            dumpMap(pw, "    ", mScreenOffFiles);
+            pw.print("  Noninteractive File values:\n");
+            dumpMap(pw, "    ", mFilesForNoninteractive);
             pw.println();
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a47b809..584761c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3105,7 +3105,7 @@
         mIsVrModeEnabled = enabled;
     }
 
-    public static void powerHintInternal(int hintId, int data) {
+    private static void powerHintInternal(int hintId, int data) {
         nativeSendPowerHint(hintId, data);
     }
 
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 755c5f0..6bf725e 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -68,7 +68,8 @@
 public final class ShutdownThread extends Thread {
     // constants
     private static final String TAG = "ShutdownThread";
-    private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
+    private static final int ACTION_DONE_POLL_WAIT_MS = 500;
+    private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
     // maximum time we wait for the shutdown broadcast before going on.
     private static final int MAX_BROADCAST_TIME = 10*1000;
     private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
@@ -471,7 +472,7 @@
                     sInstance.setRebootProgress(status, null);
                 }
                 try {
-                    mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
+                    mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
                 } catch (InterruptedException e) {
                 }
             }
@@ -565,7 +566,7 @@
                     sInstance.setRebootProgress(status, null);
                 }
                 try {
-                    mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
+                    mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
                 } catch (InterruptedException e) {
                 }
             }
@@ -710,8 +711,7 @@
                         done[0] = true;
                         break;
                     }
-                    SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
-
+                    SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
                     delay = endTime - SystemClock.elapsedRealtime();
                 }
             }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index b3e8538..3db6a25 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -25,6 +25,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.PowerManagerInternal.LowPowerModeListener;
 import android.os.PowerSaveState;
 import android.os.UserHandle;
@@ -33,7 +34,9 @@
 import android.widget.Toast;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
 import com.android.server.power.BatterySaverPolicy;
 import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
 import com.android.server.power.PowerManagerService;
@@ -63,20 +66,17 @@
     @GuardedBy("mLock")
     private boolean mEnabled;
 
-    /**
-     * Keep track of the previous enabled state, which we use to decide when to send broadcasts,
-     * which we don't want to send only when the screen state changes.
-     */
-    @GuardedBy("mLock")
-    private boolean mWasEnabled;
-
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             switch (intent.getAction()) {
                 case Intent.ACTION_SCREEN_ON:
                 case Intent.ACTION_SCREEN_OFF:
-                    mHandler.postStateChanged();
+                    if (!isEnabled()) {
+                        return; // No need to send it if not enabled.
+                    }
+                    // Don't send the broadcast, because we never did so in this case.
+                    mHandler.postStateChanged(/*sendBroadcast=*/ false);
                     break;
             }
         }
@@ -121,25 +121,32 @@
 
     @Override
     public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) {
-        mHandler.postStateChanged();
+        if (!isEnabled()) {
+            return; // No need to send it if not enabled.
+        }
+        mHandler.postStateChanged(/*sendBroadcast=*/ true);
     }
 
     private class MyHandler extends Handler {
-        private final int MSG_STATE_CHANGED = 1;
+        private static final int MSG_STATE_CHANGED = 1;
+
+        private static final int ARG_DONT_SEND_BROADCAST = 0;
+        private static final int ARG_SEND_BROADCAST = 1;
 
         public MyHandler(Looper looper) {
             super(looper);
         }
 
-        public void postStateChanged() {
-            obtainMessage(MSG_STATE_CHANGED).sendToTarget();
+        public void postStateChanged(boolean sendBroadcast) {
+            obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
+                    ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
         }
 
         @Override
         public void dispatchMessage(Message msg) {
             switch (msg.what) {
                 case MSG_STATE_CHANGED:
-                    handleBatterySaverStateChanged();
+                    handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
                     break;
             }
         }
@@ -155,38 +162,53 @@
             }
             mEnabled = enable;
 
-            mHandler.postStateChanged();
+            mHandler.postStateChanged(/*sendBroadcast=*/ true);
+        }
+    }
+
+    /** @return whether battery saver is enabled or not. */
+    boolean isEnabled() {
+        synchronized (mLock) {
+            return mEnabled;
         }
     }
 
     /**
      * Dispatch power save events to the listeners.
      *
-     * This is always called on the handler thread.
+     * This method is always called on the handler thread.
+     *
+     * This method is called only in the following cases:
+     * - When battery saver becomes activated.
+     * - When battery saver becomes deactivated.
+     * - When battery saver is on the interactive state changes.
+     * - When battery saver is on the battery saver policy changes.
      */
-    void handleBatterySaverStateChanged() {
+    void handleBatterySaverStateChanged(boolean sendBroadcast) {
         final LowPowerModeListener[] listeners;
 
-        final boolean wasEnabled;
         final boolean enabled;
-        final boolean isScreenOn = getPowerManager().isInteractive();
+        final boolean isInteractive = getPowerManager().isInteractive();
         final ArrayMap<String, String> fileValues;
 
         synchronized (mLock) {
-            Slog.i(TAG, "Battery saver enabled: screen on=" + isScreenOn);
+            Slog.i(TAG, "Battery saver " + (mEnabled ? "enabled" : "disabled")
+                    + ": isInteractive=" + isInteractive);
 
             listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
-            wasEnabled = mWasEnabled;
             enabled = mEnabled;
 
             if (enabled) {
-                fileValues = mBatterySaverPolicy.getFileValues(isScreenOn);
+                fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
             } else {
                 fileValues = null;
             }
         }
 
-        PowerManagerService.powerHintInternal(PowerHint.LOW_POWER, enabled ? 1 : 0);
+        final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+        if (pmi != null) {
+            pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
+        }
 
         if (enabled) {
             // STOPSHIP Remove the toast.
@@ -195,13 +217,13 @@
                     Toast.LENGTH_LONG).show();
         }
 
-        if (fileValues == null || fileValues.size() == 0) {
+        if (ArrayUtils.isEmpty(fileValues)) {
             mFileUpdater.restoreDefault();
         } else {
             mFileUpdater.writeFiles(fileValues);
         }
 
-        if (enabled != wasEnabled) {
+        if (sendBroadcast) {
             if (DEBUG) {
                 Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
             }
@@ -231,9 +253,5 @@
                 listener.onLowPowerModeChanged(result);
             }
         }
-
-        synchronized (mLock) {
-            mWasEnabled = enabled;
-        }
     }
 }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index e1edf11..dafab77 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -182,7 +182,7 @@
             Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
-                    Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+                    Slog.w(TAG, "Could not access statsd to inform it of an app update");
                     return;
                 }
                 try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 723b888..ce34306 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -124,6 +124,7 @@
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.IAssistDataReceiver;
 import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ContentResolver;
@@ -226,7 +227,6 @@
 import android.view.inputmethod.InputMethodManagerInternal;
 
 import com.android.internal.R;
-import com.android.internal.app.IAssistDataReceiver;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IKeyguardDismissCallback;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 74a7bd4a..33f4e34 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -35,6 +35,7 @@
 import android.os.IIncidentManager;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -360,6 +361,9 @@
             // to avoid throwing BadParcelableException.
             BaseBundle.setShouldDefuse(true);
 
+            // Within the system server, when parceling exceptions, include the stack trace
+            Parcel.setStackTraceParceling(true);
+
             // Ensure binder calls into the system always run at foreground priority.
             BinderInternal.disableBackgroundScheduling(true);
 
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index f63d1e7..114929c 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -48,7 +48,7 @@
 # TODO(b/69254249): Migrate to Robolectric 3.4.2
 LOCAL_JAVA_LIBRARIES := \
     junit \
-    platform-robolectric-prebuilt
+    platform-robolectric-3.1.1-prebuilt
 
 LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
 LOCAL_MODULE := FrameworksServicesRoboTests
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 70e8a16..66f5770 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -144,7 +144,9 @@
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
-        public TestableNotificationManagerService(Context context) { super(context); }
+        public TestableNotificationManagerService(Context context) {
+            super(context);
+        }
 
         @Override
         protected boolean isCallingUidSystem() {
@@ -160,6 +162,11 @@
         protected ICompanionDeviceManager getCompanionManager() {
             return null;
         }
+
+        @Override
+        protected void reportSeen(NotificationRecord r) {
+            return;
+        }
     }
 
     @Before
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index fbb5fd2..afece5d 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -428,7 +428,8 @@
         assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
         assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
         assertSecurityException(expectCallable, () -> mService.cancelTaskThumbnailTransition(0));
-        assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null, 0));
+        assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
+                null, 0));
     }
 
     private void testGetTasksApis(boolean expectCallable) {
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index f22dfdc..c7fd551 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -11,7 +11,6 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
@@ -623,12 +622,6 @@
     }
 
     @Override
-    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
-            String installerPackageName) {
-
-    }
-
-    @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer, int flags,
             String installerPackageName) {
 
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index afe432b..467b47a 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -37,7 +37,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -57,10 +56,10 @@
  * To run this test from root of checkout:
  * <pre>
  *  mmm -j32 frameworks/base/services/tests/servicestests/
- *  adb install out/target/product/marlin/data/app/JobTestApp/JobTestApp.apk
- *  adb install out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ *  adb install -r $OUT/data/app/JobTestApp/JobTestApp.apk
+ *  adb install -r $OUT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
  *  adb  shell am instrument -e class 'com.android.server.job.BackgroundRestrictionsTest' -w \
- *  'com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner'
+    com.android.frameworks.servicestests
  * </pre>
  */
 @RunWith(AndroidJUnit4.class)
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 5b6225e..0db19e4 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -18,13 +18,13 @@
 import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.Handler;
-import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 
 import com.android.frameworks.servicestests.R;
+import com.android.internal.annotations.VisibleForTesting;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -68,6 +68,12 @@
         int getDeviceSpecificConfigResId() {
             return mDeviceSpecificConfigResId;
         }
+
+
+        @VisibleForTesting
+        void onChange() {
+            onChange(true, null);
+        }
     }
 
     @Mock
@@ -221,14 +227,14 @@
         mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
         mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, "");
 
-        mBatterySaverPolicy.onChangeForTest();
+        mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
 
 
         mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_2;
 
-        mBatterySaverPolicy.onChangeForTest();
+        mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString())
                 .isEqualTo("{/sys/a=1, /sys/b=2}");
@@ -236,7 +242,7 @@
 
         mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
 
-        mBatterySaverPolicy.onChangeForTest();
+        mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{/proc/c=4}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{/sys/a=3}");
 
@@ -244,7 +250,7 @@
         mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
                 "file-on:/proc/z=4");
 
-        mBatterySaverPolicy.onChangeForTest();
+        mBatterySaverPolicy.onChange();
         assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{/proc/z=4}");
         assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
     }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 8531baf..baa3e05 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -17,6 +17,9 @@
 package com.android.server.usage;
 
 import static android.app.usage.AppStandby.*;
+import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
+import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -247,21 +250,27 @@
                         false));
     }
 
-    private void reportEvent(AppStandbyController controller, long elapsedTime) {
+    private void reportEvent(AppStandbyController controller, int eventType,
+            long elapsedTime) {
         // Back to ACTIVE on event
         UsageEvents.Event ev = new UsageEvents.Event();
         ev.mPackage = PACKAGE_1;
-        ev.mEventType = UsageEvents.Event.USER_INTERACTION;
+        ev.mEventType = eventType;
         controller.reportEvent(ev, elapsedTime, USER_ID);
     }
 
+    private int getStandbyBucket(AppStandbyController controller) {
+        return controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
+                true);
+    }
+
     @Test
     public void testBuckets() throws Exception {
         AppStandbyController controller = setupController();
 
         assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
 
-        reportEvent(controller, 0);
+        reportEvent(controller, USER_INTERACTION, 0);
 
         // ACTIVE bucket
         assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
@@ -278,7 +287,7 @@
         // RARE bucket
         assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE);
 
-        reportEvent(controller, 9 * DAY_MS);
+        reportEvent(controller, USER_INTERACTION, 9 * DAY_MS);
 
         assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE);
 
@@ -293,7 +302,7 @@
 
         assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
 
-        reportEvent(controller, 0);
+        reportEvent(controller, USER_INTERACTION, 0);
 
         // ACTIVE bucket
         assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
@@ -304,9 +313,7 @@
         // RARE bucket, should fail because the screen wasn't ON.
         mInjector.mElapsedRealtime = 9 * DAY_MS;
         controller.checkIdleStates(USER_ID);
-        assertNotEquals(STANDBY_BUCKET_RARE,
-                controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
-                false));
+        assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller));
 
         mInjector.setDisplayOn(true);
         assertTimeout(controller, 18 * DAY_MS, STANDBY_BUCKET_RARE);
@@ -318,8 +325,7 @@
         setChargingState(controller, false);
 
         controller.forceIdleState(PACKAGE_1, USER_ID, true);
-        assertEquals(STANDBY_BUCKET_RARE, controller.getAppStandbyBucket(PACKAGE_1, USER_ID, 0,
-                true));
+        assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(controller));
         assertTrue(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
 
         controller.forceIdleState(PACKAGE_1, USER_ID, false);
@@ -327,4 +333,20 @@
                 true));
         assertFalse(controller.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
     }
+
+    @Test
+    public void testNotificationEvent() throws Exception {
+        AppStandbyController controller = setupController();
+        setChargingState(controller, false);
+
+        reportEvent(controller, USER_INTERACTION, 0);
+        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller));
+        mInjector.mElapsedRealtime = 1;
+        reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+        assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(controller));
+
+        controller.forceIdleState(PACKAGE_1, USER_ID, true);
+        reportEvent(controller, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+        assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(controller));
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index c5ca330..1e5eb05 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -186,7 +186,7 @@
         writeScreenOnTime();
     }
 
-    public void reportUsage(String packageName, int userId, long elapsedRealtime) {
+    public int reportUsage(String packageName, int userId, long elapsedRealtime) {
         ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
         AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
                 elapsedRealtime, true);
@@ -197,12 +197,33 @@
                 + (elapsedRealtime - mElapsedSnapshot);
         appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
         appUsageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
-        appUsageHistory.currentBucket = AppStandby.STANDBY_BUCKET_ACTIVE;
-        appUsageHistory.bucketingReason = AppStandby.REASON_USAGE;
-        if (DEBUG) {
-            Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
-                    + ", reason=" + appUsageHistory.bucketingReason);
+        if (appUsageHistory.currentBucket > STANDBY_BUCKET_ACTIVE) {
+            appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE;
+            if (DEBUG) {
+                Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+                        + ", reason=" + appUsageHistory.bucketingReason);
+            }
         }
+        appUsageHistory.bucketingReason = AppStandby.REASON_USAGE;
+
+        return appUsageHistory.currentBucket;
+    }
+
+    public int reportMildUsage(String packageName, int userId, long elapsedRealtime) {
+        ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
+        AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
+                elapsedRealtime, true);
+        if (appUsageHistory.currentBucket > STANDBY_BUCKET_WORKING_SET) {
+            appUsageHistory.currentBucket = STANDBY_BUCKET_WORKING_SET;
+            if (DEBUG) {
+                Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+                        + ", reason=" + appUsageHistory.bucketingReason);
+            }
+        }
+        // TODO: Should this be a different reason for partial usage?
+        appUsageHistory.bucketingReason = AppStandby.REASON_USAGE;
+
+        return appUsageHistory.currentBucket;
     }
 
     public void setIdle(String packageName, int userId, long elapsedRealtime) {
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 5623a68..97f7de2 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -229,6 +229,7 @@
         // Get sync adapters for the authority
         String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
                 authority, userId);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
         for (String packageName: packages) {
             // Only force the sync adapters to active if the provider is not in the same package and
             // the sync adapter is a system package.
@@ -239,7 +240,12 @@
                     continue;
                 }
                 if (!packageName.equals(providerPkgName)) {
-                    setAppIdleAsync(packageName, false, userId);
+                    synchronized (mAppIdleLock) {
+                        int newBucket = mAppIdleHistory.reportMildUsage(packageName, userId,
+                                    elapsedRealtime);
+                        maybeInformListeners(packageName, userId, elapsedRealtime,
+                                newBucket);
+                    }
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 // Shouldn't happen
@@ -493,11 +499,21 @@
             if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND
                     || event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
                     || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
-                    || event.mEventType == UsageEvents.Event.USER_INTERACTION)) {
-                mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
+                    || event.mEventType == UsageEvents.Event.USER_INTERACTION
+                    || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN)) {
+
+                final int newBucket;
+                if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
+                    newBucket = mAppIdleHistory.reportMildUsage(event.mPackage, userId,
+                            elapsedRealtime);
+                } else {
+                    newBucket = mAppIdleHistory.reportUsage(event.mPackage, userId,
+                            elapsedRealtime);
+                }
+
+                maybeInformListeners(event.mPackage, userId, elapsedRealtime,
+                        newBucket);
                 if (previouslyIdle) {
-                    maybeInformListeners(event.mPackage, userId, elapsedRealtime,
-                            AppStandby.STANDBY_BUCKET_ACTIVE);
                     notifyBatteryStats(event.mPackage, userId, false);
                 }
             }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 0b10590..f02221c 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -643,6 +643,8 @@
                 return "SHORTCUT_INVOCATION";
             case UsageEvents.Event.CHOOSER_ACTION:
                 return "CHOOSER_ACTION";
+            case UsageEvents.Event.NOTIFICATION_SEEN:
+                return "NOTIFICATION_SEEN";
             default:
                 return "UNKNOWN";
         }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e13bd61..a07f2bb 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -855,6 +855,39 @@
      */
     public static abstract class Callback {
         /**
+         * @hide
+         */
+        @IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
+                HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface HandoverFailureErrors {}
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
+         * to handover the call rejects handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there is
+         * an error associated with unsupported handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+         * are some permission errors associated with APIs doing handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when user
+         * rejects handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+
+
+        /**
          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
          *
          * @param call The {@code Call} invoking this method.
@@ -989,6 +1022,21 @@
          *               {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
          */
         public void onRttInitiationFailure(Call call, int reason) {}
+
+        /**
+         * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+         * has completed successfully.
+         * @param call The call which had initiated handover.
+         */
+        public void onHandoverComplete(Call call) {}
+
+        /**
+         * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+         * has failed.
+         * @param call The call which had initiated handover.
+         * @param failureReason Error reason for failure
+         */
+        public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
     }
 
     /**
@@ -1367,6 +1415,24 @@
     }
 
     /**
+     * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+     * by {@code toHandle}.  The videoState specified indicates the desired video state after the
+     * handover.
+     * <p>
+     * A handover request is initiated by the user from one app to indicate a desire
+     * to handover a call to another.
+     *
+     * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
+     *                 this call to.
+     * @param videoState Indicates the video state desired after the handover.
+     * @param extras Bundle containing extra information to be passed to the
+     *               {@link ConnectionService}
+     */
+    public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
+        mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
+    }
+
+    /**
      * Terminate the RTT session on this call. The resulting state change will be notified via
      * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
      */
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ffb5e93..2bb1c4e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1684,6 +1684,8 @@
 
     // The internal telecom call ID associated with this connection.
     private String mTelecomCallId;
+    // The PhoneAccountHandle associated with this connection.
+    private PhoneAccountHandle mPhoneAccountHandle;
     private int mState = STATE_NEW;
     private CallAudioState mCallAudioState;
     private Uri mAddress;
@@ -3099,6 +3101,27 @@
     }
 
     /**
+     * Sets the {@link PhoneAccountHandle} associated with this connection.
+     *
+     * @hide
+     */
+    public void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+        if (mPhoneAccountHandle != phoneAccountHandle) {
+            mPhoneAccountHandle = phoneAccountHandle;
+            notifyPhoneAccountChanged(phoneAccountHandle);
+        }
+    }
+
+    /**
+     * Returns the {@link PhoneAccountHandle} associated with this connection.
+     *
+     * @hide
+     */
+    public PhoneAccountHandle getPhoneAccountHandle() {
+        return mPhoneAccountHandle;
+    }
+
+    /**
      * Sends an event associated with this {@code Connection} with associated event extras to the
      * {@link InCallService}.
      * <p>
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 35804f6..7e83306 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1382,7 +1382,7 @@
 
         connection.setTelecomCallId(callId);
         if (connection.getState() != Connection.STATE_DISCONNECTED) {
-            addConnection(callId, connection);
+            addConnection(request.getAccountHandle(), callId, connection);
         }
 
         Uri address = connection.getAddress();
@@ -1846,6 +1846,7 @@
                     mAdapter.setIsConferenced(connectionId, id);
                 }
             }
+            onConferenceAdded(conference);
         }
     }
 
@@ -2033,6 +2034,43 @@
     }
 
     /**
+     * Called by Telecom on the initiating side of the handover to create an instance of a
+     * handover connection.
+     * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+     *                               ConnectionService which needs to handover the call.
+     * @param request Details about the call which needs to be handover.
+     * @return Connection object corresponding to the handover call.
+     */
+    public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+                                                         ConnectionRequest request) {
+        return null;
+    }
+
+    /**
+     * Called by Telecom on the receiving side of the handover to request the
+     * {@link ConnectionService} to create an instance of a handover connection.
+     * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+     *                               ConnectionService which needs to handover the call.
+     * @param request Details about the call which needs to be handover.
+     * @return {@link Connection} object corresponding to the handover call.
+     */
+    public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+                                                         ConnectionRequest request) {
+        return null;
+    }
+
+    /**
+     * Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
+     * invocation which failed.
+     * @param request Details about the call which needs to be handover.
+     * @param error Reason for handover failure as defined in
+     *              {@link android.telecom.Call.Callback#HANDOVER_FAILURE_DEST_INVALID_PERM}
+     */
+    public void onHandoverFailed(ConnectionRequest request, int error) {
+        return;
+    }
+
+    /**
      * Create a {@code Connection} for a new unknown call. An unknown call is a call originating
      * from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming
      * call created using
@@ -2056,6 +2094,30 @@
     public void onConference(Connection connection1, Connection connection2) {}
 
     /**
+     * Called when a connection is added.
+     * @hide
+     */
+    public void onConnectionAdded(Connection connection) {}
+
+    /**
+     * Called when a connection is removed.
+     * @hide
+     */
+    public void onConnectionRemoved(Connection connection) {}
+
+    /**
+     * Called when a conference is added.
+     * @hide
+     */
+    public void onConferenceAdded(Conference conference) {}
+
+    /**
+     * Called when a conference is removed.
+     * @hide
+     */
+    public void onConferenceRemoved(Conference conference) {}
+
+    /**
      * Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
      * When this method is invoked, this {@link ConnectionService} should create its own
      * representation of the conference call and send it to telecom using {@link #addConference}.
@@ -2122,16 +2184,18 @@
             // prefix for a unique incremental call ID.
             id = handle.getComponentName().getClassName() + "@" + getNextCallId();
         }
-        addConnection(id, connection);
+        addConnection(handle, id, connection);
         return id;
     }
 
-    private void addConnection(String callId, Connection connection) {
+    private void addConnection(PhoneAccountHandle handle, String callId, Connection connection) {
         connection.setTelecomCallId(callId);
         mConnectionById.put(callId, connection);
         mIdByConnection.put(connection, callId);
         connection.addConnectionListener(mConnectionListener);
         connection.setConnectionService(this);
+        connection.setPhoneAccountHandle(handle);
+        onConnectionAdded(connection);
     }
 
     /** {@hide} */
@@ -2143,6 +2207,7 @@
             mConnectionById.remove(id);
             mIdByConnection.remove(connection);
             mAdapter.removeCall(id);
+            onConnectionRemoved(connection);
         }
     }
 
@@ -2179,6 +2244,8 @@
             mConferenceById.remove(id);
             mIdByConference.remove(conference);
             mAdapter.removeCall(id);
+
+            onConferenceRemoved(conference);
         }
     }
 
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 9bf0467..4bc2a9b 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -435,4 +435,21 @@
         } catch (RemoteException ignored) {
         }
     }
+
+
+    /**
+     * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+     * by destAcct.
+     * @param callId The callId of the Call which calls this function.
+     * @param destAcct ConnectionService to which the call should be handed over.
+     * @param videoState The video state desired after the handover.
+     * @param extras Extra information to be passed to ConnectionService
+     */
+    public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
+                           Bundle extras) {
+        try {
+            mAdapter.handoverTo(callId, destAcct, videoState, extras);
+        } catch (RemoteException ignored) {
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 691e7cf..74b9465 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -86,13 +86,11 @@
     /**
      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
-     * connection (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) to this
-     * {@link PhoneAccount} from a {@link PhoneAccount} specifying
-     * {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
+     * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from
+     * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
      * <p>
      * A handover request is initiated by the user from the default dialer app to indicate a desire
      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
-     * @hide
      */
     public static final String EXTRA_SUPPORTS_HANDOVER_TO =
             "android.telecom.extra.SUPPORTS_HANDOVER_TO";
@@ -113,12 +111,11 @@
      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
      * connection from this {@link PhoneAccount} to another {@link PhoneAccount}.
-     * (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) which specifies
+     * (see {@code android.telecom.Call#handoverTo()}) which specifies
      * {@link #EXTRA_SUPPORTS_HANDOVER_TO}.
      * <p>
      * A handover request is initiated by the user from the default dialer app to indicate a desire
      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
-     * @hide
      */
     public static final String EXTRA_SUPPORTS_HANDOVER_FROM =
             "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
@@ -132,7 +129,6 @@
      * <p>
      * By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log.
      * Setting this extra to {@code true} provides a means for them to log their calls.
-     * @hide
      */
     public static final String EXTRA_LOG_SELF_MANAGED_CALLS =
             "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f30d7bd..05480dc 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1065,7 +1065,7 @@
      *
      * @param state The audio state of this {@code RemoteConnection}.
      * @hide
-     * @deprecated Use {@link #setCallAudioState(CallAudioState) instead.
+     * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead.
      */
     @SystemApi
     @Deprecated
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9e52c71..da32e0b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1750,6 +1750,41 @@
         return false;
     }
 
+    /**
+     * Called from the recipient side of a handover to indicate a desire to accept the handover
+     * of an ongoing call to another {@link ConnectionService} identified by
+     * {@link PhoneAccountHandle} destAcct. For managed {@link ConnectionService}s, the specified
+     * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+     * the user must have enabled the corresponding {@link PhoneAccount}.  This can be checked using
+     * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+     * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to handover a call to it.
+     * <p>
+     * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+     * associated with the {@link PhoneAccountHandle} destAcct and call
+     * (See {@link ConnectionService#onCreateIncomingHandoverConnection}).
+     * <p>
+     * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+     * the {@link PhoneAccountHandle} destAcct does not correspond to a registered
+     * {@link PhoneAccount} or the associated {@link PhoneAccount} is not currently enabled by the
+     * user.
+     * <p>
+     * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
+     * the calling app does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
+     *
+     * @param srcAddr The {@link android.net.Uri} of the ongoing call to handover to the caller’s
+     *                {@link ConnectionService}.
+     * @param videoState Video state after the handover.
+     * @param destAcct The {@link PhoneAccountHandle} registered to the calling package.
+     */
+    public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
+        try {
+            if (isServiceConnected()) {
+                getTelecomService().acceptHandover(srcAddr, videoState, destAcct);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException acceptHandover: " + e);
+        }
+    }
 
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index bce3392..23ac940 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -77,4 +77,7 @@
     void stopRtt(String callId);
 
     void setRttMode(String callId, int mode);
+
+    void handoverTo(String callId, in PhoneAccountHandle destAcct, int videoState,
+            in Bundle extras);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 8ebac2c..3460754 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -274,4 +274,9 @@
      * @see TelecomServiceImpl#waitOnHandler
      */
     void waitOnHandlers();
+
+    /**
+     * @see TelecomServiceImpl#acceptHandover
+     */
+    void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
 }
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 4d7c71f..dc897a2 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -122,7 +122,10 @@
             // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -131,7 +134,10 @@
             // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index fd837fc..f234b0a 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -121,7 +121,10 @@
             // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -130,7 +133,10 @@
             // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 1597245..1a461f2 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -121,7 +121,10 @@
             // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
@@ -130,13 +133,16 @@
             // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
         mAlphaShort = alphas;
     }
-    
+
     private CellIdentityWcdma(CellIdentityWcdma cid) {
         this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2f39ddb..64cc7c1 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -28,6 +28,7 @@
 import android.net.INetworkPolicyManager;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -446,7 +447,15 @@
      * for #onSubscriptionsChanged to be invoked.
      */
     public static class OnSubscriptionsChangedListener {
-        private final Handler mHandler  = new Handler() {
+        private class OnSubscriptionsChangedListenerHandler extends Handler {
+            OnSubscriptionsChangedListenerHandler() {
+                super();
+            }
+
+            OnSubscriptionsChangedListenerHandler(Looper looper) {
+                super(looper);
+            }
+
             @Override
             public void handleMessage(Message msg) {
                 if (DBG) {
@@ -454,7 +463,22 @@
                 }
                 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
             }
-        };
+        }
+
+        private final Handler mHandler;
+
+        public OnSubscriptionsChangedListener() {
+            mHandler = new OnSubscriptionsChangedListenerHandler();
+        }
+
+        /**
+         * Allow a listener to be created with a custom looper
+         * @param looper the looper that the underlining handler should run on
+         * @hide
+         */
+        public OnSubscriptionsChangedListener(Looper looper) {
+            mHandler = new OnSubscriptionsChangedListenerHandler(looper);
+        }
 
         /**
          * Callback invoked when there is any change to any SubscriptionInfo. Typically
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
new file mode 100644
index 0000000..18da8b8
--- /dev/null
+++ b/test-mock/Android.mk
@@ -0,0 +1,144 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
+
+# Build the repackaged.android.test.mock library
+# ==============================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
+
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
+
+LOCAL_MODULE:= repackaged.android.test.mock
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Build the android.test.mock library
+# ===================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+
+LOCAL_MODULE:= android.test.mock
+
+include $(BUILD_JAVA_LIBRARY)
+
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
+# Generate the stub source files for android.test.mock.stubs
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(android_test_mock_source_files)
+
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
+
+ANDROID_TEST_MOCK_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/api.txt
+ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/removed.txt
+
+ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
+ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
+
+LOCAL_DROIDDOC_OPTIONS:= \
+    -stubpackages android.test.mock \
+    -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
+    -nodocs \
+    -api $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) \
+    -removedApi $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) \
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_MODULE := android-test-mock-api-stubs-gen
+
+include $(BUILD_DROIDDOC)
+
+# Remember the target that will trigger the code generation.
+android_test_mock_gen_stamp := $(full_target)
+
+# Add some additional dependencies
+$(ANDROID_TEST_MOCK_OUTPUT_API_FILE): $(full_target)
+$(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE): $(full_target)
+
+# Build the android.test.mock.stubs library
+# =========================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.mock.stubs
+
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+
+# Make sure to run droiddoc first to generate the stub source files.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
+android_test_mock_gen_stamp :=
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.stubs.jar)
+
+# Check that the android.test.mock.stubs library has not changed
+# ==============================================================
+
+# Check that the API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+    check-android-test-mock-api-current, \
+    $(ANDROID_TEST_MOCK_API_FILE), \
+    $(ANDROID_TEST_MOCK_OUTPUT_API_FILE), \
+    $(ANDROID_TEST_MOCK_REMOVED_API_FILE), \
+    $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE), \
+    -error 2 -error 3 -error 4 -error 5 -error 6 \
+    -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+    -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+    -error 25 -error 26 -error 27, \
+    cat $(LOCAL_PATH)/api/apicheck_msg_android_test_mock.txt, \
+    check-android-test-mock-api, \
+    $(call doc-timestamp-for,android-test-mock-api-stubs-gen) \
+    ))
+
+.PHONY: check-android-test-mock-api
+checkapi: check-android-test-mock-api
+
+.PHONY: update-android-test-mock-api
+update-api: update-android-test-mock-api
+
+update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP)
+	@echo Copying current.txt
+	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
+	@echo Copying removed.txt
+	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
+
+# Build the android.test.mock.sdk library
+# =======================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.mock.sdk
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-runner/api/android-test-mock-current.txt b/test-mock/api/android-test-mock-current.txt
similarity index 99%
rename from test-runner/api/android-test-mock-current.txt
rename to test-mock/api/android-test-mock-current.txt
index 93bbf6c..07fcee2 100644
--- a/test-runner/api/android-test-mock-current.txt
+++ b/test-mock/api/android-test-mock-current.txt
@@ -344,7 +344,6 @@
     method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int installExistingPackageAsUser(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void installPackage(android.net.Uri, android.content.pm.IPackageInstallObserver, int, java.lang.String);
     method public void installPackage(android.net.Uri, android.app.PackageInstallObserver, int, java.lang.String);
     method public boolean isInstantApp();
     method public boolean isInstantApp(java.lang.String);
diff --git a/test-runner/api/android-test-mock-removed.txt b/test-mock/api/android-test-mock-removed.txt
similarity index 100%
rename from test-runner/api/android-test-mock-removed.txt
rename to test-mock/api/android-test-mock-removed.txt
diff --git a/test-runner/api/apicheck_msg_android_test_mock.txt b/test-mock/api/apicheck_msg_android_test_mock.txt
similarity index 100%
rename from test-runner/api/apicheck_msg_android_test_mock.txt
rename to test-mock/api/apicheck_msg_android_test_mock.txt
diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-mock/src/android/test/mock/MockApplication.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockApplication.java
rename to test-mock/src/android/test/mock/MockApplication.java
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockContentProvider.java
rename to test-mock/src/android/test/mock/MockContentProvider.java
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockContentResolver.java
rename to test-mock/src/android/test/mock/MockContentResolver.java
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockContext.java
rename to test-mock/src/android/test/mock/MockContext.java
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-mock/src/android/test/mock/MockCursor.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockCursor.java
rename to test-mock/src/android/test/mock/MockCursor.java
diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-mock/src/android/test/mock/MockDialogInterface.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockDialogInterface.java
rename to test-mock/src/android/test/mock/MockDialogInterface.java
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockIContentProvider.java
rename to test-mock/src/android/test/mock/MockIContentProvider.java
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
similarity index 98%
rename from test-runner/src/android/test/mock/MockPackageManager.java
rename to test-mock/src/android/test/mock/MockPackageManager.java
index 7e08f51..0c562e6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -26,12 +26,11 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ChangedPackages;
-import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -653,15 +652,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * @hide - to match hiding in superclass
-     */
-    @Override
-    public void installPackage(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-mock/src/android/test/mock/MockResources.java
similarity index 100%
rename from test-runner/src/android/test/mock/MockResources.java
rename to test-mock/src/android/test/mock/MockResources.java
diff --git a/test-runner/src/android/test/mock/package.html b/test-mock/src/android/test/mock/package.html
similarity index 100%
rename from test-runner/src/android/test/mock/package.html
rename to test-mock/src/android/test/mock/package.html
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 3367aba..d0f5b32 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,14 +16,11 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
-
 # Build the android.test.runner library
 # =====================================
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := \
-    $(filter-out $(android_test_mock_source_files), $(call all-java-files-under, src))
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := \
     core-oj \
@@ -42,7 +39,12 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
+LOCAL_JAVA_LIBRARIES := \
+    core-oj \
+    core-libart \
+    framework \
+    legacy-test \
+    android.test.mock \
 
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
 
@@ -57,10 +59,7 @@
 # ============================================================
 include $(CLEAR_VARS)
 
-# Exclude android.test.mock classes as stubs for them are created in the
-# android.test.mock.stubs target
-LOCAL_SRC_FILES := \
-    $(filter-out $(android_test_mock_source_files), $(call all-java-files-under, src))
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := \
     core-oj \
@@ -153,117 +152,3 @@
 	$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
 
 endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
-
-# Build the android.test.mock library
-# ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(android_test_mock_source_files)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-LOCAL_MODULE:= android.test.mock
-
-include $(BUILD_JAVA_LIBRARY)
-
-# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
-ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
-
-# Generate the stub source files for android.test.mock.stubs
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(android_test_mock_source_files)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
-
-ANDROID_TEST_MOCK_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/api.txt
-ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/removed.txt
-
-ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
-ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
-
-LOCAL_DROIDDOC_OPTIONS:= \
-    -stubpackages android.test.mock \
-    -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
-    -nodocs \
-    -api $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) \
-    -removedApi $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := android-test-mock-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-android_test_mock_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(ANDROID_TEST_MOCK_OUTPUT_API_FILE): $(full_target)
-$(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the android.test.mock.stubs library
-# =========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.stubs
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
-android_test_mock_gen_stamp :=
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.stubs.jar)
-
-# Check that the android.test.mock.stubs library has not changed
-# ==============================================================
-
-# Check that the API we're building hasn't changed from the not-yet-released
-# SDK version.
-$(eval $(call check-api, \
-    check-android-test-mock-api-current, \
-    $(ANDROID_TEST_MOCK_API_FILE), \
-    $(ANDROID_TEST_MOCK_OUTPUT_API_FILE), \
-    $(ANDROID_TEST_MOCK_REMOVED_API_FILE), \
-    $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE), \
-    -error 2 -error 3 -error 4 -error 5 -error 6 \
-    -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
-    -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
-    -error 25 -error 26 -error 27, \
-    cat $(LOCAL_PATH)/api/apicheck_msg_android_test_mock.txt, \
-    check-android-test-mock-api, \
-    $(call doc-timestamp-for,android-test-mock-api-stubs-gen) \
-    ))
-
-.PHONY: check-android-test-mock-api
-checkapi: check-android-test-mock-api
-
-.PHONY: update-android-test-mock-api
-update-api: update-android-test-mock-api
-
-update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP)
-	@echo Copying current.txt
-	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
-	@echo Copying removed.txt
-	$(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
-
-# Build the android.test.mock.sdk library
-# =======================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.sdk
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif  # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 08efc27..0f6fb50 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -218,6 +218,7 @@
       if (attr.id) {
         printer_->Print(attr.id.value().to_string());
       }
+      printer_->Println();
     }
   }
 
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 96a0203..6fcf0f6 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -268,6 +268,11 @@
   return out << res_id.to_string();
 }
 
+// For generic code to call 'using std::to_string; to_string(T);'.
+inline std::string to_string(const ResourceId& id) {
+  return id.to_string();
+}
+
 //
 // ResourceType implementation.
 //
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 66b5a7a..e94c0b4 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -16,7 +16,6 @@
 
 #include <sys/stat.h>
 
-#include <fstream>
 #include <queue>
 #include <unordered_map>
 #include <vector>
@@ -212,6 +211,8 @@
 // This delegate will attempt to masquerade any '@id/' references with ID 0xPPTTEEEE,
 // where PP > 7f, as 0x7fPPEEEE. Any potential overlapping is verified and an error occurs if such
 // an overlap exists.
+//
+// See b/37498913.
 class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
  public:
   FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
@@ -652,24 +653,26 @@
 static bool WriteStableIdMapToPath(IDiagnostics* diag,
                                    const std::unordered_map<ResourceName, ResourceId>& id_map,
                                    const std::string& id_map_path) {
-  std::ofstream fout(id_map_path, std::ofstream::binary);
-  if (!fout) {
-    diag->Error(DiagMessage(id_map_path) << strerror(errno));
+  io::FileOutputStream fout(id_map_path);
+  if (fout.HadError()) {
+    diag->Error(DiagMessage(id_map_path) << "failed to open: " << fout.GetError());
     return false;
   }
 
+  text::Printer printer(&fout);
   for (const auto& entry : id_map) {
     const ResourceName& name = entry.first;
     const ResourceId& id = entry.second;
-    fout << name << " = " << id << "\n";
+    printer.Print(name.to_string());
+    printer.Print(" = ");
+    printer.Println(id.to_string());
   }
+  fout.Flush();
 
-  if (!fout) {
-    diag->Error(DiagMessage(id_map_path) << "failed writing to file: "
-                                         << android::base::SystemErrorCodeToString(errno));
+  if (fout.HadError()) {
+    diag->Error(DiagMessage(id_map_path) << "failed writing to file: " << fout.GetError());
     return false;
   }
-
   return true;
 }
 
@@ -985,36 +988,35 @@
 
     file::AppendPath(&out_path, "R.java");
 
-    std::ofstream fout(out_path, std::ofstream::binary);
-    if (!fout) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed writing to '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    io::FileOutputStream fout(out_path);
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
 
-    std::unique_ptr<std::ofstream> fout_text;
+    std::unique_ptr<io::FileOutputStream> fout_text;
     if (out_text_symbols_path) {
-      fout_text =
-          util::make_unique<std::ofstream>(out_text_symbols_path.value(), std::ofstream::binary);
-      if (!*fout_text) {
-        context_->GetDiagnostics()->Error(
-            DiagMessage() << "failed writing to '" << out_text_symbols_path.value()
-                          << "': " << android::base::SystemErrorCodeToString(errno));
+      fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value());
+      if (fout_text->HadError()) {
+        context_->GetDiagnostics()->Error(DiagMessage()
+                                          << "failed writing to '" << out_text_symbols_path.value()
+                                          << "': " << fout_text->GetError());
         return false;
       }
     }
 
     JavaClassGenerator generator(context_, table, java_options);
     if (!generator.Generate(package_name_to_generate, out_package, &fout, fout_text.get())) {
-      context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.getError());
+      context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.GetError());
       return false;
     }
 
-    if (!fout) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed writing to '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    fout.Flush();
+
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
     return true;
@@ -1142,18 +1144,19 @@
 
     file::AppendPath(&out_path, "Manifest.java");
 
-    std::ofstream fout(out_path, std::ofstream::binary);
-    if (!fout) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed writing to '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    io::FileOutputStream fout(out_path);
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
 
-    if (!ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout)) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed writing to '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    ClassDefinition::WriteJavaFile(manifest_class.get(), package_utf8, true, &fout);
+    fout.Flush();
+
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
     return true;
@@ -1165,19 +1168,19 @@
     }
 
     const std::string& out_path = out.value();
-    std::ofstream fout(out_path, std::ofstream::binary);
-    if (!fout) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed to open '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    io::FileOutputStream fout(out_path);
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed to open '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
 
-    proguard::WriteKeepSet(&fout, keep_set);
-    if (!fout) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed writing to '" << out_path
-                                        << "': " << android::base::SystemErrorCodeToString(errno));
+    proguard::WriteKeepSet(keep_set, &fout);
+    fout.Flush();
+
+    if (fout.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage() << "failed writing to '" << out_path
+                                                      << "': " << fout.GetError());
       return false;
     }
     return true;
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp
index 4ff6d78..27529bc 100644
--- a/tools/aapt2/io/FileStream.cpp
+++ b/tools/aapt2/io/FileStream.cpp
@@ -25,6 +25,12 @@
 #include "android-base/macros.h"
 #include "android-base/utf8.h"
 
+#if defined(_WIN32)
+// This is only needed for O_CLOEXEC.
+#include <windows.h>
+#define O_CLOEXEC O_NOINHERIT
+#endif
+
 using ::android::base::SystemErrorCodeToString;
 using ::android::base::unique_fd;
 
@@ -32,18 +38,20 @@
 namespace io {
 
 FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
-    : FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
-                      buffer_capacity) {
+    : buffer_capacity_(buffer_capacity) {
+  int mode = O_RDONLY | O_CLOEXEC | O_BINARY;
+  fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode)));
+  if (fd_ == -1) {
+    error_ = SystemErrorCodeToString(errno);
+  } else {
+    buffer_.reset(new uint8_t[buffer_capacity_]);
+  }
 }
 
 FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
-    : fd_(fd),
-      buffer_capacity_(buffer_capacity),
-      buffer_offset_(0u),
-      buffer_size_(0u),
-      total_byte_count_(0u) {
-  if (fd_ == -1) {
-    error_ = SystemErrorCodeToString(errno);
+    : fd_(fd), buffer_capacity_(buffer_capacity) {
+  if (fd_ < 0) {
+    error_ = "Bad File Descriptor";
   } else {
     buffer_.reset(new uint8_t[buffer_capacity_]);
   }
@@ -100,9 +108,16 @@
   return error_;
 }
 
-FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
-    : FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
-                       buffer_capacity) {
+FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity)
+    : buffer_capacity_(buffer_capacity) {
+  int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
+  owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666)));
+  fd_ = owned_fd_.get();
+  if (fd_ < 0) {
+    error_ = SystemErrorCodeToString(errno);
+  } else {
+    buffer_.reset(new uint8_t[buffer_capacity_]);
+  }
 }
 
 FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
@@ -111,9 +126,9 @@
 }
 
 FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
-    : fd_(fd), buffer_capacity_(buffer_capacity), buffer_offset_(0u), total_byte_count_(0u) {
-  if (fd_ == -1) {
-    error_ = SystemErrorCodeToString(errno);
+    : fd_(fd), buffer_capacity_(buffer_capacity) {
+  if (fd_ < 0) {
+    error_ = "Bad File Descriptor";
   } else {
     buffer_.reset(new uint8_t[buffer_capacity_]);
   }
diff --git a/tools/aapt2/io/FileStream.h b/tools/aapt2/io/FileStream.h
index 4ed1ad5..62d910f 100644
--- a/tools/aapt2/io/FileStream.h
+++ b/tools/aapt2/io/FileStream.h
@@ -22,7 +22,6 @@
 #include <memory>
 #include <string>
 
-#include "android-base/file.h"  // for O_BINARY
 #include "android-base/macros.h"
 #include "android-base/unique_fd.h"
 
@@ -55,15 +54,15 @@
   android::base::unique_fd fd_;
   std::string error_;
   std::unique_ptr<uint8_t[]> buffer_;
-  size_t buffer_capacity_;
-  size_t buffer_offset_;
-  size_t buffer_size_;
-  size_t total_byte_count_;
+  size_t buffer_capacity_ = 0u;
+  size_t buffer_offset_ = 0u;
+  size_t buffer_size_ = 0u;
+  size_t total_byte_count_ = 0u;
 };
 
 class FileOutputStream : public OutputStream {
  public:
-  explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
+  explicit FileOutputStream(const std::string& path,
                             size_t buffer_capacity = kDefaultBufferCapacity);
 
   // Does not take ownership of `fd`.
@@ -97,9 +96,9 @@
   int fd_;
   std::string error_;
   std::unique_ptr<uint8_t[]> buffer_;
-  size_t buffer_capacity_;
-  size_t buffer_offset_;
-  size_t total_byte_count_;
+  size_t buffer_capacity_ = 0u;
+  size_t buffer_offset_ = 0u;
+  size_t total_byte_count_ = 0u;
 };
 
 }  // namespace io
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index a6d58ca..c0eaa8e 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -16,6 +16,7 @@
 
 #include "io/FileStream.h"
 
+#include "android-base/file.h"
 #include "android-base/macros.h"
 #include "android-base/test_utils.h"
 
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index c93461a..8d91b00 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -23,6 +23,7 @@
 #include "text/Utf8Iterator.h"
 #include "util/Util.h"
 
+using ::aapt::text::Printer;
 using ::aapt::text::Utf8Iterator;
 using ::android::StringPiece;
 
@@ -109,23 +110,22 @@
   }
 }
 
-void AnnotationProcessor::WriteToStream(const StringPiece& prefix, std::ostream* out) const {
+void AnnotationProcessor::Print(Printer* printer) const {
   if (has_comments_) {
     std::string result = comment_.str();
     for (StringPiece line : util::Tokenize(result, '\n')) {
-      *out << prefix << line << "\n";
+      printer->Println(line);
     }
-    *out << prefix << " */"
-         << "\n";
+    printer->Println(" */");
   }
 
   if (annotation_bit_mask_ & AnnotationRule::kDeprecated) {
-    *out << prefix << "@Deprecated\n";
+    printer->Println("@Deprecated");
   }
 
   for (const AnnotationRule& rule : sAnnotationRules) {
     if (annotation_bit_mask_ & rule.bit_mask) {
-      *out << prefix << rule.annotation << "\n";
+      printer->Println(rule.annotation);
     }
   }
 }
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index a7bf73f..ae7bdb0 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -22,6 +22,8 @@
 
 #include "androidfw/StringPiece.h"
 
+#include "text/Printer.h"
+
 namespace aapt {
 
 // Builds a JavaDoc comment from a set of XML comments.
@@ -61,8 +63,8 @@
 
   void AppendNewLine();
 
-  // Writes the comments and annotations to the stream, with the given prefix before each line.
-  void WriteToStream(const android::StringPiece& prefix, std::ostream* out) const;
+  // Writes the comments and annotations to the Printer.
+  void Print(text::Printer* printer) const;
 
  private:
   std::stringstream comment_;
diff --git a/tools/aapt2/java/AnnotationProcessor_test.cpp b/tools/aapt2/java/AnnotationProcessor_test.cpp
index 856f4cc..69f49c8 100644
--- a/tools/aapt2/java/AnnotationProcessor_test.cpp
+++ b/tools/aapt2/java/AnnotationProcessor_test.cpp
@@ -16,8 +16,12 @@
 
 #include "java/AnnotationProcessor.h"
 
+#include "io/StringStream.h"
 #include "test/Test.h"
+#include "text/Printer.h"
 
+using ::aapt::io::StringOutputStream;
+using ::aapt::text::Printer;
 using ::testing::Eq;
 using ::testing::HasSubstr;
 using ::testing::Not;
@@ -33,9 +37,11 @@
   AnnotationProcessor processor;
   processor.AppendComment(comment);
 
-  std::stringstream result;
-  processor.WriteToStream("", &result);
-  std::string annotations = result.str();
+  std::string annotations;
+  StringOutputStream out(&annotations);
+  Printer printer(&out);
+  processor.Print(&printer);
+  out.Flush();
 
   EXPECT_THAT(annotations, HasSubstr("@Deprecated"));
 }
@@ -44,9 +50,11 @@
   AnnotationProcessor processor;
   processor.AppendComment("@SystemApi This is a system API");
 
-  std::stringstream result;
-  processor.WriteToStream("", &result);
-  std::string annotations = result.str();
+  std::string annotations;
+  StringOutputStream out(&annotations);
+  Printer printer(&out);
+  processor.Print(&printer);
+  out.Flush();
 
   EXPECT_THAT(annotations, HasSubstr("@android.annotation.SystemApi"));
   EXPECT_THAT(annotations, Not(HasSubstr("@SystemApi")));
@@ -57,9 +65,11 @@
   AnnotationProcessor processor;
   processor.AppendComment("@TestApi This is a test API");
 
-  std::stringstream result;
-  processor.WriteToStream("", &result);
-  std::string annotations = result.str();
+  std::string annotations;
+  StringOutputStream out(&annotations);
+  Printer printer(&out);
+  processor.Print(&printer);
+  out.Flush();
 
   EXPECT_THAT(annotations, HasSubstr("@android.annotation.TestApi"));
   EXPECT_THAT(annotations, Not(HasSubstr("@TestApi")));
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 0c57e7e..b692ccf 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -18,25 +18,27 @@
 
 #include "androidfw/StringPiece.h"
 
+using ::aapt::text::Printer;
 using ::android::StringPiece;
 
 namespace aapt {
 
-void ClassMember::WriteToStream(const StringPiece& prefix, bool final, std::ostream* out) const {
-  processor_.WriteToStream(prefix, out);
+void ClassMember::Print(bool /*final*/, Printer* printer) const {
+  processor_.Print(printer);
 }
 
 void MethodDefinition::AppendStatement(const StringPiece& statement) {
   statements_.push_back(statement.to_string());
 }
 
-void MethodDefinition::WriteToStream(const StringPiece& prefix, bool final,
-                                     std::ostream* out) const {
-  *out << prefix << signature_ << " {\n";
+void MethodDefinition::Print(bool final, Printer* printer) const {
+  printer->Print(signature_).Println(" {");
+  printer->Indent();
   for (const auto& statement : statements_) {
-    *out << prefix << "  " << statement << "\n";
+    printer->Println(statement);
   }
-  *out << prefix << "}";
+  printer->Undent();
+  printer->Print("}");
 }
 
 ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
@@ -62,34 +64,32 @@
   return true;
 }
 
-void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
-                                    std::ostream* out) const {
+void ClassDefinition::Print(bool final, Printer* printer) const {
   if (empty() && !create_if_empty_) {
     return;
   }
 
-  ClassMember::WriteToStream(prefix, final, out);
+  ClassMember::Print(final, printer);
 
-  *out << prefix << "public ";
+  printer->Print("public ");
   if (qualifier_ == ClassQualifier::kStatic) {
-    *out << "static ";
+    printer->Print("static ");
   }
-  *out << "final class " << name_ << " {\n";
-
-  std::string new_prefix = prefix.to_string();
-  new_prefix.append(kIndent);
+  printer->Print("final class ").Print(name_).Println(" {");
+  printer->Indent();
 
   for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
     // There can be nullptr members when a member is added to the ClassDefinition
     // and takes precedence over a previous member with the same name. The overridden member is
     // set to nullptr.
     if (member != nullptr) {
-      member->WriteToStream(new_prefix, final, out);
-      *out << "\n";
+      member->Print(final, printer);
+      printer->Println();
     }
   }
 
-  *out << prefix << "}";
+  printer->Undent();
+  printer->Print("}");
 }
 
 constexpr static const char* sWarningHeader =
@@ -100,11 +100,12 @@
     " * should not be modified by hand.\n"
     " */\n\n";
 
-bool ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
-                                    bool final, std::ostream* out) {
-  *out << sWarningHeader << "package " << package << ";\n\n";
-  def->WriteToStream("", final, out);
-  return bool(*out);
+void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
+                                    bool final, io::OutputStream* out) {
+  Printer printer(out);
+  printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
+  printer.Println();
+  def->Print(final, &printer);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 28a3489..fb11266 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -17,7 +17,6 @@
 #ifndef AAPT_JAVA_CLASSDEFINITION_H
 #define AAPT_JAVA_CLASSDEFINITION_H
 
-#include <ostream>
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -27,6 +26,7 @@
 
 #include "Resource.h"
 #include "java/AnnotationProcessor.h"
+#include "text/Printer.h"
 #include "util/Util.h"
 
 namespace aapt {
@@ -47,11 +47,10 @@
 
   virtual const std::string& GetName() const = 0;
 
-  // Writes the class member to the out stream. Subclasses should derive this method
+  // Writes the class member to the Printer. Subclasses should derive this method
   // to write their own data. Call this base method from the subclass to write out
   // this member's comments/annotations.
-  virtual void WriteToStream(const android::StringPiece& prefix, bool final,
-                             std::ostream* out) const;
+  virtual void Print(bool final, text::Printer* printer) const;
 
  private:
   AnnotationProcessor processor_;
@@ -71,11 +70,16 @@
     return name_;
   }
 
-  void WriteToStream(const android::StringPiece& prefix, bool final,
-                     std::ostream* out) const override {
-    ClassMember::WriteToStream(prefix, final, out);
-    *out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
-         << ";";
+  void Print(bool final, text::Printer* printer) const override {
+    using std::to_string;
+
+    ClassMember::Print(final, printer);
+
+    printer->Print("public static ");
+    if (final) {
+      printer->Print("final ");
+    }
+    printer->Print("int ").Print(name_).Print("=").Print(to_string(val_)).Print(";");
   }
 
  private:
@@ -100,12 +104,14 @@
     return name_;
   }
 
-  void WriteToStream(const android::StringPiece& prefix, bool final,
-                     std::ostream* out) const override {
-    ClassMember::WriteToStream(prefix, final, out);
+  void Print(bool final, text::Printer* printer) const override {
+    ClassMember::Print(final, printer);
 
-    *out << prefix << "public static " << (final ? "final " : "") << "String "
-         << name_ << "=\"" << val_ << "\";";
+    printer->Print("public static ");
+    if (final) {
+      printer->Print("final ");
+    }
+    printer->Print("String ").Print(name_).Print("=\"").Print(val_).Print("\";");
   }
 
  private:
@@ -136,25 +142,27 @@
     return name_;
   }
 
-  void WriteToStream(const android::StringPiece& prefix, bool final,
-                     std::ostream* out) const override {
-    ClassMember::WriteToStream(prefix, final, out);
+  void Print(bool final, text::Printer* printer) const override {
+    ClassMember::Print(final, printer);
 
-    *out << prefix << "public static final int[] " << name_ << "={";
+    printer->Print("public static final int[] ").Print(name_).Print("={");
+    printer->Indent();
 
     const auto begin = elements_.begin();
     const auto end = elements_.end();
     for (auto current = begin; current != end; ++current) {
       if (std::distance(begin, current) % kAttribsPerLine == 0) {
-        *out << "\n" << prefix << kIndent << kIndent;
+        printer->Println();
       }
 
-      *out << *current;
+      printer->Print(to_string(*current));
       if (std::distance(current, end) > 1) {
-        *out << ", ";
+        printer->Print(", ");
       }
     }
-    *out << "\n" << prefix << kIndent << "};";
+    printer->Println();
+    printer->Undent();
+    printer->Print("};");
   }
 
  private:
@@ -187,8 +195,7 @@
     return false;
   }
 
-  void WriteToStream(const android::StringPiece& prefix, bool final,
-                     std::ostream* out) const override;
+  void Print(bool final, text::Printer* printer) const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
@@ -201,8 +208,8 @@
 
 class ClassDefinition : public ClassMember {
  public:
-  static bool WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
-                            bool final, std::ostream* out);
+  static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
+                            bool final, io::OutputStream* out);
 
   ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
       : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
@@ -220,8 +227,7 @@
     return name_;
   }
 
-  void WriteToStream(const android::StringPiece& prefix, bool final,
-                     std::ostream* out) const override;
+  void Print(bool final, text::Printer* printer) const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 91cef64..9861770 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -37,8 +37,10 @@
 #include "java/ClassDefinition.h"
 #include "process/SymbolTable.h"
 
-using android::StringPiece;
-using android::base::StringPrintf;
+using ::aapt::io::OutputStream;
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
 
 namespace aapt {
 
@@ -230,7 +232,7 @@
                                           const StringPiece& package_name_to_generate,
                                           ClassDefinition* out_class_def,
                                           MethodDefinition* out_rewrite_method,
-                                          std::ostream* out_r_txt) {
+                                          Printer* r_txt_printer) {
   const std::string array_field_name = TransformToFieldName(name.entry);
   std::unique_ptr<ResourceArrayMember> array_def =
       util::make_unique<ResourceArrayMember>(array_field_name);
@@ -323,8 +325,8 @@
     array_def->GetCommentBuilder()->AppendComment(styleable_comment.str());
   }
 
-  if (out_r_txt != nullptr) {
-    *out_r_txt << "int[] styleable " << array_field_name << " {";
+  if (r_txt_printer != nullptr) {
+    r_txt_printer->Print("int[] styleable ").Print(array_field_name).Print(" {");
   }
 
   // Add the ResourceIds to the array member.
@@ -332,16 +334,16 @@
     const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
     array_def->AddElement(id);
 
-    if (out_r_txt != nullptr) {
+    if (r_txt_printer != nullptr) {
       if (i != 0) {
-        *out_r_txt << ",";
+        r_txt_printer->Print(",");
       }
-      *out_r_txt << " " << id;
+      r_txt_printer->Print(" ").Print(id.to_string());
     }
   }
 
-  if (out_r_txt != nullptr) {
-    *out_r_txt << " }\n";
+  if (r_txt_printer != nullptr) {
+    r_txt_printer->Println(" }");
   }
 
   // Add the Styleable array to the Styleable class.
@@ -396,9 +398,9 @@
     attr_processor->AppendComment(
         StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
 
-    if (out_r_txt != nullptr) {
-      *out_r_txt << StringPrintf("int styleable %s %d\n", sorted_attributes[i].field_name.data(),
-                                 (int)i);
+    if (r_txt_printer != nullptr) {
+      r_txt_printer->Println(
+          StringPrintf("int styleable %s %zd", sorted_attributes[i].field_name.c_str(), i));
     }
 
     out_class_def->AddMember(std::move(index_member));
@@ -422,10 +424,12 @@
 void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
                                          const ResourceEntry& entry, ClassDefinition* out_class_def,
                                          MethodDefinition* out_rewrite_method,
-                                         std::ostream* out_r_txt) {
+                                         text::Printer* r_txt_printer) {
   ResourceId real_id = id;
   if (context_->GetMinSdkVersion() < SDK_O && name.type == ResourceType::kId &&
       id.package_id() > kAppPackageId) {
+    // Workaround for feature splits using package IDs > 0x7F.
+    // See b/37498913.
     real_id = ResourceId(kAppPackageId, id.package_id(), id.entry_id());
   }
 
@@ -456,8 +460,13 @@
 
   out_class_def->AddMember(std::move(resource_member));
 
-  if (out_r_txt != nullptr) {
-    *out_r_txt << "int " << name.type << " " << field_name << " " << real_id << "\n";
+  if (r_txt_printer != nullptr) {
+    r_txt_printer->Print("int ")
+        .Print(to_string(name.type))
+        .Print(" ")
+        .Print(field_name)
+        .Print(" ")
+        .Println(real_id.to_string());
   }
 
   if (out_rewrite_method != nullptr) {
@@ -497,7 +506,7 @@
                                      const ResourceTableType& type,
                                      ClassDefinition* out_type_class_def,
                                      MethodDefinition* out_rewrite_method_def,
-                                     std::ostream* out_r_txt) {
+                                     Printer* r_txt_printer) {
   for (const auto& entry : type.entries) {
     const Maybe<std::string> unmangled_name =
         UnmangleResource(package.name, package_name_to_generate, *entry);
@@ -532,18 +541,18 @@
           static_cast<const Styleable*>(entry->values.front()->value.get());
 
       ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
-                       out_rewrite_method_def, out_r_txt);
+                       out_rewrite_method_def, r_txt_printer);
     } else {
       ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
-                      out_r_txt);
+                      r_txt_printer);
     }
   }
   return true;
 }
 
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, std::ostream* out,
-                                  std::ostream* out_r_txt) {
-  return Generate(package_name_to_generate, package_name_to_generate, out);
+bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out,
+                                  OutputStream* out_r_txt) {
+  return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt);
 }
 
 static void AppendJavaDocAnnotations(const std::vector<std::string>& annotations,
@@ -556,11 +565,16 @@
 }
 
 bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
-                                  const StringPiece& out_package_name, std::ostream* out,
-                                  std::ostream* out_r_txt) {
+                                  const StringPiece& out_package_name, OutputStream* out,
+                                  OutputStream* out_r_txt) {
   ClassDefinition r_class("R", ClassQualifier::kNone, true);
   std::unique_ptr<MethodDefinition> rewrite_method;
 
+  std::unique_ptr<Printer> r_txt_printer;
+  if (out_r_txt != nullptr) {
+    r_txt_printer = util::make_unique<Printer>(out_r_txt);
+  }
+
   // Generate an onResourcesLoaded() callback if requested.
   if (options_.rewrite_callback_options) {
     rewrite_method =
@@ -586,7 +600,7 @@
       std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
           to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
       if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
-                       rewrite_method.get(), out_r_txt)) {
+                       rewrite_method.get(), r_txt_printer.get())) {
         return false;
       }
 
@@ -595,7 +609,7 @@
         const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
         if (priv_type) {
           if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
-                           rewrite_method.get(), out_r_txt)) {
+                           rewrite_method.get(), r_txt_printer.get())) {
             return false;
           }
         }
@@ -619,22 +633,7 @@
   }
 
   AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder());
-
-  if (!ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out)) {
-    return false;
-  }
-
-  out->flush();
-
-  if (out_r_txt != nullptr) {
-    out_r_txt->flush();
-
-    if (!*out_r_txt) {
-      error_ = android::base::SystemErrorCodeToString(errno);
-      return false;
-    }
-  }
-
+  ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out);
   return true;
 }
 
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 2541749..4992f07 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -17,16 +17,16 @@
 #ifndef AAPT_JAVA_CLASS_GENERATOR_H
 #define AAPT_JAVA_CLASS_GENERATOR_H
 
-#include <ostream>
 #include <string>
 
 #include "androidfw/StringPiece.h"
 
 #include "ResourceTable.h"
 #include "ResourceValues.h"
-#include "androidfw/StringPiece.h"
+#include "io/Io.h"
 #include "process/IResourceTableConsumer.h"
 #include "process/SymbolTable.h"
+#include "text/Printer.h"
 
 namespace aapt {
 
@@ -70,14 +70,14 @@
   // All symbols technically belong to a single package, but linked libraries will
   // have their names mangled, denoting that they came from a different package.
   // We need to generate these symbols in a separate file. Returns true on success.
-  bool Generate(const android::StringPiece& package_name_to_generate, std::ostream* out,
-                std::ostream* out_r_txt = nullptr);
+  bool Generate(const android::StringPiece& package_name_to_generate, io::OutputStream* out,
+                io::OutputStream* out_r_txt = nullptr);
 
   bool Generate(const android::StringPiece& package_name_to_generate,
-                const android::StringPiece& output_package_name, std::ostream* out,
-                std::ostream* out_r_txt = nullptr);
+                const android::StringPiece& output_package_name, io::OutputStream* out,
+                io::OutputStream* out_r_txt = nullptr);
 
-  const std::string& getError() const;
+  const std::string& GetError() const;
 
   static std::string TransformToFieldName(const android::StringPiece& symbol);
 
@@ -94,13 +94,13 @@
   bool ProcessType(const android::StringPiece& package_name_to_generate,
                    const ResourceTablePackage& package, const ResourceTableType& type,
                    ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
-                   std::ostream* out_r_txt);
+                   text::Printer* r_txt_printer);
 
   // Writes a resource to the R.java file, optionally writing out a rewrite rule for its package
   // ID if `out_rewrite_method` is not nullptr.
   void ProcessResource(const ResourceNameRef& name, const ResourceId& id,
                        const ResourceEntry& entry, ClassDefinition* out_class_def,
-                       MethodDefinition* out_rewrite_method, std::ostream* out_r_txt);
+                       MethodDefinition* out_rewrite_method, text::Printer* r_txt_printer);
 
   // Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
   // its package ID if `out_rewrite_method` is not nullptr.
@@ -109,7 +109,7 @@
                         const Styleable& styleable,
                         const android::StringPiece& package_name_to_generate,
                         ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
-                        std::ostream* out_r_txt);
+                        text::Printer* r_txt_printer);
 
   IAaptContext* context_;
   ResourceTable* table_;
@@ -117,7 +117,7 @@
   std::string error_;
 };
 
-inline const std::string& JavaClassGenerator::getError() const {
+inline const std::string& JavaClassGenerator::GetError() const {
   return error_;
 }
 
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 668e434..02f4cb1 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -16,12 +16,13 @@
 
 #include "java/JavaClassGenerator.h"
 
-#include <sstream>
 #include <string>
 
+#include "io/StringStream.h"
 #include "test/Test.h"
 #include "util/Util.h"
 
+using ::aapt::io::StringOutputStream;
 using ::android::StringPiece;
 using ::testing::HasSubstr;
 using ::testing::Lt;
@@ -45,7 +46,8 @@
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
 
-  std::stringstream out;
+  std::string result;
+  StringOutputStream out(&result);
   EXPECT_FALSE(generator.Generate("android", &out));
 }
 
@@ -69,10 +71,10 @@
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
 
-  std::stringstream out;
+  std::string output;
+  StringOutputStream out(&output);
   EXPECT_TRUE(generator.Generate("android", &out));
-
-  std::string output = out.str();
+  out.Flush();
 
   EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;"));
   EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={"));
@@ -93,10 +95,12 @@
           .SetNameManglerPolicy(NameManglerPolicy{"android"})
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
-  std::stringstream out;
-  ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
 
-  std::string output = out.str();
+  std::string output;
+  StringOutputStream out(&output);
+  ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
+  out.Flush();
+
   EXPECT_THAT(output, HasSubstr("package com.android.internal;"));
   EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
   EXPECT_THAT(output, Not(HasSubstr("two")));
@@ -117,10 +121,12 @@
           .SetNameManglerPolicy(NameManglerPolicy{"android"})
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
-  std::stringstream out;
-  ASSERT_TRUE(generator.Generate("android", &out));
 
-  std::string output = out.str();
+  std::string output;
+  StringOutputStream out(&output);
+  ASSERT_TRUE(generator.Generate("android", &out));
+  out.Flush();
+
   EXPECT_THAT(output, HasSubstr("public static final class attr"));
   EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private")));
 }
@@ -147,9 +153,11 @@
   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
   {
     JavaClassGenerator generator(context.get(), table.get(), options);
-    std::stringstream out;
+    std::string output;
+    StringOutputStream out(&output);
     ASSERT_TRUE(generator.Generate("android", &out));
-    std::string output = out.str();
+    out.Flush();
+
     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
     EXPECT_THAT(output, Not(HasSubstr("two")));
     EXPECT_THAT(output, Not(HasSubstr("three")));
@@ -158,9 +166,11 @@
   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
   {
     JavaClassGenerator generator(context.get(), table.get(), options);
-    std::stringstream out;
+    std::string output;
+    StringOutputStream out(&output);
     ASSERT_TRUE(generator.Generate("android", &out));
-    std::string output = out.str();
+    out.Flush();
+
     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
     EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
     EXPECT_THAT(output, Not(HasSubstr("three")));
@@ -169,9 +179,11 @@
   options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
   {
     JavaClassGenerator generator(context.get(), table.get(), options);
-    std::stringstream out;
+    std::string output;
+    StringOutputStream out(&output);
     ASSERT_TRUE(generator.Generate("android", &out));
-    std::string output = out.str();
+    out.Flush();
+
     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
     EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
     EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;"));
@@ -235,10 +247,11 @@
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
 
-  std::stringstream out;
+  std::string output;
+  StringOutputStream out(&output);
   EXPECT_TRUE(generator.Generate("android", &out));
+  out.Flush();
 
-  std::string output = out.str();
   EXPECT_THAT(output, HasSubstr("int foo_bar="));
   EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar="));
 }
@@ -258,9 +271,11 @@
           .SetNameManglerPolicy(NameManglerPolicy{"android"})
           .Build();
   JavaClassGenerator generator(context.get(), table.get(), {});
-  std::stringstream out;
+
+  std::string output;
+  StringOutputStream out(&output);
   ASSERT_TRUE(generator.Generate("android", &out));
-  std::string output = out.str();
+  out.Flush();
 
   const char* expected_text =
       R"EOF(/**
@@ -298,9 +313,11 @@
   JavaClassGeneratorOptions options;
   options.use_final = false;
   JavaClassGenerator generator(context.get(), table.get(), options);
-  std::stringstream out;
+
+  std::string output;
+  StringOutputStream out(&output);
   ASSERT_TRUE(generator.Generate("android", &out));
-  std::string output = out.str();
+  out.Flush();
 
   EXPECT_THAT(output, HasSubstr("attr name android:one"));
   EXPECT_THAT(output, HasSubstr("attr description"));
@@ -332,9 +349,11 @@
 
   JavaClassGeneratorOptions options;
   JavaClassGenerator generator(context.get(), table.get(), {});
-  std::stringstream out;
+
+  std::string output;
+  StringOutputStream out(&output);
   ASSERT_TRUE(generator.Generate("android", &out));
-  std::string output = out.str();
+  out.Flush();
 
   std::string::size_type actionbar_pos = output.find("int[] ActionBar");
   ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
@@ -373,9 +392,11 @@
   JavaClassGeneratorOptions options;
   options.use_final = false;
   JavaClassGenerator generator(context.get(), table.get(), options);
-  std::stringstream out;
+
+  std::string output;
+  StringOutputStream out(&output);
   ASSERT_TRUE(generator.Generate("android", &out));
-  std::string output = out.str();
+  out.Flush();
 
   EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
   EXPECT_THAT(output, Not(HasSubstr("@attr description")));
@@ -409,10 +430,10 @@
   options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
   JavaClassGenerator generator(context.get(), table.get(), options);
 
-  std::stringstream out;
+  std::string output;
+  StringOutputStream out(&output);
   ASSERT_TRUE(generator.Generate("android", &out));
-
-  std::string output = out.str();
+  out.Flush();
 
   EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
   EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));
diff --git a/tools/aapt2/java/ManifestClassGenerator.h b/tools/aapt2/java/ManifestClassGenerator.h
index b12202a..3f6645f 100644
--- a/tools/aapt2/java/ManifestClassGenerator.h
+++ b/tools/aapt2/java/ManifestClassGenerator.h
@@ -23,8 +23,7 @@
 
 namespace aapt {
 
-std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag,
-                                                       xml::XmlResource* res);
+std::unique_ptr<ClassDefinition> GenerateManifestClass(IDiagnostics* diag, xml::XmlResource* res);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/java/ManifestClassGenerator_test.cpp b/tools/aapt2/java/ManifestClassGenerator_test.cpp
index ada5634..c324238 100644
--- a/tools/aapt2/java/ManifestClassGenerator_test.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator_test.cpp
@@ -16,8 +16,10 @@
 
 #include "java/ManifestClassGenerator.h"
 
+#include "io/StringStream.h"
 #include "test/Test.h"
 
+using ::aapt::io::StringOutputStream;
 using ::testing::HasSubstr;
 using ::testing::Not;
 
@@ -144,12 +146,9 @@
     return ::testing::AssertionFailure() << "manifest_class == nullptr";
   }
 
-  std::stringstream out;
-  if (!manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out)) {
-    return ::testing::AssertionFailure() << "failed to write java file";
-  }
-
-  *out_str = out.str();
+  StringOutputStream out(out_str);
+  manifest_class->WriteJavaFile(manifest_class.get(), "android", true, &out);
+  out.Flush();
   return ::testing::AssertionSuccess();
 }
 
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index b214d21..132b234 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -20,14 +20,18 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "JavaClassGenerator.h"
 #include "ResourceUtils.h"
 #include "ValueVisitor.h"
-#include "androidfw/StringPiece.h"
+#include "text/Printer.h"
 #include "util/Util.h"
 #include "xml/XmlDom.h"
 
+using ::aapt::io::OutputStream;
+using ::aapt::text::Printer;
+
 namespace aapt {
 namespace proguard {
 
@@ -326,12 +330,13 @@
   return true;
 }
 
-bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
+void WriteKeepSet(const KeepSet& keep_set, OutputStream* out) {
+  Printer printer(out);
   for (const auto& entry : keep_set.manifest_class_set_) {
     for (const UsageLocation& location : entry.second) {
-      *out << "# Referenced at " << location.source << "\n";
+      printer.Print("# Referenced at ").Println(location.source.to_string());
     }
-    *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
+    printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
   }
 
   for (const auto& entry : keep_set.conditional_class_set_) {
@@ -342,26 +347,31 @@
     }
 
     for (const UsageLocation& location : entry.second) {
-      *out << "# Referenced at " << location.source << "\n";
+      printer.Print("# Referenced at ").Println(location.source.to_string());
     }
     if (keep_set.conditional_keep_rules_ && can_be_conditional) {
-      *out << "-if class **.R$layout {\n";
+      printer.Println("-if class **.R$layout {");
+      printer.Indent();
       for (const UsageLocation& location : locations) {
-        auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry);
-        *out << "  int " << transformed_name << ";\n";
+        printer.Print("int ")
+            .Print(JavaClassGenerator::TransformToFieldName(location.name.entry))
+            .Println(";");
       }
-      *out << "}\n";
+      printer.Undent();
+      printer.Println("}");
+      printer.Println();
     }
-    *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
+    printer.Print("-keep class ").Print(entry.first).Println(" { <init>(...); }");
+    printer.Println();
   }
 
   for (const auto& entry : keep_set.method_set_) {
     for (const UsageLocation& location : entry.second) {
-      *out << "# Referenced at " << location.source << "\n";
+      printer.Print("# Referenced at ").Println(location.source.to_string());
     }
-    *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
+    printer.Print("-keepclassmembers class * { *** ").Print(entry.first).Println("(...); }");
+    printer.Println();
   }
-  return true;
 }
 
 bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index 8dbe3c2..46827ee 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -22,11 +22,13 @@
 #include <set>
 #include <string>
 
+#include "androidfw/StringPiece.h"
+
 #include "Resource.h"
 #include "ResourceTable.h"
 #include "Source.h"
 #include "ValueVisitor.h"
-#include "androidfw/StringPiece.h"
+#include "io/Io.h"
 #include "process/IResourceTableConsumer.h"
 #include "xml/XmlDom.h"
 
@@ -62,7 +64,7 @@
   }
 
  private:
-  friend bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
+  friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
 
   friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
                                std::set<UsageLocation>* locations);
@@ -76,11 +78,12 @@
 
 bool CollectProguardRulesForManifest(xml::XmlResource* res, KeepSet* keep_set,
                                      bool main_dex_only = false);
-bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
-bool CollectResourceReferences(aapt::IAaptContext* context, ResourceTable* table,
-                               KeepSet* keep_set);
 
-bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set);
+bool CollectProguardRules(xml::XmlResource* res, KeepSet* keep_set);
+
+bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
+
+void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out);
 
 bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
                       std::set<UsageLocation>* locations);
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index 802c56a..37d1a5f 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -17,13 +17,23 @@
 #include "java/ProguardRules.h"
 #include "link/Linkers.h"
 
+#include "io/StringStream.h"
 #include "test/Test.h"
 
+using ::aapt::io::StringOutputStream;
 using ::testing::HasSubstr;
 using ::testing::Not;
 
 namespace aapt {
 
+std::string GetKeepSetString(const proguard::KeepSet& set) {
+  std::string out;
+  StringOutputStream sout(&out);
+  proguard::WriteKeepSet(set, &sout);
+  sout.Flush();
+  return out;
+}
+
 TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
@@ -34,10 +44,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
 }
 
@@ -50,10 +58,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
 }
 
@@ -68,10 +74,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
 }
@@ -87,10 +91,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
 }
 
@@ -126,11 +128,10 @@
   ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set));
   ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
+  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
   EXPECT_THAT(actual, HasSubstr("int foo"));
   EXPECT_THAT(actual, HasSubstr("int bar"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -148,10 +149,9 @@
   set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
+  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
   EXPECT_THAT(actual, HasSubstr("int foo"));
   EXPECT_THAT(actual, HasSubstr("int bar"));
@@ -170,11 +170,10 @@
   set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, Not(HasSubstr("-if")));
+  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
 }
 
 TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
@@ -187,10 +186,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("bar_method"));
 }
 
@@ -208,10 +205,8 @@
   proguard::KeepSet set;
   ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set));
 
-  std::stringstream out;
-  ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
+  std::string actual = GetKeepSetString(set);
 
-  std::string actual = out.str();
   EXPECT_THAT(actual, HasSubstr("on_click"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
   EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
index 38b3585..243800c 100644
--- a/tools/aapt2/text/Printer.cpp
+++ b/tools/aapt2/text/Printer.cpp
@@ -26,18 +26,18 @@
 namespace aapt {
 namespace text {
 
-void Printer::Println(const StringPiece& str) {
+Printer& Printer::Println(const StringPiece& str) {
   Print(str);
-  Print("\n");
+  return Print("\n");
 }
 
-void Printer::Println() {
-  Print("\n");
+Printer& Printer::Println() {
+  return Print("\n");
 }
 
-void Printer::Print(const StringPiece& str) {
+Printer& Printer::Print(const StringPiece& str) {
   if (error_) {
-    return;
+    return *this;
   }
 
   auto remaining_str_begin = str.begin();
@@ -53,7 +53,7 @@
         for (int i = 0; i < indent_level_; i++) {
           if (!io::Copy(out_, "  ")) {
             error_ = true;
-            return;
+            return *this;
           }
         }
         needs_indent_ = false;
@@ -61,7 +61,7 @@
 
       if (!io::Copy(out_, str_to_copy)) {
         error_ = true;
-        return;
+        return *this;
       }
     }
 
@@ -69,7 +69,7 @@
     if (new_line_iter != remaining_str_end) {
       if (!io::Copy(out_, "\n")) {
         error_ = true;
-        return;
+        return *this;
       }
       needs_indent_ = true;
       // Ok to increment iterator here because we know that the '\n' character is one byte.
@@ -78,6 +78,7 @@
       remaining_str_begin = new_line_iter;
     }
   }
+  return *this;
 }
 
 void Printer::Indent() {
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
index 94b3c0b..f399f8e 100644
--- a/tools/aapt2/text/Printer.h
+++ b/tools/aapt2/text/Printer.h
@@ -31,9 +31,9 @@
   explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
   }
 
-  void Print(const ::android::StringPiece& str);
-  void Println(const ::android::StringPiece& str);
-  void Println();
+  Printer& Print(const ::android::StringPiece& str);
+  Printer& Println(const ::android::StringPiece& str);
+  Printer& Println();
 
   void Indent();
   void Undent();
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index a910c62..468864b 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -23,6 +23,10 @@
         "Collation.cpp",
         "main.cpp",
     ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 
     shared_libs: [
         "libstats_proto_host",
@@ -90,6 +94,10 @@
     name: "libstatslog",
     generated_sources: ["statslog.cpp"],
     generated_headers: ["statslog.h"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     export_generated_headers: ["statslog.h"],
     shared_libs: [
         "liblog",
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index eb29150..cca1294 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -96,8 +96,6 @@
 static int
 write_stats_log_cpp(FILE* out, const Atoms& atoms)
 {
-    int errorCount;
-
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -109,6 +107,8 @@
 
     fprintf(out, "namespace android {\n");
     fprintf(out, "namespace util {\n");
+    fprintf(out, "// the single event tag id for all stats logs\n");
+    fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
 
     // Print write methods
     fprintf(out, "\n");
@@ -117,7 +117,7 @@
         int argIndex;
 
         fprintf(out, "void\n");
-        fprintf(out, "stats_write(int code");
+        fprintf(out, "stats_write(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
@@ -128,7 +128,8 @@
 
         fprintf(out, "{\n");
         argIndex = 1;
-        fprintf(out, "    android_log_event_list event(code);\n");
+        fprintf(out, "    android_log_event_list event(kStatsEventTag);\n");
+        fprintf(out, "    event << code;\n");
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_STRING) {
@@ -157,8 +158,6 @@
 static int
 write_stats_log_header(FILE* out, const Atoms& atoms)
 {
-    int errorCount;
-
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -208,8 +207,7 @@
     fprintf(out, "//\n");
     for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
             signature != atoms.signatures.end(); signature++) {
-
-        fprintf(out, "void stats_write(int code");
+        fprintf(out, "void stats_write(int32_t code ");
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
@@ -229,8 +227,6 @@
 static int
 write_stats_log_java(FILE* out, const Atoms& atoms)
 {
-    int errorCount;
-
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -395,8 +391,6 @@
 static int
 write_stats_log_jni(FILE* out, const Atoms& atoms)
 {
-    int errorCount;
-
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 26a2bdd..c2f11d9 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -102,7 +102,7 @@
 
     int getWifiEnabledState();
 
-    void setCountryCode(String country, boolean persist);
+    void setCountryCode(String country);
 
     String getCountryCode();
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 68e6203..66fabf3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -1748,13 +1749,12 @@
     /**
      * Set the country code.
      * @param countryCode country code in ISO 3166 format.
-     * @param persist {@code true} if this needs to be remembered
      *
      * @hide
      */
-    public void setCountryCode(String country, boolean persist) {
+    public void setCountryCode(@NonNull String country) {
         try {
-            mService.setCountryCode(country, persist);
+            mService.setCountryCode(country);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 128d6c9..735e872 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -44,7 +44,7 @@
 @SystemService(Context.WIFI_RTT2_SERVICE)
 public class WifiRttManager {
     private static final String TAG = "WifiRttManager";
-    private static final boolean VDBG = true;
+    private static final boolean VDBG = false;
 
     private final Context mContext;
     private final IWifiRttManager mService;
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 1364224..3cad590 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -59,6 +59,7 @@
     private static final int ERROR_NOT_SET = -1;
     private static final int ERROR_TEST_REASON = 5;
     private static final String TEST_PACKAGE_NAME = "TestPackage";
+    private static final String TEST_COUNTRY_CODE = "US";
 
     @Mock Context mContext;
     @Mock IWifiManager mWifiService;
@@ -777,4 +778,23 @@
         mWifiManager.unregisterLocalOnlyHotspotObserver();
         verify(mWifiService).stopWatchLocalOnlyHotspot();
     }
+
+    /**
+     * Verify that calls WifiServiceImpl to set country code when no exception happens.
+     */
+    @Test
+    public void testSetWifiCountryCode() throws Exception {
+        mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
+        verify(mWifiService).setCountryCode(TEST_COUNTRY_CODE);
+    }
+
+    /**
+     * Verify that WifiManager.setCountryCode() rethrows exceptions if caller does not
+     * have necessary permissions.
+     */
+    @Test(expected = SecurityException.class)
+    public void testSetWifiCountryCodeFailedOnSecurityException() throws Exception {
+        doThrow(new SecurityException()).when(mWifiService).setCountryCode(anyString());
+        mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
+    }
 }