Merge "Update Hvac to remove the self register or ui components with their controller"
diff --git a/api/current.txt b/api/current.txt
index 897a8d9..c38d837 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -47620,6 +47620,7 @@
     method public void forceLayout();
     method public static int generateViewId();
     method public java.lang.CharSequence getAccessibilityClassName();
+    method public android.view.View.AccessibilityDelegate getAccessibilityDelegate();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public java.lang.CharSequence getAccessibilityPaneTitle();
diff --git a/api/system-current.txt b/api/system-current.txt
index 6a00815..cb7f7bb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6042,12 +6042,16 @@
     ctor public ImsSsInfo(int, java.lang.String);
     method public int describeContents();
     method public java.lang.String getIcbNum();
+    method public int getProvisionStatus();
     method public int getStatus();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsInfo> CREATOR;
     field public static final int DISABLED = 0; // 0x0
     field public static final int ENABLED = 1; // 0x1
     field public static final int NOT_REGISTERED = -1; // 0xffffffff
+    field public static final int SERVICE_NOT_PROVISIONED = 0; // 0x0
+    field public static final int SERVICE_PROVISIONED = 1; // 0x1
+    field public static final int SERVICE_PROVISIONING_UNKNOWN = -1; // 0xffffffff
   }
 
   public final class ImsStreamMediaProfile implements android.os.Parcelable {
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 5cc4fc4..b3e287b 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -42,7 +42,6 @@
 namespace uhid {
 
 static const char* UHID_PATH = "/dev/uhid";
-static const size_t UHID_MAX_NAME_LENGTH = 128;
 
 static struct {
     jmethodID onDeviceOpen;
@@ -90,8 +89,13 @@
 }
 
 Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
-        std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
-        std::unique_ptr<DeviceCallback> callback) {
+        std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) {
+
+    size_t size = descriptor.size();
+    if (size > HID_MAX_DESCRIPTOR_SIZE) {
+        LOGE("Received invalid hid report with descriptor size %zu, skipping", size);
+        return nullptr;
+    }
 
     int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
     if (fd < 0) {
@@ -102,10 +106,10 @@
     struct uhid_event ev;
     memset(&ev, 0, sizeof(ev));
     ev.type = UHID_CREATE2;
-    strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH);
-    memcpy(&ev.u.create2.rd_data, descriptor.get(),
-            descriptorSize * sizeof(ev.u.create2.rd_data[0]));
-    ev.u.create2.rd_size = descriptorSize;
+    strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
+    memcpy(&ev.u.create2.rd_data, descriptor.data(),
+            size * sizeof(ev.u.create2.rd_data[0]));
+    ev.u.create2.rd_size = size;
     ev.u.create2.bus = BUS_BLUETOOTH;
     ev.u.create2.vendor = vid;
     ev.u.create2.product = pid;
@@ -156,12 +160,17 @@
     mFd = -1;
 }
 
-void Device::sendReport(uint8_t* report, size_t reportSize) {
+void Device::sendReport(const std::vector<uint8_t>& report) const {
+    if (report.size() > UHID_DATA_MAX) {
+        LOGE("Received invalid report of size %zu, skipping", report.size());
+        return;
+    }
+
     struct uhid_event ev;
     memset(&ev, 0, sizeof(ev));
     ev.type = UHID_INPUT2;
-    ev.u.input2.size = reportSize;
-    memcpy(&ev.u.input2.data, report, reportSize);
+    ev.u.input2.size = report.size();
+    memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
     ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
     if (ret < 0 || ret != sizeof(ev)) {
         LOGE("Failed to send hid event: %s", strerror(errno));
@@ -191,12 +200,13 @@
 
 } // namespace uhid
 
-std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) {
+std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
     ScopedByteArrayRO scopedArray(env, javaArray);
-    outSize = scopedArray.size();
-    std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]);
-    for (size_t i = 0; i < outSize; i++) {
-        data[i] = static_cast<uint8_t>(scopedArray[i]);
+    size_t size = scopedArray.size();
+    std::vector<uint8_t> data;
+    data.reserve(size);
+    for (size_t i = 0; i < size; i++) {
+        data.push_back(static_cast<uint8_t>(scopedArray[i]));
     }
     return data;
 }
@@ -208,23 +218,20 @@
         return 0;
     }
 
-    size_t size;
-    std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);
+    std::vector<uint8_t> desc = getData(env, rawDescriptor);
 
     std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
 
     uhid::Device* d = uhid::Device::open(
-            id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
-            std::move(desc), size, std::move(cb));
+            id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb));
     return reinterpret_cast<jlong>(d);
 }
 
 static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
-    size_t size;
-    std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
+    std::vector<uint8_t> report = getData(env, rawReport);
     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
     if (d) {
-        d->sendReport(report.get(), size);
+        d->sendReport(report);
     } else {
         LOGE("Could not send report, Device* is null!");
     }
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 149456d..61a1f76 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -15,6 +15,7 @@
  */
 
 #include <memory>
+#include <vector>
 
 #include <jni.h>
 
@@ -38,13 +39,12 @@
 class Device {
 public:
     static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
-            std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
-            std::unique_ptr<DeviceCallback> callback);
+            std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback);
 
     Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
     ~Device();
 
-    void sendReport(uint8_t* report, size_t reportSize);
+    void sendReport(const std::vector<uint8_t>& report) const;
     void close();
 
     int handleEvents(int events);
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 691356b..35e03e4 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -76,9 +76,9 @@
             break;
         }
         case LogicalOperation::NOT:
-            newCondition = (conditionCache[children[0]] == ConditionState::kFalse)
-                                   ? ConditionState::kTrue
-                                   : ConditionState::kFalse;
+            newCondition = children.empty() ? ConditionState::kUnknown :
+                              ((conditionCache[children[0]] == ConditionState::kFalse) ?
+                                  ConditionState::kTrue : ConditionState::kFalse);
             break;
         case LogicalOperation::NAND:
             newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse;
diff --git a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
index 23d6926..6529d65 100644
--- a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
@@ -40,6 +40,7 @@
     EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
               ConditionState::kUnknown);
 }
+
 TEST(ConditionTrackerTest, TestAndCondition) {
     // Set up the matcher
     LogicalOperation operation = LogicalOperation::AND;
@@ -103,6 +104,11 @@
     conditionResults.clear();
     conditionResults.push_back(ConditionState::kFalse);
     EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
+
+    children.clear();
+    conditionResults.clear();
+    EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
+              ConditionState::kUnknown);
 }
 
 TEST(ConditionTrackerTest, TestNandCondition) {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 4f60b0c..bc4ed15 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -964,22 +964,6 @@
 Landroid/app/WallpaperManager;->setBitmap(Landroid/graphics/Bitmap;Landroid/graphics/Rect;ZII)I
 Landroid/app/WallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;I)Z
 Landroid/app/WallpaperManager;->sGlobals:Landroid/app/WallpaperManager$Globals;
-Landroid/appwidget/AppWidgetHost;-><init>(Landroid/content/Context;ILandroid/widget/RemoteViews$OnClickHandler;Landroid/os/Looper;)V
-Landroid/appwidget/AppWidgetHost;->HANDLE_VIEW_DATA_CHANGED:I
-Landroid/appwidget/AppWidgetHost;->mHandler:Landroid/os/Handler;
-Landroid/appwidget/AppWidgetHost;->sService:Lcom/android/internal/appwidget/IAppWidgetService;
-Landroid/appwidget/AppWidgetHostView;->getDefaultPaddingForWidget(Landroid/content/Context;Landroid/content/pm/ApplicationInfo;Landroid/graphics/Rect;)Landroid/graphics/Rect;
-Landroid/appwidget/AppWidgetHostView;->mAppWidgetId:I
-Landroid/appwidget/AppWidgetHostView;->mInfo:Landroid/appwidget/AppWidgetProviderInfo;
-Landroid/appwidget/AppWidgetHostView;->updateAppWidgetSize(Landroid/os/Bundle;IIIIZ)V
-Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;)V
-Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;Landroid/os/Bundle;)V
-Landroid/appwidget/AppWidgetManager;->bindAppWidgetIdIfAllowed(IILandroid/content/ComponentName;Landroid/os/Bundle;)Z
-Landroid/appwidget/AppWidgetManager;->bindRemoteViewsService(Landroid/content/Context;ILandroid/content/Intent;Landroid/app/IServiceConnection;I)Z
-Landroid/appwidget/AppWidgetManager;->getInstalledProviders(I)Ljava/util/List;
-Landroid/appwidget/AppWidgetManager;->getInstalledProvidersForProfile(ILandroid/os/UserHandle;Ljava/lang/String;)Ljava/util/List;
-Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService;
-Landroid/appwidget/AppWidgetProviderInfo;->providerInfo:Landroid/content/pm/ActivityInfo;
 Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
 Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
 Landroid/bluetooth/IBluetooth$Stub;-><init>()V
@@ -1849,18 +1833,6 @@
 Landroid/icu/util/UResourceBundle;->getType()I
 Landroid/icu/util/UResourceBundleIterator;->hasNext()Z
 Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle;
-Landroid/location/Country;-><init>(Ljava/lang/String;I)V
-Landroid/location/Country;->getCountryIso()Ljava/lang/String;
-Landroid/location/Country;->getSource()I
-Landroid/location/CountryDetector;-><init>(Landroid/location/ICountryDetector;)V
-Landroid/location/CountryDetector;->addCountryListener(Landroid/location/CountryListener;Landroid/os/Looper;)V
-Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
-Landroid/location/CountryDetector;->removeCountryListener(Landroid/location/CountryListener;)V
-Landroid/location/CountryListener;->onCountryDetected(Landroid/location/Country;)V
-Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
-Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
-Landroid/location/Geofence;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/location/GpsStatus;->setTimeToFirstFix(I)V
 Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
 Landroid/location/ICountryListener$Stub;-><init>()V
 Landroid/location/IGeocodeProvider$Stub;-><init>()V
@@ -1879,25 +1851,6 @@
 Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
 Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
 Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
-Landroid/location/Location;->mElapsedRealtimeNanos:J
-Landroid/location/Location;->mProvider:Ljava/lang/String;
-Landroid/location/LocationManager;->mService:Landroid/location/ILocationManager;
-Landroid/location/LocationManager;->requestLocationUpdates(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;Landroid/app/PendingIntent;)V
-Landroid/location/LocationManager;->sendNiResponse(II)Z
-Landroid/location/LocationRequest;->checkDisplacement(F)V
-Landroid/location/LocationRequest;->checkInterval(J)V
-Landroid/location/LocationRequest;->checkProvider(Ljava/lang/String;)V
-Landroid/location/LocationRequest;->checkQuality(I)V
-Landroid/location/LocationRequest;->mExpireAt:J
-Landroid/location/LocationRequest;->mExplicitFastestInterval:Z
-Landroid/location/LocationRequest;->mFastestInterval:J
-Landroid/location/LocationRequest;->mHideFromAppOps:Z
-Landroid/location/LocationRequest;->mInterval:J
-Landroid/location/LocationRequest;->mNumUpdates:I
-Landroid/location/LocationRequest;->mProvider:Ljava/lang/String;
-Landroid/location/LocationRequest;->mQuality:I
-Landroid/location/LocationRequest;->mSmallestDisplacement:F
-Landroid/location/LocationRequest;->mWorkSource:Landroid/os/WorkSource;
 Landroid/media/AmrInputStream;-><init>(Ljava/io/InputStream;)V
 Landroid/media/AsyncPlayer;->setUsesWakeLock(Landroid/content/Context;)V
 Landroid/media/AudioAttributes$Builder;->addTag(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder;
@@ -2366,10 +2319,6 @@
 Landroid/media/VolumeShaper$State;->mVolume:F
 Landroid/media/VolumeShaper$State;->mXOffset:F
 Landroid/media/WebVttRenderer;-><init>(Landroid/content/Context;)V
-Landroid/mtp/MtpPropertyList;->append(IIIJ)V
-Landroid/mtp/MtpPropertyList;->append(IILjava/lang/String;)V
-Landroid/mtp/MtpStorage;->getPath()Ljava/lang/String;
-Landroid/mtp/MtpStorage;->getStorageId()I
 Landroid/net/ConnectivityManager;->ACTION_TETHER_STATE_CHANGED:Ljava/lang/String;
 Landroid/net/ConnectivityManager;->EXTRA_ACTIVE_TETHER:Ljava/lang/String;
 Landroid/net/ConnectivityManager;->EXTRA_AVAILABLE_TETHER:Ljava/lang/String;
@@ -2847,13 +2796,6 @@
 Landroid/nfc/INfcAdapterExtras;->open(Ljava/lang/String;Landroid/os/IBinder;)Landroid/os/Bundle;
 Landroid/nfc/INfcAdapterExtras;->setCardEmulationRoute(Ljava/lang/String;I)V
 Landroid/nfc/INfcAdapterExtras;->transceive(Ljava/lang/String;[B)Landroid/os/Bundle;
-Landroid/opengl/EGL14;->eglGetDisplay(J)Landroid/opengl/EGLDisplay;
-Landroid/opengl/GLES20;->glGetActiveAttrib(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V
-Landroid/opengl/GLES20;->glGetActiveUniform(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V
-Landroid/opengl/GLSurfaceView$EglHelper;->mEglContext:Ljavax/microedition/khronos/egl/EGLContext;
-Landroid/opengl/GLSurfaceView$GLThread;->mEglHelper:Landroid/opengl/GLSurfaceView$EglHelper;
-Landroid/opengl/GLSurfaceView;->mGLThread:Landroid/opengl/GLSurfaceView$GLThread;
-Landroid/opengl/GLSurfaceView;->mRenderer:Landroid/opengl/GLSurfaceView$Renderer;
 Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;)Landroid/os/AsyncResult;
 Landroid/os/AsyncTask;->mFuture:Ljava/util/concurrent/FutureTask;
 Landroid/os/AsyncTask;->mStatus:Landroid/os/AsyncTask$Status;
@@ -5233,7 +5175,6 @@
 Landroid/view/View;->findViewByAccessibilityId(I)Landroid/view/View;
 Landroid/view/View;->fitsSystemWindows()Z
 Landroid/view/View;->gatherTransparentRegion(Landroid/graphics/Region;)Z
-Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate;
 Landroid/view/View;->getAccessibilityViewId()I
 Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;)V
 Landroid/view/View;->getBoundsOnScreen(Landroid/graphics/Rect;Z)V
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 4b4250d..2808166 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -55,15 +55,6 @@
 Landroid/app/TaskStackListener;->onTaskStackChanged()V
 Landroid/app/WallpaperColors;-><init>(Landroid/graphics/Color;Landroid/graphics/Color;Landroid/graphics/Color;I)V
 Landroid/bluetooth/IBluetooth;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V
-Landroid/companion/AssociationRequest;->getDeviceFilters()Ljava/util/List;
-Landroid/companion/AssociationRequest;->isSingleDevice()Z
-Landroid/companion/BluetoothDeviceFilter;->getAddress()Ljava/lang/String;
-Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
-Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceDisplayNameInternal(Landroid/net/wifi/ScanResult;)Ljava/lang/String;
-Landroid/companion/BluetoothDeviceFilterUtils;->getDeviceMacAddress(Landroid/os/Parcelable;)Ljava/lang/String;
-Landroid/companion/BluetoothLeDeviceFilter;->getScanFilter()Landroid/bluetooth/le/ScanFilter;
-Landroid/companion/DeviceFilter;->getDeviceDisplayName(Landroid/os/Parcelable;)Ljava/lang/String;
-Landroid/companion/DeviceFilter;->matches(Landroid/os/Parcelable;)Z
 Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
 Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
 Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
@@ -99,7 +90,6 @@
 Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V
 Landroid/location/INetInitiatedListener$Stub;-><init>()V
 Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z
-Landroid/location/Location;->setExtraLocation(Ljava/lang/String;Landroid/location/Location;)V
 Landroid/media/AudioManager;->registerAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V
 Landroid/media/AudioManager;->unregisterAudioPortUpdateListener(Landroid/media/AudioManager$OnAudioPortUpdateListener;)V
 Landroid/media/AudioSystem;->checkAudioFlinger()I
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 49cc498..f003d4b 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -53,14 +54,17 @@
     static final int HANDLE_UPDATE = 1;
     static final int HANDLE_PROVIDER_CHANGED = 2;
     static final int HANDLE_PROVIDERS_CHANGED = 3;
+    @UnsupportedAppUsage
     static final int HANDLE_VIEW_DATA_CHANGED = 4;
 
     final static Object sServiceLock = new Object();
+    @UnsupportedAppUsage
     static IAppWidgetService sService;
     static boolean sServiceInitialized = false;
     private DisplayMetrics mDisplayMetrics;
 
     private String mContextOpPackageName;
+    @UnsupportedAppUsage
     private final Handler mHandler;
     private final int mHostId;
     private final Callbacks mCallbacks;
@@ -156,6 +160,7 @@
     /**
      * @hide
      */
+    @UnsupportedAppUsage
     public AppWidgetHost(Context context, int hostId, OnClickHandler handler, Looper looper) {
         mContextOpPackageName = context.getOpPackageName();
         mHostId = hostId;
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index ab0eb92..a9187b6 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -16,6 +16,7 @@
 
 package android.appwidget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -70,7 +71,9 @@
     Context mContext;
     Context mRemoteContext;
 
+    @UnsupportedAppUsage
     int mAppWidgetId;
+    @UnsupportedAppUsage
     AppWidgetProviderInfo mInfo;
     View mView;
     int mViewMode = VIEW_MODE_NOINIT;
@@ -174,6 +177,7 @@
         return getDefaultPaddingForWidget(context, appInfo, padding);
     }
 
+    @UnsupportedAppUsage
     private static Rect getDefaultPaddingForWidget(Context context, ApplicationInfo appInfo,
             Rect padding) {
         if (padding == null) {
@@ -284,6 +288,7 @@
     /**
      * @hide
      */
+    @UnsupportedAppUsage
     public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
             int maxHeight, boolean ignorePadding) {
         if (newOptions == null) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 20248b9..dbc1c19 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -23,6 +23,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
+import android.annotation.UnsupportedAppUsage;
 import android.app.IServiceConnection;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -463,6 +464,7 @@
 
     private final Context mContext;
     private final String mPackageName;
+    @UnsupportedAppUsage
     private final IAppWidgetService mService;
     private final DisplayMetrics mDisplayMetrics;
 
@@ -816,6 +818,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
         if (mService == null) {
             return Collections.emptyList();
@@ -842,6 +845,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
             @Nullable UserHandle profile, @Nullable String packageName) {
         if (mService == null) {
@@ -902,6 +906,7 @@
      *                      provider for this AppWidget.
      * @hide
      */
+    @UnsupportedAppUsage
     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
         if (mService == null) {
             return;
@@ -924,6 +929,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
         if (mService == null) {
             return;
@@ -1094,6 +1100,7 @@
      * @see Context#getServiceDispatcher(ServiceConnection, Handler, int)
      * @hide
      */
+    @UnsupportedAppUsage
     public boolean bindRemoteViewsService(Context context, int appWidgetId, Intent intent,
             IServiceConnection connection, @Context.BindServiceFlags int flags) {
         if (mService == null) {
@@ -1139,6 +1146,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
             ComponentName provider, Bundle options) {
         if (mService == null) {
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 6dd85ca..53315cc 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -270,6 +271,7 @@
     public int widgetFeatures;
 
     /** @hide */
+    @UnsupportedAppUsage
     public ActivityInfo providerInfo;
 
     public AppWidgetProviderInfo() {
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 922224a..db54f08 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.OneTimeUseBuilder;
@@ -59,12 +60,14 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     public boolean isSingleDevice() {
         return mSingleDevice;
     }
 
     /** @hide */
     @NonNull
+    @UnsupportedAppUsage
     public List<DeviceFilter<?>> getDeviceFilters() {
         return mDeviceFilters;
     }
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index 84e1536..7507e17 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -25,6 +25,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
 import android.os.Parcel;
 import android.os.ParcelUuid;
@@ -99,6 +100,7 @@
 
     /** @hide */
     @Nullable
+    @UnsupportedAppUsage
     public String getAddress() {
         return mAddress;
     }
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 4ee38fe..bd507a6 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.le.ScanFilter;
 import android.net.wifi.ScanResult;
@@ -124,14 +125,17 @@
         Log.i(LOG_TAG, getDeviceDisplayNameInternal(device) + (result ? " ~ " : " !~ ") + criteria);
     }
 
+    @UnsupportedAppUsage
     public static String getDeviceDisplayNameInternal(@NonNull BluetoothDevice device) {
         return firstNotEmpty(device.getAliasName(), device.getAddress());
     }
 
+    @UnsupportedAppUsage
     public static String getDeviceDisplayNameInternal(@NonNull ScanResult device) {
         return firstNotEmpty(device.SSID, device.BSSID);
     }
 
+    @UnsupportedAppUsage
     public static String getDeviceMacAddress(@NonNull Parcelable device) {
         if (device instanceof BluetoothDevice) {
             return ((BluetoothDevice) device).getAddress();
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 7fb768c..1de931e 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -25,6 +25,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanRecord;
@@ -92,6 +93,7 @@
 
     /** @hide */
     @NonNull
+    @UnsupportedAppUsage
     public ScanFilter getScanFilter() {
         return mScanFilter;
     }
diff --git a/core/java/android/companion/DeviceFilter.java b/core/java/android/companion/DeviceFilter.java
index 10135a4..dc7cf82 100644
--- a/core/java/android/companion/DeviceFilter.java
+++ b/core/java/android/companion/DeviceFilter.java
@@ -19,6 +19,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
@@ -44,9 +45,11 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     boolean matches(D device);
 
     /** @hide */
+    @UnsupportedAppUsage
     String getDeviceDisplayName(D device);
 
     /**  @hide */
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index 93fa403..b06dd7a 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -21,9 +21,12 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -55,6 +58,7 @@
      * @param size the initial size of the set of values
      */
     public ContentValues(int size) {
+        Preconditions.checkArgumentNonnegative(size);
         mMap = new ArrayMap<>(size);
     }
 
@@ -64,6 +68,7 @@
      * @param from the values to copy
      */
     public ContentValues(ContentValues from) {
+        Objects.requireNonNull(from);
         mMap = new ArrayMap<>(from.mMap);
     }
 
diff --git a/core/java/android/database/RedactingCursor.java b/core/java/android/database/RedactingCursor.java
new file mode 100644
index 0000000..6322d56
--- /dev/null
+++ b/core/java/android/database/RedactingCursor.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database;
+
+import android.annotation.NonNull;
+import android.util.SparseArray;
+
+import java.util.Map;
+
+/**
+ * Cursor that offers to redact values of requested columns.
+ *
+ * @hide
+ */
+public class RedactingCursor extends CrossProcessCursorWrapper {
+    private final SparseArray<Object> mRedactions;
+
+    private RedactingCursor(@NonNull Cursor cursor, SparseArray<Object> redactions) {
+        super(cursor);
+        mRedactions = redactions;
+    }
+
+    /**
+     * Create a wrapped instance of the given {@link Cursor} which redacts the
+     * requested columns so they always return specific values when accessed.
+     * <p>
+     * If a redacted column appears multiple times in the underlying cursor, all
+     * instances will be redacted. If none of the redacted columns appear in the
+     * given cursor, the given cursor will be returned untouched to improve
+     * performance.
+     */
+    public static Cursor create(@NonNull Cursor cursor, @NonNull Map<String, Object> redactions) {
+        final SparseArray<Object> internalRedactions = new SparseArray<>();
+
+        final String[] columns = cursor.getColumnNames();
+        for (int i = 0; i < columns.length; i++) {
+            if (redactions.containsKey(columns[i])) {
+                internalRedactions.put(i, redactions.get(columns[i]));
+            }
+        }
+
+        if (internalRedactions.size() == 0) {
+            return cursor;
+        } else {
+            return new RedactingCursor(cursor, internalRedactions);
+        }
+    }
+
+    @Override
+    public void fillWindow(int position, CursorWindow window) {
+        // Fill window directly to ensure data is redacted
+        DatabaseUtils.cursorFillWindow(this, position, window);
+    }
+
+    @Override
+    public CursorWindow getWindow() {
+        // Returning underlying window risks leaking redacted data
+        return null;
+    }
+
+    @Override
+    public Cursor getWrappedCursor() {
+        throw new UnsupportedOperationException(
+                "Returning underlying cursor risks leaking redacted data");
+    }
+
+    @Override
+    public double getDouble(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (double) mRedactions.valueAt(i);
+        } else {
+            return super.getDouble(columnIndex);
+        }
+    }
+
+    @Override
+    public float getFloat(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (float) mRedactions.valueAt(i);
+        } else {
+            return super.getFloat(columnIndex);
+        }
+    }
+
+    @Override
+    public int getInt(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (int) mRedactions.valueAt(i);
+        } else {
+            return super.getInt(columnIndex);
+        }
+    }
+
+    @Override
+    public long getLong(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (long) mRedactions.valueAt(i);
+        } else {
+            return super.getLong(columnIndex);
+        }
+    }
+
+    @Override
+    public short getShort(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (short) mRedactions.valueAt(i);
+        } else {
+            return super.getShort(columnIndex);
+        }
+    }
+
+    @Override
+    public String getString(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (String) mRedactions.valueAt(i);
+        } else {
+            return super.getString(columnIndex);
+        }
+    }
+
+    @Override
+    public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            buffer.data = ((String) mRedactions.valueAt(i)).toCharArray();
+            buffer.sizeCopied = buffer.data.length;
+        } else {
+            super.copyStringToBuffer(columnIndex, buffer);
+        }
+    }
+
+    @Override
+    public byte[] getBlob(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return (byte[]) mRedactions.valueAt(i);
+        } else {
+            return super.getBlob(columnIndex);
+        }
+    }
+
+    @Override
+    public int getType(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return DatabaseUtils.getTypeOfObject(mRedactions.valueAt(i));
+        } else {
+            return super.getType(columnIndex);
+        }
+    }
+
+    @Override
+    public boolean isNull(int columnIndex) {
+        final int i = mRedactions.indexOfKey(columnIndex);
+        if (i >= 0) {
+            return mRedactions.valueAt(i) == null;
+        } else {
+            return super.isNull(columnIndex);
+        }
+    }
+}
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index d6d9764..e6b6acf 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -39,11 +39,18 @@
 public final class SQLiteGlobal {
     private static final String TAG = "SQLiteGlobal";
 
+    /** @hide */
+    public static final String SYNC_MODE_FULL = "FULL";
+
     private static final Object sLock = new Object();
+
     private static int sDefaultPageSize;
 
     private static native int nativeReleaseMemory();
 
+    /** @hide */
+    public static volatile String sDefaultSyncMode;
+
     private SQLiteGlobal() {
     }
 
@@ -103,6 +110,11 @@
      * Gets the default database synchronization mode when WAL is not in use.
      */
     public static String getDefaultSyncMode() {
+        // Use the FULL synchronous mode for system processes by default.
+        String defaultMode = sDefaultSyncMode;
+        if (defaultMode != null) {
+            return defaultMode;
+        }
         return SystemProperties.get("debug.sqlite.syncmode",
                 Resources.getSystem().getString(
                 com.android.internal.R.string.db_default_sync_mode));
@@ -112,6 +124,11 @@
      * Gets the database synchronization mode when in WAL mode.
      */
     public static String getWALSyncMode() {
+        // Use the FULL synchronous mode for system processes by default.
+        String defaultMode = sDefaultSyncMode;
+        if (defaultMode != null) {
+            return defaultMode;
+        }
         return SystemProperties.get("debug.sqlite.wal.syncmode",
                 Resources.getSystem().getString(
                 com.android.internal.R.string.db_wal_sync_mode));
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 52a2354..081d8d1 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -372,7 +372,7 @@
         if (score < 0) {
             throw new IllegalArgumentException("Score must be >= 0");
         }
-        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
+        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED,  score, 0);
     }
 
     /**
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 5752b6f..591370f 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -241,6 +241,9 @@
                         } else {
                             try {
                                 key = bp.getInterfaceDescriptor();
+                                if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
+                                    key = "<proxy to dead node>";
+                                }
                             } catch (Throwable t) {
                                 key = "<exception during getDescriptor>";
                             }
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9c3a409..68572dd 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -469,6 +469,12 @@
          * The height of the image/video in pixels.
          */
         public static final String HEIGHT = "height";
+
+        /**
+         * Package that contributed this media.
+         * @hide
+         */
+        public static final String OWNER_PACKAGE_NAME = "owner_package_name";
      }
 
     /**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 131fe13..092702c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -421,8 +421,8 @@
     boolean isWindowTraceEnabled();
 
     /**
-     * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION
-     * on the next user activity.
+     * Requests that the WindowManager sends
+     * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity.
      */
     void requestUserActivityNotification();
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e2e2b00..65ab3ac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9008,8 +9008,6 @@
      * composition. For more details see {@link AccessibilityDelegate}.
      *
      * @return The delegate, or null if none set.
-     *
-     * @hide
      */
     public AccessibilityDelegate getAccessibilityDelegate() {
         return mAccessibilityDelegate;
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 17ab956..e64d2af 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -96,7 +96,7 @@
     return toJavaStringArray(env, cStrings);
 }
 
-static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::DisabledChecks checks) {
+static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckFlags::Type checks) {
     std::vector<std::string> cPackageInfo;
     if (packageInfo) {
         size_t count = env->GetArrayLength(packageInfo);
@@ -116,11 +116,11 @@
 }
 
 static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
-    return verify(env, packageInfo, ::android::vintf::ENABLE_ALL_CHECKS);
+    return verify(env, packageInfo, ::android::vintf::CheckFlags::ENABLE_ALL_CHECKS);
 }
 
 static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) {
-    return verify(env, nullptr, ::android::vintf::DISABLE_AVB_CHECK);
+    return verify(env, nullptr, ::android::vintf::CheckFlags::DISABLE_AVB_CHECK);
 }
 
 static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 48113df..3db7f9d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -265,11 +265,10 @@
     optional int32 stack_id = 4;
     optional .android.view.WindowLayoutParamsProto attributes = 5;
     optional .android.graphics.RectProto given_content_insets = 6;
-    reserved 7 to 10;
-//    optional .android.graphics.RectProto frame = 7;
-//    optional .android.graphics.RectProto containing_frame = 8;
-//    optional .android.graphics.RectProto parent_frame = 9;
-//    optional .android.graphics.RectProto content_frame = 10;
+    optional .android.graphics.RectProto frame = 7 [deprecated=true];
+    optional .android.graphics.RectProto containing_frame = 8 [deprecated=true];
+    optional .android.graphics.RectProto parent_frame = 9 [deprecated=true];
+    optional .android.graphics.RectProto content_frame = 10 [deprecated=true];
     optional .android.graphics.RectProto content_insets = 11;
     optional .android.graphics.RectProto surface_insets = 12;
     optional WindowStateAnimatorProto animator = 13;
@@ -282,18 +281,16 @@
     optional int32 system_ui_visibility = 21;
     optional bool has_surface = 22;
     optional bool is_ready_for_display = 23;
-    reserved 24 to 28;
-//    optional .android.graphics.RectProto display_frame = 24;
-//    optional .android.graphics.RectProto overscan_frame = 25;
-//    optional .android.graphics.RectProto visible_frame = 26;
-//    optional .android.graphics.RectProto decor_frame = 27;
-//    optional .android.graphics.RectProto outset_frame = 28;
+    optional .android.graphics.RectProto display_frame = 24 [deprecated=true];
+    optional .android.graphics.RectProto overscan_frame = 25 [deprecated=true];
+    optional .android.graphics.RectProto visible_frame = 26 [deprecated=true];
+    optional .android.graphics.RectProto decor_frame = 27 [deprecated=true];
+    optional .android.graphics.RectProto outset_frame = 28 [deprecated=true];
     optional .android.graphics.RectProto overscan_insets = 29;
     optional .android.graphics.RectProto visible_insets = 30;
     optional .android.graphics.RectProto stable_insets = 31;
     optional .android.graphics.RectProto outsets = 32;
-    reserved 33;
-//    optional .android.view.DisplayCutoutProto cutout = 33;
+    optional .android.view.DisplayCutoutProto cutout = 33 [deprecated=true];
     optional bool remove_on_exit = 34;
     optional bool destroying = 35;
     optional bool removed = 36;
diff --git a/core/res/res/anim/keyguard_occlude_open_enter.xml b/core/res/res/anim/keyguard_occlude_open_enter.xml
deleted file mode 100644
index e742616..0000000
--- a/core/res/res/anim/keyguard_occlude_open_enter.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shareInterpolator="false">
-    <translate
-        android:fromYDelta="90%"
-        android:toYDelta="0%"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="400"/>
-    <alpha
-        android:fromAlpha="0.0"
-        android:toAlpha="1.0"
-        android:interpolator="@interpolator/fast_out_slow_in"
-        android:duration="300"/>
-</set>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 140bb7d8..2f45cce 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2156,7 +2156,6 @@
   <java-symbol type="anim" name="push_down_out" />
   <java-symbol type="anim" name="push_up_in" />
   <java-symbol type="anim" name="push_up_out" />
-  <java-symbol type="anim" name="keyguard_occlude_open_enter" />
   <java-symbol type="anim" name="lock_screen_behind_enter" />
   <java-symbol type="anim" name="lock_screen_behind_enter_wallpaper" />
   <java-symbol type="anim" name="lock_screen_behind_enter_fade_in" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 2a906ae..d704957 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1301,6 +1301,11 @@
                 android:process=":MemoryFileProvider">
         </provider>
 
+        <provider android:name="android.content.RedactingProvider"
+                android:authorities="android.content.RedactingProvider"
+                android:process=":RedactingProvider">
+        </provider>
+
         <!-- Application components used for os tests -->
 
         <service android:name="android.os.MessengerService"
diff --git a/core/tests/coretests/src/android/content/RedactingProvider.java b/core/tests/coretests/src/android/content/RedactingProvider.java
new file mode 100644
index 0000000..e2ad448
--- /dev/null
+++ b/core/tests/coretests/src/android/content/RedactingProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.RedactingCursor;
+import android.net.Uri;
+import android.util.ArrayMap;
+
+public class RedactingProvider extends ContentProvider {
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        switch (uri.getLastPathSegment()) {
+            case "missing": {
+                final MatrixCursor cursor = new MatrixCursor(
+                        new String[] { "name", "size", "_data" });
+                cursor.addRow(new Object[] { "foo", 10, "/path/to/foo" });
+                cursor.addRow(new Object[] { "bar", 20, "/path/to/bar" });
+
+                final ArrayMap<String, Object> redactions = new ArrayMap<>();
+                redactions.put("missing", null);
+                return RedactingCursor.create(cursor, redactions);
+            }
+            case "single": {
+                final MatrixCursor cursor = new MatrixCursor(
+                        new String[] { "name", "size", "_data" });
+                cursor.addRow(new Object[] { "foo", 10, "/path/to/foo" });
+                cursor.addRow(new Object[] { "bar", 20, "/path/to/bar" });
+
+                final ArrayMap<String, Object> redactions = new ArrayMap<>();
+                redactions.put("name", null);
+                redactions.put("_data", "/dev/null");
+                return RedactingCursor.create(cursor, redactions);
+            }
+            case "multiple": {
+                final MatrixCursor cursor = new MatrixCursor(
+                        new String[] { "_data", "name", "_data" });
+                cursor.addRow(new Object[] { "/path", "foo", "/path" });
+
+                final ArrayMap<String, Object> redactions = new ArrayMap<>();
+                redactions.put("_data", null);
+                return RedactingCursor.create(cursor, redactions);
+            }
+        }
+
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/core/tests/coretests/src/android/database/RedactingCursorTest.java b/core/tests/coretests/src/android/database/RedactingCursorTest.java
new file mode 100644
index 0000000..93998f3
--- /dev/null
+++ b/core/tests/coretests/src/android/database/RedactingCursorTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RedactingCursorTest {
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void testMissing() throws Exception {
+        final Cursor redacting = getContext().getContentResolver().query(
+                Uri.parse("content://android.content.RedactingProvider/missing"), null, null, null);
+
+        redacting.moveToNext();
+        assertEquals("foo", redacting.getString(0));
+        assertEquals(10, redacting.getInt(1));
+        assertEquals("/path/to/foo", redacting.getString(2));
+        redacting.moveToNext();
+        assertEquals("bar", redacting.getString(0));
+        assertEquals(20, redacting.getInt(1));
+        assertEquals("/path/to/bar", redacting.getString(2));
+    }
+
+    @Test
+    public void testSingle() throws Exception {
+        final Cursor redacting = getContext().getContentResolver().query(
+                Uri.parse("content://android.content.RedactingProvider/single"), null, null, null);
+
+        redacting.moveToNext();
+        assertEquals(null, redacting.getString(0));
+        assertEquals(10, redacting.getInt(1));
+        assertEquals("/dev/null", redacting.getString(2));
+        assertEquals(Cursor.FIELD_TYPE_NULL, redacting.getType(0));
+        assertEquals(Cursor.FIELD_TYPE_INTEGER, redacting.getType(1));
+        assertEquals(Cursor.FIELD_TYPE_STRING, redacting.getType(2));
+        assertTrue(redacting.isNull(0));
+        assertFalse(redacting.isNull(1));
+        assertFalse(redacting.isNull(2));
+
+        redacting.moveToNext();
+        assertEquals(null, redacting.getString(0));
+        assertEquals(20, redacting.getInt(1));
+        assertEquals("/dev/null", redacting.getString(2));
+    }
+
+    @Test
+    public void testMultiple() throws Exception {
+        final Cursor redacting = getContext().getContentResolver().query(
+                Uri.parse("content://android.content.RedactingProvider/multiple"),
+                null, null, null);
+
+        redacting.moveToNext();
+        assertEquals(null, redacting.getString(0));
+        assertEquals("foo", redacting.getString(1));
+        assertEquals(null, redacting.getString(2));
+    }
+}
diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java
index 7c1485d..6f82b78 100644
--- a/location/java/android/location/Country.java
+++ b/location/java/android/location/Country.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -78,6 +79,7 @@
      *        <li>{@link #COUNTRY_SOURCE_LOCALE}</li>
      *        </ul>
      */
+    @UnsupportedAppUsage
     public Country(final String countryIso, final int source) {
         if (countryIso == null || source < COUNTRY_SOURCE_NETWORK
                 || source > COUNTRY_SOURCE_LOCALE) {
@@ -107,6 +109,7 @@
     /**
      * @return the ISO 3166-1 two letters country code
      */
+    @UnsupportedAppUsage
     public final String getCountryIso() {
         return mCountryIso;
     }
@@ -121,6 +124,7 @@
      *         <li>{@link #COUNTRY_SOURCE_LOCALE}</li>
      *         </ul>
      */
+    @UnsupportedAppUsage
     public final int getSource() {
         return mSource;
     }
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index ec6dfb7..119d1e0 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -19,6 +19,7 @@
 import java.util.HashMap;
 
 import android.annotation.SystemService;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
@@ -87,6 +88,7 @@
      *       create an instance of this class is using the factory
      *       Context.getSystemService.
      */
+    @UnsupportedAppUsage
     public CountryDetector(ICountryDetector service) {
         mService = service;
         mListeners = new HashMap<CountryListener, ListenerTransport>();
@@ -98,6 +100,7 @@
      * @return the country if it is available immediately, otherwise null will
      *         be returned.
      */
+    @UnsupportedAppUsage
     public Country detectCountry() {
         try {
             return mService.detectCountry();
@@ -116,6 +119,7 @@
      *        implement the callback mechanism. If looper is null then the
      *        callbacks will be called on the main thread.
      */
+    @UnsupportedAppUsage
     public void addCountryListener(CountryListener listener, Looper looper) {
         synchronized (mListeners) {
             if (!mListeners.containsKey(listener)) {
@@ -133,6 +137,7 @@
     /**
      * Remove the listener
      */
+    @UnsupportedAppUsage
     public void removeCountryListener(CountryListener listener) {
         synchronized (mListeners) {
             ListenerTransport transport = mListeners.get(listener);
diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java
index e36db41..70a83c5 100644
--- a/location/java/android/location/CountryListener.java
+++ b/location/java/android/location/CountryListener.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.annotation.UnsupportedAppUsage;
+
 /**
  * The listener for receiving the notification when the country is detected or
  * changed
@@ -26,5 +28,6 @@
     /**
      * @param country the changed or detected country.
      */
+    @UnsupportedAppUsage
     void onCountryDetected(Country country);
 }
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 174fe3e..d90e4b5 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -53,6 +54,7 @@
     /**
      * returns the Geocoder's locale
      */
+    @UnsupportedAppUsage
     public Locale getLocale() {
         return mLocale;
     }
@@ -60,6 +62,7 @@
     /**
      * returns the package name of the Geocoder's client
      */
+    @UnsupportedAppUsage
     public String getClientPackage() {
         return mPackageName;
     }
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index 5de779a..ed2aa64 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -98,6 +99,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() {
         @Override
         public Geofence createFromParcel(Parcel in) {
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index b601cde..d90a597 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.annotation.UnsupportedAppUsage;
 import android.util.SparseArray;
 
 import java.util.Iterator;
@@ -206,6 +207,7 @@
                 status.mAzimuths);
     }
 
+    @UnsupportedAppUsage
     void setTimeToFirstFix(int ttff) {
         mTimeToFirstFix = ttff;
     }
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 684cafa..70a97e1 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -123,8 +124,10 @@
         }
     };
 
+    @UnsupportedAppUsage
     private String mProvider;
     private long mTime = 0;
+    @UnsupportedAppUsage
     private long mElapsedRealtimeNanos = 0;
     private double mLatitude = 0.0;
     private double mLongitude = 0.0;
@@ -1156,6 +1159,7 @@
      * @param value the Location to attach
      * @hide
      */
+    @UnsupportedAppUsage
     public void setExtraLocation(String key, Location value) {
         if (mExtras == null) {
             mExtras = new Bundle();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 30a07ef..b5d9431 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -29,6 +29,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -68,6 +69,7 @@
     private static final String TAG = "LocationManager";
 
     private final Context mContext;
+    @UnsupportedAppUsage
     private final ILocationManager mService;
     private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport;
     private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport;
@@ -1004,6 +1006,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     private void requestLocationUpdates(LocationRequest request, LocationListener listener,
             Looper looper, PendingIntent intent) {
 
@@ -2328,6 +2331,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     public boolean sendNiResponse(int notifId, int userResponse) {
         try {
             return mService.sendNiResponse(notifId, userResponse);
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 96a0817..2d7f7e3 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -17,6 +17,7 @@
 package android.location;
 
 import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -141,16 +142,26 @@
      */
     private static final double FASTEST_INTERVAL_FACTOR = 6.0;  // 6x
 
+    @UnsupportedAppUsage
     private int mQuality = POWER_LOW;
+    @UnsupportedAppUsage
     private long mInterval = 60 * 60 * 1000;   // 60 minutes
+    @UnsupportedAppUsage
     private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);  // 10 minutes
+    @UnsupportedAppUsage
     private boolean mExplicitFastestInterval = false;
+    @UnsupportedAppUsage
     private long mExpireAt = Long.MAX_VALUE;  // no expiry
+    @UnsupportedAppUsage
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
+    @UnsupportedAppUsage
     private float mSmallestDisplacement = 0.0f;    // meters
+    @UnsupportedAppUsage
     private WorkSource mWorkSource = null;
+    @UnsupportedAppUsage
     private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
 
+    @UnsupportedAppUsage
     private String mProvider = LocationManager.FUSED_PROVIDER;
             // for deprecated APIs that explicitly request a provider
 
@@ -592,12 +603,14 @@
         return mHideFromAppOps;
     }
 
+    @UnsupportedAppUsage
     private static void checkInterval(long millis) {
         if (millis < 0) {
             throw new IllegalArgumentException("invalid interval: " + millis);
         }
     }
 
+    @UnsupportedAppUsage
     private static void checkQuality(int quality) {
         switch (quality) {
             case ACCURACY_FINE:
@@ -612,12 +625,14 @@
         }
     }
 
+    @UnsupportedAppUsage
     private static void checkDisplacement(float meters) {
         if (meters < 0.0f) {
             throw new IllegalArgumentException("invalid displacement: " + meters);
         }
     }
 
+    @UnsupportedAppUsage
     private static void checkProvider(String name) {
         if (name == null) {
             throw new IllegalArgumentException("invalid provider: " + name);
diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java
index ede90da..557f099 100644
--- a/media/java/android/mtp/MtpPropertyList.java
+++ b/media/java/android/mtp/MtpPropertyList.java
@@ -16,6 +16,7 @@
 
 package android.mtp;
 
+import android.annotation.UnsupportedAppUsage;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -49,6 +50,7 @@
         mStringValues = new ArrayList<>();
     }
 
+    @UnsupportedAppUsage
     public void append(int handle, int property, int type, long value) {
         mObjectHandles.add(handle);
         mPropertyCodes.add(property);
@@ -57,6 +59,7 @@
         mStringValues.add(null);
     }
 
+    @UnsupportedAppUsage
     public void append(int handle, int property, String value) {
         mObjectHandles.add(handle);
         mPropertyCodes.add(property);
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 2625e0c..c714b3c 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,6 +16,7 @@
 
 package android.mtp;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.storage.StorageVolume;
 
 /**
@@ -46,6 +47,7 @@
      *
      * @return the storage ID
      */
+    @UnsupportedAppUsage
     public final int getStorageId() {
         return mStorageId;
     }
@@ -55,6 +57,7 @@
      *
      * @return the storage file path
      */
+    @UnsupportedAppUsage
     public final String getPath() {
         return mPath;
     }
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index 53ec6c8..728e6e1 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -18,6 +18,7 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceView;
@@ -163,6 +164,7 @@
     /**
      * {@hide}
      */
+    @UnsupportedAppUsage
     public static native EGLDisplay eglGetDisplay(
         long display_id
     );
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index 137f2f5..d66e7ac 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -19,6 +19,8 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
+
 /** OpenGL ES 2.0
  */
 public class GLES20 {
@@ -824,6 +826,7 @@
     // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveAttrib(
         int program,
         int index,
@@ -872,6 +875,7 @@
     // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveUniform(
         int program,
         int index,
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 0f0a7e9d..8a3e6a0 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -16,6 +16,7 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Trace;
 import android.util.AttributeSet;
@@ -1235,6 +1236,7 @@
         EGLDisplay mEglDisplay;
         EGLSurface mEglSurface;
         EGLConfig mEglConfig;
+        @UnsupportedAppUsage
         EGLContext mEglContext;
 
     }
@@ -1844,6 +1846,7 @@
 
         // End of member variables protected by the sGLThreadManager monitor.
 
+        @UnsupportedAppUsage
         private EglHelper mEglHelper;
 
         /**
@@ -1919,7 +1922,9 @@
 
     private final WeakReference<GLSurfaceView> mThisWeakRef =
             new WeakReference<GLSurfaceView>(this);
+    @UnsupportedAppUsage
     private GLThread mGLThread;
+    @UnsupportedAppUsage
     private Renderer mRenderer;
     private boolean mDetached;
     private EGLConfigChooser mEGLConfigChooser;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
index 01df0ec..dddfa7a 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -102,17 +102,4 @@
     private boolean isRectZero(Rect r) {
         return r.left == 0 && r.top == 0 && r.right == 0 && r.bottom == 0;
     }
-
-    @Test
-    public void testPlusPaint_isEqualToBoltPaint() {
-        // Before setting color
-        assertTrue(mBatteryDrawable.mPlusPaint.hasEqualAttributes(mBatteryDrawable.mBoltPaint));
-
-        final int fakeFillColor = 123;
-        final int fakeBackgrundColor = 456;
-
-        // After
-        mBatteryDrawable.setColors(fakeFillColor, fakeBackgrundColor);
-        assertTrue(mBatteryDrawable.mPlusPaint.hasEqualAttributes(mBatteryDrawable.mBoltPaint));
-    }
 }
diff --git a/packages/SystemUI/docs/plugin_hooks.md b/packages/SystemUI/docs/plugin_hooks.md
index 5b08bfc..9fe2e18 100644
--- a/packages/SystemUI/docs/plugin_hooks.md
+++ b/packages/SystemUI/docs/plugin_hooks.md
@@ -51,6 +51,10 @@
 
 Use: Control over swipes/input for notification views, can be used to control what happens when you swipe/long-press
 
+### Action: com.android.systemui.action.PLUGIN_CLOCK
+Expected interface: [ClockPlugin](/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java)
+
+Use: Allows replacement of the keyguard main clock.
 
 # Global plugin dependencies
 These classes can be accessed by any plugin using PluginDependency as long as they @Requires them.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
new file mode 100644
index 0000000..b4fc820
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+import android.graphics.Paint.Style;
+import android.view.View;
+
+/**
+ * This plugin is used to replace main clock in keyguard.
+ */
+@ProvidesInterface(action = ClockPlugin.ACTION, version = ClockPlugin.VERSION)
+public interface ClockPlugin extends Plugin {
+
+    String ACTION = "com.android.systemui.action.PLUGIN_CLOCK";
+    int VERSION = 1;
+
+    /**
+     * Get clock view.
+     * @return clock view from plugin.
+     */
+    View getView();
+
+    /**
+     * Set clock paint style.
+     * @param style The new style to set in the paint.
+     */
+    void setStyle(Style style);
+
+    /**
+     * Set clock text color.
+     * @param color A color value.
+     */
+    void setTextColor(int color);
+}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
new file mode 100644
index 0000000..89b873e
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is a view that shows clock information in Keyguard. -->
+<com.android.keyguard.KeyguardClockSwitch
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:layout_alignParentTop="true">
+    <TextClock
+        android:id="@+id/default_clock_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:letterSpacing="0.03"
+        android:textColor="?attr/wallpaperTextColor"
+        android:singleLine="true"
+        style="@style/widget_big_thin"
+        android:format12Hour="@string/keyguard_widget_12_hours_format"
+        android:format24Hour="@string/keyguard_widget_24_hours_format" />
+</com.android.keyguard.KeyguardClockSwitch>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
index 87983b9..a795442 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_presentation.xml
@@ -38,19 +38,10 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal|top">
-                <TextClock
-                    android:id="@+id/clock_view"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_horizontal"
-                    android:layout_centerHorizontal="true"
-                    android:layout_alignParentTop="true"
-                    android:letterSpacing="0.03"
-                    android:textColor="?attr/wallpaperTextColor"
-                    android:singleLine="true"
-                    style="@style/widget_big_thin"
-                    android:format12Hour="@string/keyguard_widget_12_hours_format"
-                    android:format24Hour="@string/keyguard_widget_24_hours_format" />
+                <include layout="@layout/keyguard_clock_switch"
+                         android:id="@+id/clock_view"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content" />
                 <View
                     android:id="@+id/clock_separator"
                     android:layout_width="@dimen/widget_separator_width"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index ba05ccf..4ae2d41 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -55,19 +55,10 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal|top">
-            <TextClock
-                android:id="@+id/clock_view"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:layout_centerHorizontal="true"
-                android:layout_alignParentTop="true"
-                android:letterSpacing="0.03"
-                android:textColor="?attr/wallpaperTextColor"
-                android:singleLine="true"
-                style="@style/widget_big_thin"
-                android:format12Hour="@string/keyguard_widget_12_hours_format"
-                android:format24Hour="@string/keyguard_widget_24_hours_format" />
+            <include layout="@layout/keyguard_clock_switch"
+                 android:id="@+id/clock_view"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content" />
             <View
                 android:id="@+id/clock_separator"
                 android:layout_width="@dimen/widget_separator_width"
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index baaf699..d72021e 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -18,14 +18,16 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_marginStart="@dimen/rounded_corner_content_padding"
+    android:layout_marginEnd="@dimen/rounded_corner_content_padding"
+    android:paddingStart="@dimen/nav_content_padding"
+    android:paddingEnd="@dimen/nav_content_padding">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingStart="@dimen/rounded_corner_content_padding"
-        android:paddingEnd="@dimen/rounded_corner_content_padding"
         android:clipChildren="false"
         android:clipToPadding="false">
 
@@ -34,8 +36,6 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="horizontal"
-            android:paddingStart="@dimen/nav_content_padding"
-            android:paddingEnd="@dimen/nav_content_padding"
             android:clipToPadding="false"
             android:clipChildren="false" />
 
@@ -46,8 +46,6 @@
             android:layout_gravity="center"
             android:gravity="center"
             android:orientation="horizontal"
-            android:paddingStart="@dimen/nav_content_padding"
-            android:paddingEnd="@dimen/nav_content_padding"
             android:clipToPadding="false"
             android:clipChildren="false" />
 
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 6d5b7788..24a0c71 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -18,14 +18,16 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_marginTop="@dimen/rounded_corner_content_padding"
+    android:layout_marginBottom="@dimen/rounded_corner_content_padding"
+    android:paddingTop="@dimen/nav_content_padding"
+    android:paddingBottom="@dimen/nav_content_padding">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingTop="@dimen/rounded_corner_content_padding"
-        android:paddingBottom="@dimen/rounded_corner_content_padding"
         android:clipChildren="false"
         android:clipToPadding="false">
 
@@ -34,10 +36,8 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
-            android:paddingTop="@dimen/nav_content_padding"
-            android:paddingBottom="@dimen/nav_content_padding"
-            android:clipChildren="false"
-            android:clipToPadding="false" />
+            android:clipToPadding="false"
+            android:clipChildren="false" />
 
         <com.android.systemui.statusbar.phone.ReverseLinearLayout
             android:id="@+id/center_group"
@@ -45,10 +45,8 @@
             android:layout_height="match_parent"
             android:gravity="center"
             android:orientation="vertical"
-            android:paddingTop="@dimen/nav_content_padding"
-            android:paddingBottom="@dimen/nav_content_padding"
-            android:clipChildren="false"
-            android:clipToPadding="false" />
+            android:clipToPadding="false"
+            android:clipChildren="false" />
 
     </com.android.systemui.statusbar.phone.NearestTouchFrame>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
new file mode 100644
index 0000000..5bbbc52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -0,0 +1,155 @@
+package com.android.keyguard;
+
+import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextClock;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+
+/**
+ * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
+ */
+public class KeyguardClockSwitch extends FrameLayout {
+    /**
+     * Optional/alternative clock injected via plugin.
+     */
+    private ClockPlugin mClockPlugin;
+    /**
+     * Default clock.
+     */
+    private TextClock mClockView;
+
+    private final PluginListener<ClockPlugin> mClockPluginListener =
+            new PluginListener<ClockPlugin>() {
+                @Override
+                public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
+                    View view = plugin.getView();
+                    if (view != null) {
+                        mClockPlugin = plugin;
+                        addView(view, -1,
+                                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                        ViewGroup.LayoutParams.WRAP_CONTENT));
+                        initPluginParams();
+                        mClockView.setVisibility(View.GONE);
+                    }
+                }
+
+                @Override
+                public void onPluginDisconnected(ClockPlugin plugin) {
+                    View view = plugin.getView();
+                    if (view != null) {
+                        mClockPlugin = null;
+                        removeView(view);
+                        mClockView.setVisibility(View.VISIBLE);
+                    }
+                }
+            };
+
+    public KeyguardClockSwitch(Context context) {
+        this(context, null);
+    }
+
+    public KeyguardClockSwitch(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mClockView = findViewById(R.id.default_clock_view);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
+                ClockPlugin.class);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
+    }
+
+    /**
+     * It will also update plugin setStyle if plugin is connected.
+     */
+    public void setStyle(Style style) {
+        mClockView.getPaint().setStyle(style);
+        if (mClockPlugin != null) {
+            mClockPlugin.setStyle(style);
+        }
+    }
+
+    /**
+     * It will also update plugin setTextColor if plugin is connected.
+     */
+    public void setTextColor(int color) {
+        mClockView.setTextColor(color);
+        if (mClockPlugin != null) {
+            mClockPlugin.setTextColor(color);
+        }
+    }
+
+    public void setShowCurrentUserTime(boolean showCurrentUserTime) {
+        mClockView.setShowCurrentUserTime(showCurrentUserTime);
+    }
+
+    public void setElegantTextHeight(boolean elegant) {
+        mClockView.setElegantTextHeight(elegant);
+    }
+
+    public void setTextSize(int unit, float size) {
+        mClockView.setTextSize(unit, size);
+    }
+
+    public void setFormat12Hour(CharSequence format) {
+        mClockView.setFormat12Hour(format);
+    }
+
+    public void setFormat24Hour(CharSequence format) {
+        mClockView.setFormat24Hour(format);
+    }
+
+    public Paint getPaint() {
+        return mClockView.getPaint();
+    }
+
+    public int getCurrentTextColor() {
+        return mClockView.getCurrentTextColor();
+    }
+
+    public float getTextSize() {
+        return mClockView.getTextSize();
+    }
+
+    public void refresh() {
+        mClockView.refresh();
+    }
+
+    /**
+     * When plugin changes, set all kept parameters into newer plugin.
+     */
+    private void initPluginParams() {
+        if (mClockPlugin != null) {
+            mClockPlugin.setStyle(getPaint().getStyle());
+            mClockPlugin.setTextColor(getCurrentTextColor());
+        }
+    }
+
+    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+    PluginListener getClockPluginListener() {
+        return mClockPluginListener;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 6da143c..6d1313c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -39,7 +39,6 @@
 import android.view.View;
 import android.widget.GridLayout;
 import android.widget.RelativeLayout;
-import android.widget.TextClock;
 import android.widget.TextView;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -64,7 +63,7 @@
     private final float mSmallClockScale;
 
     private TextView mLogoutView;
-    private TextClock mClockView;
+    private KeyguardClockSwitch mClockView;
     private View mClockSeparator;
     private TextView mOwnerInfo;
     private KeyguardSliceView mKeyguardSlice;
@@ -248,7 +247,7 @@
                         .scaleX(clockScale)
                         .scaleY(clockScale)
                         .withEndAction(() -> {
-                            mClockView.getPaint().setStyle(style);
+                            mClockView.setStyle(style);
                             mClockView.invalidate();
                         })
                         .start();
@@ -256,7 +255,7 @@
                 mClockView.setY(top);
                 mClockView.setScaleX(clockScale);
                 mClockView.setScaleY(clockScale);
-                mClockView.getPaint().setStyle(style);
+                mClockView.setStyle(style);
                 mClockView.invalidate();
             }
         } else if (view == mClockSeparator) {
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 3c44eb4..0864ff0 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -55,6 +55,7 @@
 
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
 
 /**
@@ -69,6 +70,10 @@
     private static final long BACKOFF_MILLIS = 1000;
     private static final long DEFERRED_CALLBACK_MILLIS = 5000;
 
+    // Default interaction flags if swipe up is disabled before connecting to launcher
+    private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP
+            | FLAG_SHOW_OVERVIEW_BUTTON;
+
     private final Context mContext;
     private final Handler mHandler;
     private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
@@ -220,7 +225,7 @@
 
             // When launcher service is disabled, reset interaction flags because it is inactive
             if (!isEnabled()) {
-                mInteractionFlags = 0;
+                mInteractionFlags = getDefaultInteractionFlags();
                 Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
             }
 
@@ -300,7 +305,8 @@
                 com.android.internal.R.string.config_recentsComponentName));
         mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, 0);
+        mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
+                getDefaultInteractionFlags());
 
         // Listen for the package update changes.
         if (SystemServicesProxy.getInstance(context)
@@ -397,6 +403,15 @@
         }
     }
 
+    private int getDefaultInteractionFlags() {
+        // If there is no settings available use device default or get it from settings
+        final boolean defaultState = getSwipeUpDefaultValue();
+        final boolean swipeUpEnabled = getSwipeUpSettingAvailable()
+                ? getSwipeUpEnabledFromSettings(defaultState)
+                : defaultState;
+        return swipeUpEnabled ? 0 : DEFAULT_DISABLE_SWIPE_UP_STATE;
+    }
+
     private void notifyBackButtonAlphaChanged(float alpha, boolean animate) {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
@@ -427,6 +442,21 @@
                 ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
     }
 
+    private boolean getSwipeUpDefaultValue() {
+        return mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default);
+    }
+
+    private boolean getSwipeUpSettingAvailable() {
+        return mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_setting_available);
+    }
+
+    private boolean getSwipeUpEnabledFromSettings(boolean defaultValue) {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, defaultValue ? 1 : 0) == 1;
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(TAG_OPS + " state:");
@@ -440,12 +470,10 @@
         pw.print("  quickStepIntent="); pw.println(mQuickStepIntent);
         pw.print("  quickStepIntentResolved="); pw.println(isEnabled());
 
-        final int swipeUpDefaultValue = mContext.getResources()
-                .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default) ? 1 : 0;
-        final int swipeUpEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, swipeUpDefaultValue);
-        pw.print("  swipeUpSetting="); pw.println(swipeUpEnabled != 0);
-        pw.print("  swipeUpSettingDefault="); pw.println(swipeUpDefaultValue != 0);
+        final boolean swipeUpDefaultValue = getSwipeUpDefaultValue();
+        final boolean swipeUpEnabled = getSwipeUpEnabledFromSettings(swipeUpDefaultValue);
+        pw.print("  swipeUpSetting="); pw.println(swipeUpEnabled);
+        pw.print("  swipeUpSettingDefault="); pw.println(swipeUpDefaultValue);
     }
 
     public interface OverviewProxyListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index fe8ea34..c96aa73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -45,6 +45,7 @@
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceProvider;
 import androidx.slice.builders.ListBuilder;
@@ -127,8 +128,8 @@
 
     @Override
     public Slice onBindSlice(Uri sliceUri) {
-        ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
-        builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText));
+        ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
+        builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
         addNextAlarm(builder);
         addZenMode(builder);
         addPrimaryAction(builder);
@@ -139,11 +140,13 @@
         // Add simple action because API requires it; Keyguard handles presenting
         // its own slices so this action + icon are actually never used.
         PendingIntent pi = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
-        Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
-        SliceAction action = new SliceAction(pi, icon, mLastText);
+        IconCompat icon = IconCompat.createWithResource(getContext(),
+                R.drawable.ic_access_alarms_big);
+        SliceAction action = SliceAction.createDeeplink(pi, icon,
+                ListBuilder.ICON_IMAGE, mLastText);
 
-        RowBuilder primaryActionRow = new RowBuilder(builder, Uri.parse(KEYGUARD_ACTION_URI))
-            .setPrimaryAction(action);
+        RowBuilder primaryActionRow = new RowBuilder(Uri.parse(KEYGUARD_ACTION_URI))
+                .setPrimaryAction(action);
         builder.addRow(primaryActionRow);
     }
 
@@ -152,10 +155,11 @@
             return;
         }
 
-        Icon alarmIcon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big);
-        RowBuilder alarmRowBuilder = new RowBuilder(builder, mAlarmUri)
+        IconCompat alarmIcon = IconCompat.createWithResource(getContext(),
+                R.drawable.ic_access_alarms_big);
+        RowBuilder alarmRowBuilder = new RowBuilder(mAlarmUri)
                 .setTitle(mNextAlarm)
-                .addEndItem(alarmIcon);
+                .addEndItem(alarmIcon, ListBuilder.ICON_IMAGE);
         builder.addRow(alarmRowBuilder);
     }
 
@@ -167,10 +171,11 @@
         if (!isDndSuppressingNotifications()) {
             return;
         }
-        RowBuilder dndBuilder = new RowBuilder(builder, mDndUri)
+        RowBuilder dndBuilder = new RowBuilder(mDndUri)
                 .setContentDescription(getContext().getResources()
                         .getString(R.string.accessibility_quick_settings_dnd))
-                .addEndItem(Icon.createWithResource(getContext(), R.drawable.stat_sys_dnd));
+                .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
+                        ListBuilder.ICON_IMAGE);
         builder.addRow(dndBuilder);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index af0ed284..506d697 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -40,7 +40,6 @@
     private final int mShortAnimDuration;
     private final StatusBar mStatusBar;
     private final UserManagerHelper mUserManagerHelper;
-    private int mCurrentForegroundUserId;
     private boolean mShowing;
 
     public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) {
@@ -55,7 +54,6 @@
         mUserGridView.setUserSelectionListener(this::onUserSelected);
 
         mUserManagerHelper = new UserManagerHelper(context);
-        updateCurrentForegroundUser();
 
         mShortAnimDuration = mContainer.getResources()
             .getInteger(android.R.integer.config_shortAnimTime);
@@ -78,22 +76,8 @@
     }
 
     public void onUserSwitched(int newUserId) {
-        // The logic for foreground user change is needed here to exclude the reboot case. On
-        // reboot, system fires ACTION_USER_SWITCHED change from -1 to 0 user. This is not an actual
-        // user switch. We only want to trigger keyguard dismissal when foreground user changes.
-        if (foregroundUserChanged()) {
-            toggleSwitchInProgress(false);
-            updateCurrentForegroundUser();
-            mParent.post(this::dismissKeyguard);
-        }
-    }
-
-    private boolean foregroundUserChanged() {
-        return mCurrentForegroundUserId != mUserManagerHelper.getForegroundUserId();
-    }
-
-    private void updateCurrentForegroundUser() {
-        mCurrentForegroundUserId = mUserManagerHelper.getForegroundUserId();
+        toggleSwitchInProgress(false);
+        mParent.post(this::dismissKeyguard);
     }
 
     private void onUserSelected(UserGridRecyclerView.UserRecord record) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 8f552e3..92a9efe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -40,6 +40,8 @@
     public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
     public static final boolean FORCE_NO_BLANKING =
             SystemProperties.getBoolean("debug.force_no_blanking", false);
+    public static final boolean FORCE_BLANKING =
+            SystemProperties.getBoolean("debug.force_blanking", false);
 
     private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
     private static DozeParameters sInstance;
@@ -183,7 +185,7 @@
      * @return {@code true} if screen needs to be completely black before a power transition.
      */
     public boolean getDisplayNeedsBlanking() {
-        return !FORCE_NO_BLANKING && mContext.getResources().getBoolean(
+        return FORCE_BLANKING || !FORCE_NO_BLANKING && mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_displayBlanksAfterDoze);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index b80cd30..042e4ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -103,9 +103,9 @@
     private float mDarkAmount;
 
     /**
-     * If keyguard will just fade away or will require a password.
+     * If keyguard will require a password or just fade away.
      */
-    private boolean mFadeAway;
+    private boolean mCurrentlySecure;
 
     /**
      * Dozing and receiving a notification (AOD notification.)
@@ -135,7 +135,7 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight,
-            int keyguardStatusHeight, float dark, boolean fadeAway, boolean pulsing,
+            int keyguardStatusHeight, float dark, boolean secure, boolean pulsing,
             int bouncerTop) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
@@ -144,7 +144,7 @@
         mHeight = parentHeight;
         mKeyguardStatusHeight = keyguardStatusHeight;
         mDarkAmount = dark;
-        mFadeAway = fadeAway;
+        mCurrentlySecure = secure;
         mPulsing = pulsing;
         mBouncerTop = bouncerTop;
     }
@@ -198,7 +198,7 @@
 
         float clockYRegular = getExpandedClockPosition();
         boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop;
-        float clockYTarget = !mFadeAway && hasEnoughSpace ?
+        float clockYTarget = mCurrentlySecure && hasEnoughSpace ?
                 mMinTopMargin : -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
@@ -218,11 +218,11 @@
      */
     private float getClockAlpha(int y) {
         float alphaKeyguard;
-        if (mFadeAway) {
+        if (mCurrentlySecure) {
+            alphaKeyguard = 1;
+        } else {
             alphaKeyguard = Math.max(0, y / Math.max(1f, getExpandedClockPosition()));
             alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
-        } else {
-            alphaKeyguard = 1;
         }
         return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7db5802..7476963 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -92,6 +92,21 @@
 
     private static final boolean DEBUG = false;
 
+    /**
+     * Fling expanding QS.
+     */
+    public static final int FLING_EXPAND = 0;
+
+    /**
+     * Fling collapsing QS, potentially stopping when QS becomes QQS.
+     */
+    public static final int FLING_COLLAPSE = 1;
+
+    /**
+     * Fing until QS is completely hidden.
+     */
+    public static final int FLING_HIDE = 2;
+
     // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
     // changed.
     private static final int CAP_HEIGHT = 1456;
@@ -524,8 +539,7 @@
                     totalHeight,
                     mKeyguardStatusView.getHeight(),
                     mInterpolatedDarkAmount,
-                    !mStatusBar.isKeyguardCurrentlySecure()
-                            || mStatusBar.isKeyguardOccludeAnimationRunning(),
+                    mStatusBar.isKeyguardCurrentlySecure(),
                     mPulsing,
                     mBouncerTop);
             mClockPositionAlgorithm.run(mClockPositionResult);
@@ -624,7 +638,7 @@
     }
 
     @Override
-    public void resetViews() {
+    public void resetViews(boolean animate) {
         mIsLaunchTransitionFinished = false;
         mBlockTouches = false;
         mUnlockIconActive = false;
@@ -632,11 +646,15 @@
             mAffordanceHelper.reset(false);
             mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
         }
-        closeQs();
         mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
                 true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
-        mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
-                true /* cancelAnimators */);
+        if (animate) {
+            animateCloseQs(true /* animateAway */);
+        } else {
+            closeQs();
+        }
+        mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, animate,
+                !animate /* cancelAnimators */);
         mNotificationStackScroller.resetScrollPosition();
     }
 
@@ -658,7 +676,13 @@
         setQsExpansion(mQsMinExpansionHeight);
     }
 
-    public void animateCloseQs() {
+    /**
+     * Animate QS closing by flinging it.
+     * If QS is expanded, it will collapse into QQS and stop.
+     *
+     * @param animateAway Do not stop when QS becomes QQS. Fling until QS isn't visible anymore.
+     */
+    public void animateCloseQs(boolean animateAway) {
         if (mQsExpansionAnimator != null) {
             if (!mQsAnimatorExpand) {
                 return;
@@ -667,14 +691,7 @@
             mQsExpansionAnimator.cancel();
             setQsExpansion(height);
         }
-        flingSettings(0 /* vel */, false);
-    }
-
-    public void openQs() {
-        cancelQsAnimation();
-        if (mQsExpansionEnabled) {
-            setQsExpansion(mQsMaxExpansionHeight);
-        }
+        flingSettings(0 /* vel */, animateAway ? FLING_HIDE : FLING_COLLAPSE);
     }
 
     public void expandWithQs() {
@@ -687,7 +704,7 @@
 
     public void expandWithoutQs() {
         if (isQsExpanded()) {
-            flingSettings(0 /* velocity */, false /* expand */);
+            flingSettings(0 /* velocity */, FLING_COLLAPSE);
         } else {
             expand(true /* animate */);
         }
@@ -831,7 +848,7 @@
         if (expandsQs) {
             logQsSwipeDown(y);
         }
-        flingSettings(vel, expandsQs && !isCancelMotionEvent);
+        flingSettings(vel, expandsQs && !isCancelMotionEvent ? FLING_EXPAND : FLING_COLLAPSE);
     }
 
     private void logQsSwipeDown(float y) {
@@ -1100,7 +1117,8 @@
         mLastOverscroll = 0f;
         mQsExpansionFromOverscroll = false;
         setQsExpansion(mQsExpansionHeight);
-        flingSettings(!mQsExpansionEnabled && open ? 0f : velocity, open && mQsExpansionEnabled,
+        flingSettings(!mQsExpansionEnabled && open ? 0f : velocity,
+                open && mQsExpansionEnabled ? FLING_EXPAND : FLING_COLLAPSE,
                 new Runnable() {
                     @Override
                     public void run() {
@@ -1467,13 +1485,35 @@
         }
     }
 
-    public void flingSettings(float vel, boolean expand) {
-        flingSettings(vel, expand, null, false /* isClick */);
+    /**
+     * @see #flingSettings(float, int, Runnable, boolean)
+     */
+    public void flingSettings(float vel, int type) {
+        flingSettings(vel, type, null, false /* isClick */);
     }
 
-    protected void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable,
+    /**
+     * Animates QS or QQS as if the user had swiped up or down.
+     *
+     * @param vel Finger velocity or 0 when not initiated by touch events.
+     * @param type Either {@link #FLING_EXPAND}, {@link #FLING_COLLAPSE} or {@link #FLING_HIDE}.
+     * @param onFinishRunnable Runnable to be executed at the end of animation.
+     * @param isClick If originated by click (different interpolator and duration.)
+     */
+    protected void flingSettings(float vel, int type, final Runnable onFinishRunnable,
             boolean isClick) {
-        float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
+        float target;
+        switch (type) {
+            case FLING_EXPAND:
+                target = mQsMaxExpansionHeight;
+                break;
+            case FLING_COLLAPSE:
+                target = mQsMinExpansionHeight;
+                break;
+            case FLING_HIDE:
+            default:
+                target = 0;
+        }
         if (target == mQsExpansionHeight) {
             if (onFinishRunnable != null) {
                 onFinishRunnable.run();
@@ -1483,7 +1523,8 @@
 
         // If we move in the opposite direction, reset velocity and use a different duration.
         boolean oppositeDirection = false;
-        if (vel > 0 && !expand || vel < 0 && expand) {
+        boolean expanding = type == FLING_EXPAND;
+        if (vel > 0 && !expanding || vel < 0 && expanding) {
             vel = 0;
             oppositeDirection = true;
         }
@@ -1497,11 +1538,8 @@
         if (oppositeDirection) {
             animator.setDuration(350);
         }
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                setQsExpansion((Float) animation.getAnimatedValue());
-            }
+        animator.addUpdateListener(animation -> {
+            setQsExpansion((Float) animation.getAnimatedValue());
         });
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -1515,7 +1553,7 @@
         });
         animator.start();
         mQsExpansionAnimator = animator;
-        mQsAnimatorExpand = expand;
+        mQsAnimatorExpand = expanding;
     }
 
     /**
@@ -2001,10 +2039,12 @@
     public void onClick(View v) {
         onQsExpansionStarted();
         if (mQsExpanded) {
-            flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
+            flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
+                    true /* isClick */);
         } else if (mQsExpansionEnabled) {
             mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
-            flingSettings(0 /* vel */, true /* expand */, null, true /* isClick */);
+            flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */,
+                    true /* isClick */);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 5d23494..deac669e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -194,7 +194,7 @@
             pv.collapse(delayed, speedUpFactor);
             waiting = true;
         } else {
-            pv.resetViews();
+            pv.resetViews(false /* animate */);
             pv.setExpandedFraction(0); // just in case
             pv.cancelPeek();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e4eeec1..1f09835 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1240,7 +1240,7 @@
         ));
     }
 
-    public abstract void resetViews();
+    public abstract void resetViews(boolean animate);
 
     protected abstract float getPeekHeight();
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index dd4ea3d..3c351ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -322,8 +322,6 @@
     public static final int FADE_KEYGUARD_START_DELAY = 100;
     public static final int FADE_KEYGUARD_DURATION = 300;
     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
-    public static final int FADE_BACKDROP_DURATION = 300;
-    public static final int FADE_BACKDROP_DURATION_FAST = 240;
 
     /** If true, the system is in the half-boot-to-decryption-screen state.
      * Prudently disable QS and notifications.  */
@@ -545,7 +543,6 @@
     private boolean mIsOccluded;
     private boolean mWereIconsJustHidden;
     private boolean mBouncerWasShowingWhenHidden;
-    private boolean mKeyguardOccludeAnimationRunning;
 
     // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
     // this animation is tied to the scrim for historic reasons.
@@ -1644,7 +1641,7 @@
 
         boolean wakeAndUnlock = mBiometricUnlockController != null
             && mBiometricUnlockController.isWakeAndUnlock();
-        if (mLaunchTransitionFadingAway && !mIsOccluded || wakeAndUnlock) {
+        if (mLaunchTransitionFadingAway || wakeAndUnlock) {
             mBackdrop.setVisibility(View.INVISIBLE);
             Trace.endSection();
             return;
@@ -1763,8 +1760,7 @@
                 boolean cannotAnimateDoze = mDozing && !ScrimState.AOD.getAnimateChange();
                 if (mBiometricUnlockController.getMode()
                         == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        || hideBecauseOccluded  && !mKeyguardOccludeAnimationRunning
-                        || cannotAnimateDoze) {
+                        || hideBecauseOccluded || cannotAnimateDoze) {
 
                     // We are unlocking directly - no animation!
                     mBackdrop.setVisibility(View.GONE);
@@ -1775,9 +1771,7 @@
                     mBackdrop.animate()
                             .alpha(SRC_MIN_ALPHA)
                             .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
-                            .setDuration(
-                                    mKeyguardOccludeAnimationRunning
-                                            ? FADE_BACKDROP_DURATION_FAST : FADE_BACKDROP_DURATION)
+                            .setDuration(300)
                             .setStartDelay(0)
                             .withEndAction(() -> {
                                 mBackdrop.setVisibility(View.GONE);
@@ -2245,7 +2239,8 @@
                 mNotificationPanel.expand(true /* animate */);
                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
-                mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
+                mNotificationPanel.flingSettings(0 /* velocity */,
+                        NotificationPanelView.FLING_EXPAND);
                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
             }
         }
@@ -3674,27 +3669,6 @@
     }
 
     /**
-    * Is keyguard being occluded by a newly launched activity.
-    */
-    public boolean isKeyguardOccludeAnimationRunning() {
-        return mKeyguardOccludeAnimationRunning;
-    }
-
-    /**
-     * Plays the animation when new activity is launched over keyguard.
-     */
-    public void animateKeyguardOccluding() {
-        mKeyguardOccludeAnimationRunning = true;
-        addPostCollapseAction(() -> {
-            mStatusBarKeyguardViewManager.reset(true /* hideBouncerWhenShowing */);
-            mKeyguardOccludeAnimationRunning = false;
-        });
-        mStatusBarKeyguardViewManager.animateCollapsePanels(1.0f /* speedfactor */);
-        updateScrimController();
-        updateMediaMetaData(false /* metaDataChanged */, true /* allowEnterAnimation */);
-    }
-
-    /**
      * Plays the animation when an activity that was occluding Keyguard goes away.
      */
     public void animateKeyguardUnoccluding() {
@@ -3716,7 +3690,7 @@
         Log.w(TAG, "Launch transition: Timeout!");
         mNotificationPanel.onAffordanceLaunchEnded();
         releaseGestureWakeLock();
-        mNotificationPanel.resetViews();
+        mNotificationPanel.resetViews(false /* animate */);
     }
 
     private void runLaunchTransitionEndRunnable() {
@@ -3869,7 +3843,9 @@
         Trace.beginSection("StatusBar#updateKeyguardState");
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationController.setVisible(true);
-            mNotificationPanel.resetViews();
+            boolean dozingAnimated = mDozingRequested
+                    && DozeParameters.getInstance(mContext).shouldControlScreenOff();
+            mNotificationPanel.resetViews(dozingAnimated);
             if (mKeyguardUserSwitcher != null) {
                 mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
             }
@@ -4014,7 +3990,7 @@
             if (mNotificationPanel.isQsDetailShowing()) {
                 mNotificationPanel.closeQsDetail();
             } else {
-                mNotificationPanel.animateCloseQs();
+                mNotificationPanel.animateCloseQs(false /* animateAway */);
             }
             return true;
         }
@@ -4039,7 +4015,7 @@
 
     private void showBouncerIfKeyguard() {
         if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
-                && !mKeyguardViewMediator.isHiding() && !mKeyguardOccludeAnimationRunning) {
+                && !mKeyguardViewMediator.isHiding()) {
             showBouncer(true /* scrimmed */);
         }
     }
@@ -4539,11 +4515,6 @@
 
         @Override
         public void onStartedGoingToSleep() {
-            // in case we start going to sleep while new animation is launching over keyguard, make
-            // sure to finish it
-            if (mKeyguardOccludeAnimationRunning) {
-                runPostCollapseRunnables();
-            }
             notifyHeadsUpGoingToSleep();
             dismissVolumeDialog();
         }
@@ -4785,7 +4756,7 @@
                     ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
             mScrimController.transitionTo(state);
         } else if (isInLaunchTransition() || mLaunchCameraOnScreenTurningOn
-                || launchingAffordanceWithPreview || mKeyguardOccludeAnimationRunning) {
+                || launchingAffordanceWithPreview) {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 97088bd..c4424d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -365,11 +365,6 @@
                             }
                         });
                 return;
-            } else if (animate) {
-                mOccluded = true;
-                mStatusBar.animateKeyguardOccluding();
-                mStatusBarWindowManager.setKeyguardOccluded(mOccluded);
-                return;
             }
         } else if (!occluded && mOccluded && mShowing) {
             StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index f83fb43..a38328a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -144,8 +144,7 @@
                 state.scrimsVisibility == ScrimController.VISIBILITY_FULLY_OPAQUE;
         final boolean keyguardOrAod = state.keyguardShowing
                 || (state.dozing && mDozeParameters.getAlwaysOn());
-        if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper
-                && !state.keyguardOccluded) {
+        if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) {
             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
         } else {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 1bdb7ad..196d9bc 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -119,7 +119,9 @@
         // 3 Removed because of a revert.
         if (oldVersion < 4) {
             // Delay this so that we can wait for everything to be registered first.
-            new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000);
+            final int user = mCurrentUser;
+            new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
+                    () -> clearAllFromUser(user), 5000);
         }
         setValue(TUNER_VERSION, newVersion);
     }
@@ -221,6 +223,10 @@
 
     @Override
     public void clearAll() {
+        clearAllFromUser(mCurrentUser);
+    }
+
+    public void clearAllFromUser(int user) {
         // A couple special cases.
         Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
         Intent intent = new Intent(DemoMode.ACTION_DEMO);
@@ -231,7 +237,7 @@
             if (ArrayUtils.contains(RESET_BLACKLIST, key)) {
                 continue;
             }
-            Settings.Secure.putString(mContentResolver, key, null);
+            Settings.Secure.putStringForUser(mContentResolver, key, null, user);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
new file mode 100644
index 0000000..e6e4857
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Color;
+import android.graphics.Paint.Style;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.text.TextPaint;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextClock;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardClockSwitchTest extends SysuiTestCase {
+    private PluginManager mPluginManager;
+
+    @Mock
+    TextClock mClockView;
+    @InjectMocks
+    KeyguardClockSwitch mKeyguardClockSwitch;
+
+    @Before
+    public void setUp() {
+        mPluginManager = mDependency.injectMockDependency(PluginManager.class);
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        mKeyguardClockSwitch =
+                (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void onAttachToWindow_addPluginListener() {
+        mKeyguardClockSwitch.onAttachedToWindow();
+
+        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
+        verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class));
+    }
+
+    @Test
+    public void onDetachToWindow_removePluginListener() {
+        mKeyguardClockSwitch.onDetachedFromWindow();
+
+        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
+        verify(mPluginManager).removePluginListener(listener.capture());
+    }
+
+    @Test
+    public void onPluginConnected_showPluginClock() {
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        TextClock pluginView = new TextClock(getContext());
+        when(plugin.getView()).thenReturn(pluginView);
+        TextPaint paint = mock(TextPaint.class);
+        doReturn(paint).when(mClockView).getPaint();
+        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
+
+        listener.onPluginConnected(plugin, null);
+
+        verify(mClockView).setVisibility(GONE);
+        assertThat(plugin.getView().getParent()).isEqualTo(mKeyguardClockSwitch);
+    }
+
+    @Test
+    public void onPluginDisconnected_showDefaultClock() {
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        TextClock pluginView = new TextClock(getContext());
+        when(plugin.getView()).thenReturn(pluginView);
+        mClockView.setVisibility(GONE);
+        mKeyguardClockSwitch.addView(plugin.getView(), -1,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
+
+        listener.onPluginDisconnected(plugin);
+
+        verify(mClockView).setVisibility(VISIBLE);
+        assertThat(plugin.getView().getParent()).isNull();
+    }
+
+    @Test
+    public void setTextColor_defaultClockSetTextColor() {
+        mKeyguardClockSwitch.setTextColor(Color.YELLOW);
+
+        verify(mClockView).setTextColor(Color.YELLOW);
+    }
+
+    @Test
+    public void setTextColor_pluginClockSetTextColor() {
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        TextClock pluginView = new TextClock(getContext());
+        when(plugin.getView()).thenReturn(pluginView);
+        TextPaint paint = mock(TextPaint.class);
+        doReturn(paint).when(mClockView).getPaint();
+        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
+        listener.onPluginConnected(plugin, null);
+
+        mKeyguardClockSwitch.setTextColor(Color.WHITE);
+
+        verify(plugin).setTextColor(Color.WHITE);
+    }
+
+    @Test
+    public void setStyle_defaultClockSetStyle() {
+        TextPaint paint = mock(TextPaint.class);
+        Style style = mock(Style.class);
+        doReturn(paint).when(mClockView).getPaint();
+
+        mKeyguardClockSwitch.setStyle(style);
+
+        verify(paint).setStyle(style);
+    }
+
+    @Test
+    public void setStyle_pluginClockSetStyle() {
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        TextClock pluginView = new TextClock(getContext());
+        when(plugin.getView()).thenReturn(pluginView);
+        TextPaint paint = mock(TextPaint.class);
+        doReturn(paint).when(mClockView).getPaint();
+        Style style = mock(Style.class);
+        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
+        listener.onPluginConnected(plugin, null);
+
+        mKeyguardClockSwitch.setStyle(style);
+
+        verify(plugin).setStyle(style);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index d2e8371..4ec30fd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -55,7 +55,7 @@
 
     @Test
     public void showSlice_notifiesListener() {
-        ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
+        ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
         AtomicBoolean notified = new AtomicBoolean();
         mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
         mKeyguardSliceView.onChanged(builder.build());
@@ -74,13 +74,11 @@
 
     @Test
     public void hasHeader_readsSliceData() {
-        ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
+        ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
         mKeyguardSliceView.onChanged(builder.build());
         Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader());
 
-        builder.setHeader((ListBuilder.HeaderBuilder headerBuilder) -> {
-            headerBuilder.setTitle("header title!");
-        });
+        builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
         mKeyguardSliceView.onChanged(builder.build());
         Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader());
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 1d8de2f..9e96df2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -22,7 +22,6 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
-import android.widget.TextClock;
 
 import com.android.systemui.SysuiTestCase;
 
@@ -40,7 +39,7 @@
     @Mock
     KeyguardSliceView mKeyguardSlice;
     @Mock
-    TextClock mClockView;
+    KeyguardClockSwitch mClockView;
     @InjectMocks
     KeyguardStatusView mKeyguardStatusView;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 46e2bfb..a26b1b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -137,7 +137,8 @@
 
     @Test
     public void addZenMode_addedToSlice() {
-        ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri()));
+        ListBuilder listBuilder = spy(new ListBuilder(getContext(), mProvider.getUri(),
+            ListBuilder.INFINITY));
         mProvider.addZenMode(listBuilder);
         verify(listBuilder, never()).addRow(any(ListBuilder.RowBuilder.class));
 
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index 89e9d6a..14e6e91 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -24,7 +24,8 @@
         android:protectionLevel="signatureOrSystem" />
 
     <original-package android:name="com.android.smspush" />
-    <application>
+    <application
+        android:allowClearUserData="false">
         <service android:name=".WapPushManager"
             android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND"
             android:exported="true">
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 6cc6221..f8b4d74 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -941,9 +941,10 @@
     // OS: 6.0
     NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
 
-    // ACTION: App notification settings > Block Notifications
+    // ACTION: App notification settings > Block Notifications or long press on
+    // notification blocks.
     // CATEGORY: SETTINGS
-    // OS: 6.0
+    // OS: 9.0
     ACTION_BAN_APP_NOTES = 147;
 
     // ACTION: Notification shade > Dismiss all button
@@ -6425,6 +6426,10 @@
     // OS: Q (will also ship in PQ1A)
     FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH = 1553;
 
+    // OPEN: Settings > Add face
+    // OS: Q
+    FACE_ENROLL_PREVIEW = 1554;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index a40afc3..f7c1c10 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -136,7 +136,7 @@
     CountDownLatch mLatch;
     FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
     IBackupObserver mBackupObserver;
-    IBackupManagerMonitor mMonitor;
+    @Nullable private IBackupManagerMonitor mMonitor;
     boolean mUserInitiated;
     SinglePackageBackupRunner mBackupRunner;
     private final int mBackupRunnerOpToken;
@@ -154,7 +154,7 @@
             IFullBackupRestoreObserver observer,
             String[] whichPackages, boolean updateSchedule,
             FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
-            IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
+            @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
             boolean userInitiated) {
         super(observer);
         this.backupManagerService = backupManagerService;
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
new file mode 100644
index 0000000..8c83e67
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupReporter.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.keyvalue;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupManagerMonitor;
+import android.app.backup.BackupTransport;
+import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
+import android.content.pm.PackageInfo;
+import android.util.EventLog;
+import android.util.Slog;
+
+import com.android.server.EventLogTags;
+import com.android.server.backup.BackupManagerService;
+import com.android.server.backup.DataChangedJournal;
+import com.android.server.backup.remote.RemoteResult;
+import com.android.server.backup.utils.BackupManagerMonitorUtils;
+import com.android.server.backup.utils.BackupObserverUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+/**
+ * Reports events that happen during a key-value backup task to:
+ *
+ * <ul>
+ *   <li>Logcat (main and event buffers).
+ *   <li>Backup observer (see {@link IBackupObserver}).
+ *   <li>Backup manager monitor (see {@link IBackupManagerMonitor}).
+ * </ul>
+ */
+// TODO: In KeyValueBackupTaskTest, remove direct assertions on logcat, observer or monitor and
+//       verify calls to this object. Add these and more assertions to the test of this class.
+class KeyValueBackupReporter {
+    private static final String TAG = "KeyValueBackupTask";
+    private static final boolean DEBUG = BackupManagerService.DEBUG;
+    private static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || true;
+
+    private final BackupManagerService mBackupManagerService;
+    private final IBackupObserver mObserver;
+    @Nullable private IBackupManagerMonitor mMonitor;
+
+    KeyValueBackupReporter(
+            BackupManagerService backupManagerService,
+            IBackupObserver observer,
+            IBackupManagerMonitor monitor) {
+        mBackupManagerService = backupManagerService;
+        mObserver = observer;
+        mMonitor = monitor;
+    }
+
+    /** Returns the monitor or {@code null} if we lost connection to it. */
+    @Nullable
+    IBackupManagerMonitor getMonitor() {
+        return mMonitor;
+    }
+
+    void onSkipBackup() {
+        if (DEBUG) {
+            Slog.d(TAG, "Skipping backup since one is already in progress");
+        }
+    }
+
+    void onEmptyQueueAtStart() {
+        Slog.w(TAG, "Backup begun with an empty queue, nothing to do");
+    }
+
+    void onPmFoundInQueue() {
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "PM metadata in queue, removing");
+        }
+    }
+
+    void onQueueReady(List<BackupRequest> queue) {
+        if (DEBUG) {
+            Slog.v(TAG, "Beginning backup of " + queue.size() + " targets");
+        }
+    }
+
+    void onTransportReady(String transportName) {
+        EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
+    }
+
+    void onInitializeTransport(String transportName) {
+        Slog.i(TAG, "Initializing transport and resetting backup state");
+    }
+
+    void onTransportInitialized(int status) {
+        if (status == BackupTransport.TRANSPORT_OK) {
+            EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
+        } else {
+            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
+            Slog.e(TAG, "Transport error in initializeDevice()");
+        }
+    }
+
+    void onInitializeTransportError(Exception e) {
+        Slog.e(TAG, "Error during initialization", e);
+    }
+
+    void onSkipPm() {
+        Slog.d(TAG, "Skipping backup of PM metadata");
+    }
+
+    void onInvokePmAgentError(Exception e) {
+        Slog.e(TAG, "Error during PM metadata backup", e);
+    }
+
+    void onEmptyQueue() {
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "Queue now empty");
+        }
+    }
+
+    void onStartPackageBackup(String packageName) {
+        Slog.d(TAG, "Starting key-value backup of " + packageName);
+    }
+
+    void onPackageNotEligibleForBackup(String packageName) {
+        Slog.i(TAG, "Package " + packageName + " no longer supports backup, skipping");
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+    }
+
+    void onPackageEligibleForFullBackup(String packageName) {
+        Slog.i(
+                TAG,
+                "Package " + packageName + " performs full-backup rather than key-value, skipping");
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+    }
+
+    void onPackageStopped(String packageName) {
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+    }
+
+    void onBindAgentError(SecurityException e) {
+        Slog.d(TAG, "Error in bind/backup", e);
+    }
+
+    void onAgentUnknown(String packageName) {
+        Slog.d(TAG, "Package does not exist, skipping");
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+    }
+
+    void onAgentError(String packageName) {
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "Agent failure for " + packageName + ", re-staging");
+        }
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
+    }
+
+    void onInvokeAgent(String packageName) {
+        if (DEBUG) {
+            Slog.d(TAG, "Invoking agent on " + packageName);
+        }
+    }
+
+    void onAgentFilesReady(File backupDataFile) {
+        if (MORE_DEBUG) {
+            Slog.d(TAG, "Data file: " + backupDataFile);
+        }
+    }
+
+    void onRestoreconFailed(File backupDataFile) {
+        Slog.e(TAG, "SELinux restorecon failed on " + backupDataFile);
+    }
+
+    void onCallAgentDoBackupError(String packageName, boolean callingAgent, Exception e) {
+        if (callingAgent) {
+            Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e);
+        } else {
+            Slog.e(TAG, "Error before invoking agent on " + packageName + ": " + e);
+        }
+        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
+    }
+
+    void onFailAgentError(String packageName) {
+        Slog.w(TAG, "Error conveying failure to " + packageName);
+    }
+
+    void onAgentIllegalKey(PackageInfo packageInfo, String key) {
+        String packageName = packageInfo.packageName;
+        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, "bad key");
+        mMonitor =
+                BackupManagerMonitorUtils.monitorEvent(
+                        mMonitor,
+                        BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY,
+                        packageInfo,
+                        BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                        BackupManagerMonitorUtils.putMonitoringExtra(
+                                null, BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, key));
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_AGENT_FAILURE);
+        if (MORE_DEBUG) {
+            Slog.i(
+                    TAG,
+                    "Agent failure for " + packageName + " with illegal key " + key + ", dropped");
+        }
+    }
+
+    void onReadAgentDataError(String packageName, IOException e) {
+        Slog.w(TAG, "Unable read backup data for " + packageName + ": " + e);
+    }
+
+    void onWriteWidgetDataError(String packageName, IOException e) {
+        Slog.w(TAG, "Unable to save widget data for " + packageName + ": " + e);
+    }
+
+    void onDigestError(NoSuchAlgorithmException e) {
+        Slog.e(TAG, "Unable to use SHA-1!");
+    }
+
+    void onWriteWidgetData(boolean priorStateExists, @Nullable byte[] widgetState) {
+        if (MORE_DEBUG) {
+            Slog.i(
+                    TAG,
+                    "Checking widget update: state="
+                            + (widgetState != null)
+                            + " prior="
+                            + priorStateExists);
+        }
+    }
+
+    void onTruncateDataError() {
+        Slog.w(TAG, "Unable to roll back");
+    }
+
+    void onSendDataToTransport(String packageName) {
+        if (MORE_DEBUG) {
+            Slog.v(TAG, "Sending non-empty data to transport for " + packageName);
+        }
+    }
+
+    void onNonIncrementalAndNonIncrementalRequired() {
+        Slog.e(TAG, "Transport requested non-incremental but already the case");
+    }
+
+    void onEmptyData(PackageInfo packageInfo) {
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "No backup data written, not calling transport");
+        }
+        mMonitor =
+                BackupManagerMonitorUtils.monitorEvent(
+                        mMonitor,
+                        BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
+                        packageInfo,
+                        BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+                        null);
+    }
+
+    void onPackageBackupComplete(String packageName, long size) {
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.SUCCESS);
+        EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, packageName, size);
+        mBackupManagerService.logBackupComplete(packageName);
+    }
+
+    void onPackageBackupRejected(String packageName) {
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        EventLogTags.writeBackupAgentFailure(packageName, "Transport rejected");
+    }
+
+    void onPackageBackupQuotaExceeded(String packageName) {
+        if (MORE_DEBUG) {
+            Slog.d(TAG, "Package " + packageName + " hit quota limit on key-value backup");
+        }
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+        EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, packageName);
+    }
+
+    void onAgentDoQuotaExceededError(Exception e) {
+        Slog.e(TAG, "Unable to notify about quota exceeded: " + e);
+    }
+
+    void onPackageBackupNonIncrementalRequired(PackageInfo packageInfo) {
+        Slog.i(TAG, "Transport lost data, retrying package");
+        BackupManagerMonitorUtils.monitorEvent(
+                mMonitor,
+                BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED,
+                packageInfo,
+                BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+                /* extras */ null);
+    }
+
+    void onPackageBackupTransportFailure(String packageName) {
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
+        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
+    }
+
+    void onPackageBackupError(String packageName, Exception e) {
+        Slog.e(TAG, "Transport error backing up " + packageName, e);
+        BackupObserverUtils.sendBackupOnPackageResult(
+                mObserver, packageName, BackupManager.ERROR_TRANSPORT_ABORTED);
+        EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, packageName);
+    }
+
+    void onCloseFileDescriptorError(String logName) {
+        Slog.w(TAG, "Error closing " + logName + " file-descriptor");
+    }
+
+    void onCancel() {
+        if (MORE_DEBUG) {
+            Slog.v(TAG, "Cancel received");
+        }
+    }
+
+    void onAgentTimedOut(@Nullable PackageInfo packageInfo) {
+        String packageName = getPackageName(packageInfo);
+        Slog.i(TAG, "Agent " + packageName + " timed out");
+        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
+        // Time-out used to be implemented as cancel w/ cancelAll = false.
+        // TODO: Change monitoring event to reflect time-out as an event itself.
+        mMonitor =
+                BackupManagerMonitorUtils.monitorEvent(
+                        mMonitor,
+                        BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
+                        packageInfo,
+                        BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+                        BackupManagerMonitorUtils.putMonitoringExtra(
+                                null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false));
+    }
+
+    void onAgentCancelled(@Nullable PackageInfo packageInfo) {
+        String packageName = getPackageName(packageInfo);
+        Slog.i(TAG, "Cancel backing up " + packageName);
+        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
+        mMonitor =
+                BackupManagerMonitorUtils.monitorEvent(
+                        mMonitor,
+                        BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
+                        packageInfo,
+                        BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+                        BackupManagerMonitorUtils.putMonitoringExtra(
+                                null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true));
+    }
+
+    private String getPackageName(@Nullable PackageInfo packageInfo) {
+        return (packageInfo != null) ? packageInfo.packageName : "no_package_yet";
+    }
+
+    void onRevertBackup() {
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "Reverting backup queue, re-staging everything");
+        }
+    }
+
+    void onTransportRequestBackupTimeError(Exception e) {
+        Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e);
+    }
+
+    void onRemoteCallReturned(RemoteResult result) {
+        if (MORE_DEBUG) {
+            Slog.v(TAG, "Agent call returned " + result);
+        }
+    }
+
+    void onJournalDeleteFailed(DataChangedJournal journal) {
+        Slog.e(TAG, "Unable to remove backup journal file " + journal);
+    }
+
+    void onSetCurrentTokenError(Exception e) {
+        Slog.e(TAG, "Transport threw reporting restore set: " + e);
+    }
+
+    void onTransportNotInitialized() {
+        if (MORE_DEBUG) {
+            Slog.d(TAG, "Transport requires initialization, rerunning");
+        }
+    }
+
+    void onPendingInitializeTransportError(Exception e) {
+        Slog.w(TAG, "Failed to query transport name for pending init: " + e);
+    }
+
+    void onBackupFinished(int status) {
+        BackupObserverUtils.sendBackupFinished(mObserver, status);
+    }
+
+    void onStartFullBackup(List<String> pendingFullBackups) {
+        Slog.d(TAG, "Starting full backups for: " + pendingFullBackups);
+    }
+
+    void onKeyValueBackupFinished() {
+        Slog.i(TAG, "K/V backup pass finished");
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 1cb9933..41013aa 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -16,7 +16,11 @@
 
 package com.android.server.backup.keyvalue;
 
-import static com.android.server.backup.BackupManagerService.DEBUG_BACKUP_TRACE;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+
 import static com.android.server.backup.BackupManagerService.KEY_WIDGET_STATE;
 import static com.android.server.backup.BackupManagerService.OP_PENDING;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
@@ -29,7 +33,6 @@
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupManager;
-import android.app.backup.BackupManagerMonitor;
 import android.app.backup.BackupTransport;
 import android.app.backup.IBackupCallback;
 import android.app.backup.IBackupManager;
@@ -47,7 +50,6 @@
 import android.os.WorkSource;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.util.EventLog;
 import android.util.Pair;
 import android.util.Slog;
 
@@ -55,12 +57,12 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
-import com.android.server.EventLogTags;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
+import com.android.server.backup.TransportManager;
 import com.android.server.backup.fullbackup.PerformFullTransportBackupTask;
 import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.internal.Operation;
@@ -69,9 +71,8 @@
 import com.android.server.backup.remote.RemoteResult;
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.backup.utils.AppBackupUtils;
-import com.android.server.backup.utils.BackupManagerMonitorUtils;
-import com.android.server.backup.utils.BackupObserverUtils;
 
+import java.io.Closeable;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
@@ -172,7 +173,7 @@
 // TODO: Distinguish between cancel and time-out where possible for logging/monitoring/observing
 public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
     private static final String TAG = "KeyValueBackupTask";
-    private static final boolean DEBUG = BackupManagerService.DEBUG || true;
+    private static final boolean DEBUG = BackupManagerService.DEBUG;
     private static final boolean MORE_DEBUG = BackupManagerService.MORE_DEBUG || false;
     private static final int THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND;
     private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
@@ -212,8 +213,8 @@
             List<BackupRequest> queue,
             @Nullable DataChangedJournal dataChangedJournal,
             IBackupObserver observer,
-            IBackupManagerMonitor monitor,
-            @Nullable OnTaskFinishedListener listener,
+            @Nullable IBackupManagerMonitor monitor,
+            OnTaskFinishedListener listener,
             List<String> pendingFullBackups,
             boolean userInitiated,
             boolean nonIncremental) {
@@ -239,10 +240,13 @@
     }
 
     private final BackupManagerService mBackupManagerService;
+    private final PackageManager mPackageManager;
+    private final TransportManager mTransportManager;
     private final TransportClient mTransportClient;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final IBackupObserver mObserver;
-    private final OnTaskFinishedListener mListener;
+    private final KeyValueBackupReporter mReporter;
+    private final OnTaskFinishedListener mTaskFinishedListener;
     private final boolean mUserInitiated;
     private final boolean mNonIncremental;
     private final int mCurrentOpToken;
@@ -251,7 +255,6 @@
     private final List<BackupRequest> mQueue;
     private final List<String> mPendingFullBackups;
     @Nullable private final DataChangedJournal mJournal;
-    private IBackupManagerMonitor mMonitor;
     @Nullable private PerformFullTransportBackupTask mFullBackupTask;
 
     private IBackupAgent mAgentBinder;
@@ -294,20 +297,22 @@
             List<BackupRequest> queue,
             @Nullable DataChangedJournal journal,
             IBackupObserver observer,
-            IBackupManagerMonitor monitor,
-            @Nullable OnTaskFinishedListener listener,
+            @Nullable IBackupManagerMonitor monitor,
+            OnTaskFinishedListener taskFinishedListener,
             List<String> pendingFullBackups,
             boolean userInitiated,
             boolean nonIncremental) {
         mBackupManagerService = backupManagerService;
+        mTransportManager = backupManagerService.getTransportManager();
+        mPackageManager = backupManagerService.getPackageManager();
         mTransportClient = transportClient;
         mOriginalQueue = queue;
         // We need to retain the original queue contents in case of transport failure
-        mQueue = new ArrayList<>(mOriginalQueue);
+        mQueue = new ArrayList<>(queue);
         mJournal = journal;
         mObserver = observer;
-        mMonitor = monitor;
-        mListener = (listener != null) ? listener : OnTaskFinishedListener.NOP;
+        mReporter = new KeyValueBackupReporter(backupManagerService, observer, monitor);
+        mTaskFinishedListener = taskFinishedListener;
         mPendingFullBackups = pendingFullBackups;
         mUserInitiated = userInitiated;
         mNonIncremental = nonIncremental;
@@ -332,7 +337,7 @@
     public void run() {
         Process.setThreadPriority(THREAD_PRIORITY);
 
-        BackupState state = beginBackup();
+        BackupState state = startBackup();
         while (state == BackupState.RUNNING_QUEUE || state == BackupState.BACKUP_PM) {
             if (mCancelled) {
                 state = BackupState.CANCELLED;
@@ -342,24 +347,24 @@
                     state = backupPm();
                     break;
                 case RUNNING_QUEUE:
-                    Pair<BackupState, RemoteResult> stateAndResult = invokeNextAgent();
+                    Pair<BackupState, RemoteResult> stateAndResult = extractNextAgentData();
                     state = stateAndResult.first;
                     if (state == null) {
-                        state = processAgentInvocation(stateAndResult.second);
+                        state = handleAgentResult(stateAndResult.second);
                     }
                     break;
             }
         }
         if (state == BackupState.CANCELLED) {
-            finalizeCancelledBackup();
+            finishCancelledBackup();
         } else {
-            finalizeBackup();
+            finishBackup();
         }
     }
 
-    private BackupState processAgentInvocation(RemoteResult result) {
+    private BackupState handleAgentResult(RemoteResult result) {
         if (result == RemoteResult.FAILED_THREAD_INTERRUPTED) {
-            // Not an explicit cancel, we need to flag it
+            // Not an explicit cancel, we need to flag it.
             mCancelled = true;
             handleAgentCancelled();
             return BackupState.CANCELLED;
@@ -373,7 +378,7 @@
             return BackupState.RUNNING_QUEUE;
         }
         Preconditions.checkState(result.succeeded());
-        return handleAgentResult(result.get());
+        return sendDataToTransport(result.get());
     }
 
     @Override
@@ -382,24 +387,10 @@
     @Override
     public void operationComplete(long unusedResult) {}
 
-    private BackupState beginBackup() {
-        if (DEBUG_BACKUP_TRACE) {
-            mBackupManagerService.clearBackupTrace();
-            StringBuilder b = new StringBuilder(256);
-            b.append("beginBackup: [");
-            for (BackupRequest req : mOriginalQueue) {
-                b.append(' ');
-                b.append(req.packageName);
-            }
-            b.append(" ]");
-            mBackupManagerService.addBackupTrace(b.toString());
-        }
+    private BackupState startBackup() {
         synchronized (mBackupManagerService.getCurrentOpLock()) {
             if (mBackupManagerService.isBackupOperationInProgress()) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Skipping backup since one is already in progress");
-                }
-                mBackupManagerService.addBackupTrace("Skipped. Backup already in progress.");
+                mReporter.onSkipBackup();
                 return BackupState.FINAL;
             }
         }
@@ -415,19 +406,17 @@
                         /* runningJob */ null,
                         new CountDownLatch(1),
                         mObserver,
-                        mMonitor,
-                        mListener,
+                        mReporter.getMonitor(),
+                        mTaskFinishedListener,
                         mUserInitiated);
         registerTask();
-        mBackupManagerService.addBackupTrace("STATE => INITIAL");
 
         mAgentBinder = null;
         mStatus = BackupTransport.TRANSPORT_OK;
 
         // Sanity check: if the queue is empty we have no work to do.
         if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
-            Slog.w(TAG, "Backup begun with an empty queue, nothing to do.");
-            mBackupManagerService.addBackupTrace("queue empty at begin");
+            mReporter.onEmptyQueueAtStart();
             return BackupState.FINAL;
         }
 
@@ -441,55 +430,39 @@
         // we're committed to evaluating it for backup regardless.
         for (int i = 0; i < mQueue.size(); i++) {
             if (PACKAGE_MANAGER_SENTINEL.equals(mQueue.get(i).packageName)) {
-                if (MORE_DEBUG) {
-                    Slog.i(TAG, "PM metadata in queue, removing");
-                }
+                mReporter.onPmFoundInQueue();
                 mQueue.remove(i);
                 skipPm = false;
                 break;
             }
         }
+        mReporter.onQueueReady(mQueue);
 
-        if (DEBUG) {
-            Slog.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
-        }
         File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
         try {
-            IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.beginBackup()");
+            IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.startBackup()");
             String transportName = transport.name();
-            EventLog.writeEvent(EventLogTags.BACKUP_START, transportName);
+            mReporter.onTransportReady(transportName);
 
-            // If we haven't stored package manager metadata yet, we must init the transport.
+            // If we haven't stored PM metadata yet, we must initialize the transport.
             if (pmState.length() <= 0) {
-                Slog.i(TAG, "Initializing transport and resetting backup state");
-                mBackupManagerService.addBackupTrace("initializing transport " + transportName);
-                mBackupManagerService.resetBackupState(mStateDir);  // Just to make sure.
+                mReporter.onInitializeTransport(transportName);
+                mBackupManagerService.resetBackupState(mStateDir);
                 mStatus = transport.initializeDevice();
-
-                mBackupManagerService.addBackupTrace("transport.initializeDevice() == " + mStatus);
-                if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    EventLog.writeEvent(EventLogTags.BACKUP_INITIALIZE);
-                } else {
-                    EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
-                    Slog.e(TAG, "Transport error in initializeDevice()");
-                }
+                mReporter.onTransportInitialized(mStatus);
             }
         } catch (Exception e) {
-            Slog.e(TAG, "Error during initialization", e);
-            mBackupManagerService.addBackupTrace("Exception in backup thread during init: " + e);
+            mReporter.onInitializeTransportError(e);
             mStatus = BackupTransport.TRANSPORT_ERROR;
         }
-        mBackupManagerService.addBackupTrace("exiting prelim: " + mStatus);
 
         if (mStatus != BackupTransport.TRANSPORT_OK) {
-            // if things went wrong at this point, we need to
-            // restage everything and try again later.
-            mBackupManagerService.resetBackupState(mStateDir);  // Just to make sure.
+            mBackupManagerService.resetBackupState(mStateDir);
             return BackupState.FINAL;
         }
 
         if (skipPm) {
-            Slog.d(TAG, "Skipping backup of PM metadata");
+            mReporter.onSkipPm();
             return BackupState.RUNNING_QUEUE;
         }
 
@@ -498,38 +471,27 @@
 
     private BackupState backupPm() {
         RemoteResult agentResult = null;
-        BackupState nextState;
         try {
-            // The package manager doesn't have a proper <application> etc, but since it's running
-            // here in the system process we can just set up its agent directly and use a synthetic
-            // BackupRequest.
+            // Since PM is running in the system process we can set up its agent directly.
             BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
             Pair<Integer, RemoteResult> statusAndResult =
-                    invokeAgentForBackup(
+                    extractAgentData(
                             PACKAGE_MANAGER_SENTINEL,
                             IBackupAgent.Stub.asInterface(pmAgent.onBind()));
             mStatus = statusAndResult.first;
             agentResult = statusAndResult.second;
-
-            mBackupManagerService.addBackupTrace("PM agent invoke: " + mStatus);
         } catch (Exception e) {
-            Slog.e(TAG, "Error during PM metadata backup", e);
-            mBackupManagerService.addBackupTrace("Exception in backup thread during pm: " + e);
+            mReporter.onInvokePmAgentError(e);
             mStatus = BackupTransport.TRANSPORT_ERROR;
         }
-        mBackupManagerService.addBackupTrace("exiting backupPm: " + mStatus);
 
-        if (mStatus == BackupTransport.TRANSPORT_OK) {
-            Preconditions.checkNotNull(agentResult);
-            nextState = processAgentInvocation(agentResult);
-        } else {
-            // if things went wrong at this point, we need to
-            // restage everything and try again later.
-            mBackupManagerService.resetBackupState(mStateDir);  // Just to make sure.
-            nextState = BackupState.FINAL;
+        if (mStatus != BackupTransport.TRANSPORT_OK) {
+            mBackupManagerService.resetBackupState(mStateDir);
+            return BackupState.FINAL;
         }
 
-        return nextState;
+        Preconditions.checkNotNull(agentResult);
+        return handleAgentResult(agentResult);
     }
 
     /**
@@ -540,250 +502,183 @@
      *   <li>({@code null}, agent result): In case we successfully called the agent.
      * </ul>
      */
-    private Pair<BackupState, RemoteResult> invokeNextAgent() {
+    private Pair<BackupState, RemoteResult> extractNextAgentData() {
         mStatus = BackupTransport.TRANSPORT_OK;
-        mBackupManagerService.addBackupTrace("invoke q=" + mQueue.size());
 
-        // Sanity check that we have work to do.  If not, skip to the end where
-        // we reestablish the wakelock invariants etc.
         if (mQueue.isEmpty()) {
-            if (MORE_DEBUG) {
-                Slog.i(TAG, "Queue now empty");
-            }
+            mReporter.onEmptyQueue();
             return Pair.create(BackupState.FINAL, null);
         }
 
-        // pop the entry we're going to process on this step
         BackupRequest request = mQueue.remove(0);
+        String packageName = request.packageName;
+        mReporter.onStartPackageBackup(packageName);
 
-        Slog.d(TAG, "Starting key-value backup of " + request);
-        mBackupManagerService.addBackupTrace("launch agent for " + request.packageName);
-
-        // Verify that the requested app exists; it might be something that
-        // requested a backup but was then uninstalled.  The request was
-        // journalled and rather than tamper with the journal it's safer
-        // to sanity-check here.  This also gives us the classname of the
-        // package's backup agent.
+        // Verify that the requested app is eligible for key-value backup.
         RemoteResult agentResult = null;
         try {
-            PackageManager pm = mBackupManagerService.getPackageManager();
-            mCurrentPackage = pm.getPackageInfo(request.packageName,
-                    PackageManager.GET_SIGNING_CERTIFICATES);
-            if (!AppBackupUtils.appIsEligibleForBackup(mCurrentPackage.applicationInfo, pm)) {
-                // The manifest has changed but we had a stale backup request pending. This won't
-                // happen again because the app won't be requesting further backups.
-                Slog.i(TAG, "Package " + request.packageName
-                        + " no longer supports backup, skipping");
-                mBackupManagerService.addBackupTrace("skipping - not eligible, completion is noop");
-                // Shouldn't happen in case of requested backup, as pre-check was done in
-                // #requestBackup(), except to app update done concurrently
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver,
-                        mCurrentPackage.packageName,
-                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+            mCurrentPackage = mPackageManager.getPackageInfo(
+                    request.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+            ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
+            if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
+                // The manifest has changed. This won't happen again because the app won't be
+                // requesting further backups.
+                mReporter.onPackageNotEligibleForBackup(packageName);
                 return Pair.create(BackupState.RUNNING_QUEUE, null);
             }
 
             if (AppBackupUtils.appGetsFullBackup(mCurrentPackage)) {
-                // It's possible that this app *formerly* was enqueued for key-value backup, but has
-                // since been updated and now only supports the full-backup path. Don't proceed with
-                // a key-value backup for it in this case.
-                Slog.i(TAG, "Package " + request.packageName
-                        + " performs full-backup rather than key-value, skipping");
-                mBackupManagerService.addBackupTrace(
-                        "skipping - fullBackupOnly, completion is noop");
-                // Shouldn't happen in case of requested backup, as pre-check was done in
-                // #requestBackup()
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver,
-                        mCurrentPackage.packageName,
-                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                // Initially enqueued for key-value backup, but only supports full-backup now.
+                mReporter.onPackageEligibleForFullBackup(packageName);
                 return Pair.create(BackupState.RUNNING_QUEUE, null);
             }
 
-            if (AppBackupUtils.appIsStopped(mCurrentPackage.applicationInfo)) {
-                // The app has been force-stopped or cleared or just installed,
-                // and not yet launched out of that state, so just as it won't
-                // receive broadcasts, we won't run it for backup.
-                mBackupManagerService.addBackupTrace("skipping - stopped");
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver,
-                        mCurrentPackage.packageName,
-                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+            if (AppBackupUtils.appIsStopped(applicationInfo)) {
+                // Just as it won't receive broadcasts, we won't run it for backup.
+                mReporter.onPackageStopped(packageName);
                 return Pair.create(BackupState.RUNNING_QUEUE, null);
             }
 
             try {
-                mBackupManagerService.setWorkSource(
-                        new WorkSource(mCurrentPackage.applicationInfo.uid));
+                mBackupManagerService.setWorkSource(new WorkSource(applicationInfo.uid));
                 IBackupAgent agent =
                         mBackupManagerService.bindToAgentSynchronous(
-                                mCurrentPackage.applicationInfo,
+                                applicationInfo,
                                 ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
-                mBackupManagerService.addBackupTrace("agent bound; a? = " + (agent != null));
                 if (agent != null) {
                     mAgentBinder = agent;
                     Pair<Integer, RemoteResult> statusAndResult =
-                            invokeAgentForBackup(request.packageName, agent);
+                            extractAgentData(request.packageName, agent);
                     mStatus = statusAndResult.first;
                     agentResult = statusAndResult.second;
                 } else {
-                    // Timeout waiting for the agent
+                    // Timeout waiting for the agent to bind.
                     mStatus = BackupTransport.AGENT_ERROR;
                 }
-            } catch (SecurityException se) {
-                // Try for the next one.
-                Slog.d(TAG, "Error in bind/backup", se);
+            } catch (SecurityException e) {
+                mReporter.onBindAgentError(e);
                 mStatus = BackupTransport.AGENT_ERROR;
-                mBackupManagerService.addBackupTrace("agent SE");
             }
         } catch (PackageManager.NameNotFoundException e) {
-            Slog.d(TAG, "Package does not exist, skipping");
-            mBackupManagerService.addBackupTrace("no such package");
             mStatus = BackupTransport.AGENT_UNKNOWN;
         } finally {
             mBackupManagerService.setWorkSource(null);
         }
 
         if (mStatus != BackupTransport.TRANSPORT_OK) {
-            BackupState nextState = BackupState.RUNNING_QUEUE;
             mAgentBinder = null;
 
-            // An agent-level failure means we re-enqueue this one agent for
-            // a later retry, but otherwise proceed normally.
             if (mStatus == BackupTransport.AGENT_ERROR) {
-                if (MORE_DEBUG) {
-                    Slog.i(TAG, "Agent failure for " + request.packageName + ", re-staging");
-                }
+                mReporter.onAgentError(packageName);
                 mBackupManagerService.dataChangedImpl(request.packageName);
                 mStatus = BackupTransport.TRANSPORT_OK;
-                BackupObserverUtils
-                        .sendBackupOnPackageResult(mObserver, mCurrentPackage.packageName,
-                                BackupManager.ERROR_AGENT_FAILURE);
-            } else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
-                // Failed lookup of the app, so we couldn't bring up an agent, but
-                // we're otherwise fine.  Just drop it and go on to the next as usual.
-                mStatus = BackupTransport.TRANSPORT_OK;
-                BackupObserverUtils
-                        .sendBackupOnPackageResult(mObserver, request.packageName,
-                                BackupManager.ERROR_PACKAGE_NOT_FOUND);
-            } else {
-                // Transport-level failure means we re-enqueue everything
-                revertAndEndBackup();
-                nextState = BackupState.FINAL;
+                return Pair.create(BackupState.RUNNING_QUEUE, null);
             }
 
-            return Pair.create(nextState, null);
+            if (mStatus == BackupTransport.AGENT_UNKNOWN) {
+                mReporter.onAgentUnknown(packageName);
+                mStatus = BackupTransport.TRANSPORT_OK;
+                return Pair.create(BackupState.RUNNING_QUEUE, null);
+            }
+
+            // Transport-level failure, re-enqueue everything.
+            revertBackup();
+            return Pair.create(BackupState.FINAL, null);
         }
 
         // Success: caller will figure out the state based on call result
-        mBackupManagerService.addBackupTrace("call made; result = " + agentResult);
         return Pair.create(null, agentResult);
     }
 
-    private void finalizeBackup() {
-        mBackupManagerService.addBackupTrace("finishing");
-
-        // Mark packages that we didn't backup (because backup was cancelled, etc.) as needing
-        // backup.
-        for (BackupRequest req : mQueue) {
-            mBackupManagerService.dataChangedImpl(req.packageName);
+    private void finishBackup() {
+        // Mark packages that we couldn't backup as pending backup.
+        for (BackupRequest request : mQueue) {
+            mBackupManagerService.dataChangedImpl(request.packageName);
         }
 
-        // Either backup was successful, in which case we of course do not need
-        // this pass's journal any more; or it failed, in which case we just
-        // re-enqueued all of these packages in the current active journal.
-        // Either way, we no longer need this pass's journal.
+        // If backup succeeded, we just invalidated this journal. If not, we've already re-enqueued
+        // the packages and also don't need the journal.
         if (mJournal != null && !mJournal.delete()) {
-            Slog.e(TAG, "Unable to remove backup journal file " + mJournal);
+            mReporter.onJournalDeleteFailed(mJournal);
         }
 
-        // If everything actually went through and this is the first time we've
-        // done a backup, we can now record what the current backup dataset token
-        // is.
-        String callerLogString = "KVBT.finalizeBackup()";
-        if ((mBackupManagerService.getCurrentToken() == 0) && (mStatus
-                == BackupTransport.TRANSPORT_OK)) {
-            mBackupManagerService.addBackupTrace("success; recording token");
+        String callerLogString = "KVBT.finishBackup()";
+
+        // If we succeeded and this is the first time we've done a backup, we can record the current
+        // backup dataset token.
+        long currentToken = mBackupManagerService.getCurrentToken();
+        if ((mStatus == BackupTransport.TRANSPORT_OK) && (currentToken == 0)) {
             try {
                 IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
                 mBackupManagerService.setCurrentToken(transport.getCurrentRestoreSet());
                 mBackupManagerService.writeRestoreTokens();
             } catch (Exception e) {
-                // nothing for it at this point, unfortunately, but this will be
-                // recorded the next time we fully succeed.
-                Slog.e(TAG, "Transport threw reporting restore set: " + e);
-                mBackupManagerService.addBackupTrace("transport threw returning token");
+                // This will be recorded the next time we succeed.
+                mReporter.onSetCurrentTokenError(e);
             }
         }
 
-        // Set up the next backup pass - at this point we can set mBackupRunning
-        // to false to allow another pass to fire
         synchronized (mBackupManagerService.getQueueLock()) {
             mBackupManagerService.setBackupRunning(false);
             if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
-                if (MORE_DEBUG) {
-                    Slog.d(TAG, "Transport requires initialization, rerunning");
-                }
-                mBackupManagerService.addBackupTrace("init required; rerunning");
+                mReporter.onTransportNotInitialized();
                 try {
-                    String name = mBackupManagerService.getTransportManager()
-                            .getTransportName(mTransportClient.getTransportComponent());
-                    mBackupManagerService.getPendingInits().add(name);
+                    IBackupTransport transport = mTransportClient.connectOrThrow(callerLogString);
+                    mBackupManagerService.getPendingInits().add(transport.name());
+                    clearPmMetadata();
+                    mBackupManagerService.backupNow();
                 } catch (Exception e) {
-                    Slog.w(TAG, "Failed to query transport name for init: " + e);
-                    // swallow it and proceed; we don't rely on this
+                    mReporter.onPendingInitializeTransportError(e);
                 }
-                clearMetadata();
-                mBackupManagerService.backupNow();
             }
         }
 
-        mBackupManagerService.clearBackupTrace();
-
         unregisterTask();
+        mReporter.onKeyValueBackupFinished();
 
-        if (!mCancelled && mStatus == BackupTransport.TRANSPORT_OK &&
-                mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
-            Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
-            // Acquiring wakelock for PerformFullTransportBackupTask before its start.
-            mBackupManagerService.getWakelock().acquire();
-            // The full-backup task is now responsible for calling onFinish() on mListener, which
-            // was the listener we passed it.
+        if (!mCancelled
+                && mStatus == BackupTransport.TRANSPORT_OK
+                && mFullBackupTask != null
+                && !mPendingFullBackups.isEmpty()) {
+            mReporter.onStartFullBackup(mPendingFullBackups);
+            // The key-value backup has finished but not the overall backup. Full-backup task will:
+            // * Call mObserver.backupFinished() (which is called by mReporter below).
+            // * Call mTaskFinishedListener.onFinished().
+            // * Release the wakelock.
             (new Thread(mFullBackupTask, "full-transport-requested")).start();
-        } else if (mCancelled) {
-            mListener.onFinished(callerLogString);
-            if (mFullBackupTask != null) {
-                mFullBackupTask.unregisterTask();
-            }
-            BackupObserverUtils.sendBackupFinished(mObserver, BackupManager.ERROR_BACKUP_CANCELLED);
-        } else {
-            mListener.onFinished(callerLogString);
-            if (mFullBackupTask != null) {
-                mFullBackupTask.unregisterTask();
-            }
-            switch (mStatus) {
-                case BackupTransport.TRANSPORT_OK:
-                case BackupTransport.TRANSPORT_QUOTA_EXCEEDED:
-                case BackupTransport.TRANSPORT_PACKAGE_REJECTED:
-                    BackupObserverUtils.sendBackupFinished(mObserver, BackupManager.SUCCESS);
-                    break;
-                case BackupTransport.TRANSPORT_NOT_INITIALIZED:
-                    BackupObserverUtils.sendBackupFinished(mObserver,
-                            BackupManager.ERROR_TRANSPORT_ABORTED);
-                    break;
-                case BackupTransport.TRANSPORT_ERROR:
-                default:
-                    BackupObserverUtils.sendBackupFinished(mObserver,
-                            BackupManager.ERROR_TRANSPORT_ABORTED);
-                    break;
-            }
+            return;
         }
-        Slog.i(TAG, "K/V backup pass finished");
+
+        if (mFullBackupTask != null) {
+            mFullBackupTask.unregisterTask();
+        }
+        mTaskFinishedListener.onFinished(callerLogString);
+        mReporter.onBackupFinished(getBackupFinishedStatus(mCancelled, mStatus));
         mBackupManagerService.getWakelock().release();
     }
 
-    // Remove the PM metadata state. This will generate an init on the next pass.
-    private void clearMetadata() {
-        final File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
-        if (pmState.exists()) pmState.delete();
+    private int getBackupFinishedStatus(boolean cancelled, int transportStatus) {
+        if (cancelled) {
+            return BackupManager.ERROR_BACKUP_CANCELLED;
+        }
+        switch (transportStatus) {
+            case BackupTransport.TRANSPORT_OK:
+            case BackupTransport.TRANSPORT_QUOTA_EXCEEDED:
+            case BackupTransport.TRANSPORT_PACKAGE_REJECTED:
+                return BackupManager.SUCCESS;
+            case BackupTransport.TRANSPORT_NOT_INITIALIZED:
+            case BackupTransport.TRANSPORT_ERROR:
+            default:
+                return BackupManager.ERROR_TRANSPORT_ABORTED;
+        }
+    }
+
+    /** Removes PM state, triggering initialization in the next key-value task. */
+    private void clearPmMetadata() {
+        File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
+        if (pmState.exists()) {
+            pmState.delete();
+        }
     }
 
     /**
@@ -791,22 +686,16 @@
      * {@link BackupTransport#TRANSPORT_OK}, the second of the pair contains the agent result,
      * otherwise {@code null}.
      */
-    private Pair<Integer, RemoteResult> invokeAgentForBackup(
-            String packageName, IBackupAgent agent) {
-        if (DEBUG) {
-            Slog.d(TAG, "Invoking agent on " + packageName);
-        }
-        mBackupManagerService.addBackupTrace("invoking " + packageName);
+    private Pair<Integer, RemoteResult> extractAgentData(String packageName, IBackupAgent agent) {
+        mReporter.onInvokeAgent(packageName);
 
         File blankStateFile = new File(mStateDir, BLANK_STATE_FILE_NAME);
         mSavedStateFile = new File(mStateDir, packageName);
+        File savedStateFileForAgent = (mNonIncremental) ? blankStateFile : mSavedStateFile;
         mBackupDataFile =
                 new File(mBackupManagerService.getDataDir(), packageName + STAGING_FILE_SUFFIX);
         mNewStateFile = new File(mStateDir, packageName + NEW_STATE_FILE_SUFFIX);
-        if (MORE_DEBUG) {
-            Slog.d(TAG, "Data file: " + mBackupDataFile);
-        }
-
+        mReporter.onAgentFilesReady(mBackupDataFile);
 
         mSavedState = null;
         mBackupData = null;
@@ -815,46 +704,31 @@
         boolean callingAgent = false;
         final RemoteResult agentResult;
         try {
-            // Look up the package info & signatures.  This is first so that if it
-            // throws an exception, there's no file setup yet that would need to
-            // be unraveled.
+            // TODO: Move this to backupPm()
             if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
-                // The metadata 'package' is synthetic; construct one and make
-                // sure our global state is pointed at it
                 mCurrentPackage = new PackageInfo();
                 mCurrentPackage.packageName = packageName;
             }
 
+            // MODE_CREATE to make an empty file if necessary
             mSavedState = ParcelFileDescriptor.open(
-                    (mNonIncremental) ? blankStateFile : mSavedStateFile,
-                    ParcelFileDescriptor.MODE_READ_ONLY |
-                            ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
-
-            mBackupData = ParcelFileDescriptor.open(mBackupDataFile,
-                    ParcelFileDescriptor.MODE_READ_WRITE |
-                            ParcelFileDescriptor.MODE_CREATE |
-                            ParcelFileDescriptor.MODE_TRUNCATE);
+                    savedStateFileForAgent, MODE_READ_ONLY | MODE_CREATE);
+            mBackupData = ParcelFileDescriptor.open(
+                    mBackupDataFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+            mNewState = ParcelFileDescriptor.open(
+                    mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
 
             if (!SELinux.restorecon(mBackupDataFile)) {
-                Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataFile);
+                mReporter.onRestoreconFailed(mBackupDataFile);
             }
 
-            mNewState = ParcelFileDescriptor.open(mNewStateFile,
-                    ParcelFileDescriptor.MODE_READ_WRITE |
-                            ParcelFileDescriptor.MODE_CREATE |
-                            ParcelFileDescriptor.MODE_TRUNCATE);
-
-            IBackupTransport transport =
-                    mTransportClient.connectOrThrow("KVBT.invokeAgentForBackup()");
-
-            final long quota = transport.getBackupQuota(packageName, false /* isFullBackup */);
-            callingAgent = true;
-
-            // Initiate the target's backup pass
+            IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()");
+            long quota = transport.getBackupQuota(packageName, /* isFullBackup */ false);
+            int transportFlags = transport.getTransportFlags();
             long kvBackupAgentTimeoutMillis =
                     mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
-            mBackupManagerService.addBackupTrace("calling agent doBackup()");
 
+            callingAgent = true;
             agentResult =
                     remoteCall(
                             callback ->
@@ -864,22 +738,19 @@
                                             mNewState,
                                             quota,
                                             callback,
-                                            transport.getTransportFlags()),
+                                            transportFlags),
                             kvBackupAgentTimeoutMillis);
         } catch (Exception e) {
-            Slog.e(TAG, "Error invoking agent on " + packageName + ": " + e);
-            mBackupManagerService.addBackupTrace("exception: " + e);
-            EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName, e.toString());
+            mReporter.onCallAgentDoBackupError(packageName, callingAgent, e);
             errorCleanup();
+            // TODO: Remove the check on callingAgent when RemoteCall supports local agent calls.
             int status =
                     callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR;
             return Pair.create(status, null);
-        } finally {
-            if (mNonIncremental) {
-                blankStateFile.delete();
-            }
         }
-
+        if (mNonIncremental) {
+            blankStateFile.delete();
+        }
         return Pair.create(BackupTransport.TRANSPORT_OK, agentResult);
     }
 
@@ -887,7 +758,7 @@
         try {
             agent.fail(message);
         } catch (Exception e) {
-            Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
+            mReporter.onFailAgentError(mCurrentPackage.packageName);
         }
     }
 
@@ -898,36 +769,27 @@
             MessageDigest md = MessageDigest.getInstance("SHA-1");
             checksum = md.digest(input);
         } catch (NoSuchAlgorithmException e) {
-            Slog.e(TAG, "Unable to use SHA-1!");
+            mReporter.onDigestError(e);
             return "00";
         }
 
-        StringBuffer sb = new StringBuffer(checksum.length * 2);
+        StringBuilder string = new StringBuilder(checksum.length * 2);
         for (byte item : checksum) {
-            sb.append(Integer.toHexString(item));
+            string.append(Integer.toHexString(item));
         }
-        return sb.toString();
+        return string.toString();
     }
 
     private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
             throws IOException {
         // TODO: http://b/22388012
         byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, UserHandle.USER_SYSTEM);
-        // has the widget state changed since last time?
-        final File widgetFile = new File(mStateDir, pkgName + "_widget");
-        final boolean priorStateExists = widgetFile.exists();
-
-        if (MORE_DEBUG) {
-            if (priorStateExists || widgetState != null) {
-                Slog.i(TAG, "Checking widget update: state=" + (widgetState != null)
-                        + " prior=" + priorStateExists);
-            }
-        }
-
+        File widgetFile = new File(mStateDir, pkgName + "_widget");
+        boolean priorStateExists = widgetFile.exists();
         if (!priorStateExists && widgetState == null) {
-            // no prior state, no new state => nothing to do
             return;
         }
+        mReporter.onWriteWidgetData(priorStateExists, widgetState);
 
         // if the new state is not null, we might need to compare checksums to
         // determine whether to update the widget blob in the archive.  If the
@@ -969,93 +831,67 @@
         }
     }
 
-    private BackupState handleAgentResult(long unusedResult) {
+    private BackupState sendDataToTransport(long agentResult) {
         Preconditions.checkState(mBackupData != null);
 
-        final String pkgName = mCurrentPackage.packageName;
-        final long filepos = mBackupDataFile.length();
+        String packageName = mCurrentPackage.packageName;
+        ApplicationInfo applicationInfo = mCurrentPackage.applicationInfo;
+        long filePos = mBackupDataFile.length();
         FileDescriptor fd = mBackupData.getFileDescriptor();
+        boolean writingWidgetData = false;
         try {
-            // If it's a 3rd party app, see whether they wrote any protected keys
-            // and complain mightily if they are attempting shenanigans.
-            if (mCurrentPackage.applicationInfo != null &&
-                    (mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
-                            == 0) {
-                ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataFile,
-                        ParcelFileDescriptor.MODE_READ_ONLY);
+            // If it's a 3rd party app, crash them if they wrote any protected keys.
+            if (applicationInfo != null &&
+                    (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                ParcelFileDescriptor readFd =
+                        ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY);
                 BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
                 try {
                     while (in.readNextHeader()) {
-                        final String key = in.getKey();
+                        String key = in.getKey();
                         if (key != null && key.charAt(0) >= 0xff00) {
-                            // Not okay: crash them and bail.
+                            mReporter.onAgentIllegalKey(mCurrentPackage, key);
                             failAgent(mAgentBinder, "Illegal backup key: " + key);
-                            mBackupManagerService
-                                    .addBackupTrace("illegal key " + key + " from " + pkgName);
-                            EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
-                                    "bad key");
-                            mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
-                                    BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY,
-                                    mCurrentPackage,
-                                    BackupManagerMonitor
-                                            .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
-                                    BackupManagerMonitorUtils.putMonitoringExtra(null,
-                                            BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY,
-                                            key));
-                            BackupObserverUtils
-                                    .sendBackupOnPackageResult(mObserver, pkgName,
-                                            BackupManager.ERROR_AGENT_FAILURE);
                             errorCleanup();
-                            if (MORE_DEBUG) {
-                                Slog.i(TAG, "Agent failure for " + pkgName
-                                        + " with illegal key " + key + ", dropped");
-                            }
-
                             return BackupState.RUNNING_QUEUE;
                         }
                         in.skipEntityData();
                     }
                 } finally {
-                    if (readFd != null) {
-                        readFd.close();
-                    }
+                    readFd.close();
                 }
             }
 
-            // Piggyback the widget state payload, if any
-            writeWidgetPayloadIfAppropriate(fd, pkgName);
+            writingWidgetData = true;
+            writeWidgetPayloadIfAppropriate(fd, packageName);
         } catch (IOException e) {
-            // Hard disk error; recovery/failure policy TBD.  For now roll back,
-            // but we may want to consider this a transport-level failure (i.e.
-            // we're in such a bad state that we can't contemplate doing backup
-            // operations any more during this pass).
-            Slog.w(TAG, "Unable read backup data or to save widget state for " + pkgName);
+            if (writingWidgetData) {
+                mReporter.onWriteWidgetDataError(packageName, e);
+            } else {
+                mReporter.onReadAgentDataError(packageName, e);
+            }
             try {
-                Os.ftruncate(fd, filepos);
+                Os.ftruncate(fd, filePos);
             } catch (ErrnoException ee) {
-                Slog.w(TAG, "Unable to roll back");
+                mReporter.onTruncateDataError();
             }
         }
 
         clearAgentState();
-        mBackupManagerService.addBackupTrace("operation complete");
 
         ParcelFileDescriptor backupData = null;
         mStatus = BackupTransport.TRANSPORT_OK;
         long size = 0;
         try {
-            IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.handleAgentResult()");
+            IBackupTransport transport =
+                    mTransportClient.connectOrThrow("KVBT.sendDataToTransport()");
             size = mBackupDataFile.length();
             if (size > 0) {
-                if (MORE_DEBUG) {
-                    Slog.v(TAG, "Sending non-empty data to transport for " + pkgName);
-                }
                 boolean isNonIncremental = mSavedStateFile.length() == 0;
-                if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    backupData = ParcelFileDescriptor.open(mBackupDataFile,
-                            ParcelFileDescriptor.MODE_READ_ONLY);
-                    mBackupManagerService.addBackupTrace("sending data to transport");
 
+                if (mStatus == BackupTransport.TRANSPORT_OK) {
+                    mReporter.onSendDataToTransport(packageName);
+                    backupData = ParcelFileDescriptor.open(mBackupDataFile, MODE_READ_ONLY);
                     int userInitiatedFlag =
                             mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
                     int incrementalFlag =
@@ -1069,114 +905,58 @@
 
                 if (isNonIncremental
                         && mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
-                    // TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED is only valid if the backup was
-                    // incremental, as if the backup is non-incremental there is no state to
-                    // clear. This avoids us ending up in a retry loop if the transport always
-                    // returns this code.
-                    Slog.e(TAG, "Transport requested non-incremental but already the case");
-                    mBackupManagerService.addBackupTrace(
-                            "Transport requested non-incremental but already the case, error");
+                    mReporter.onNonIncrementalAndNonIncrementalRequired();
                     mStatus = BackupTransport.TRANSPORT_ERROR;
                 }
 
-                mBackupManagerService.addBackupTrace("data delivered: " + mStatus);
                 if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    mBackupManagerService.addBackupTrace("finishing op on transport");
                     mStatus = transport.finishBackup();
-                    mBackupManagerService.addBackupTrace("finished: " + mStatus);
-                } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
-                    mBackupManagerService.addBackupTrace("transport rejected package");
                 }
             } else {
-                if (MORE_DEBUG) {
-                    Slog.i(TAG, "No backup data written, not calling transport");
-                }
-                mBackupManagerService.addBackupTrace("no data to send");
-                mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
-                        BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
-                        mCurrentPackage,
-                        BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
-                        null);
+                mReporter.onEmptyData(mCurrentPackage);
             }
 
             if (mStatus == BackupTransport.TRANSPORT_OK) {
-                // After successful transport, delete the now-stale data
-                // and juggle the files so that next time we supply the agent
-                // with the new state file it just created.
                 mBackupDataFile.delete();
                 mNewStateFile.renameTo(mSavedStateFile);
-                BackupObserverUtils.sendBackupOnPackageResult(
-                        mObserver, pkgName, BackupManager.SUCCESS);
-                EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
-                mBackupManagerService.logBackupComplete(pkgName);
+                mReporter.onPackageBackupComplete(packageName, size);
             } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
-                // The transport has rejected backup of this specific package.  Roll it
-                // back but proceed with running the rest of the queue.
                 mBackupDataFile.delete();
                 mNewStateFile.delete();
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
-                        BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
-                EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
+                mReporter.onPackageBackupRejected(packageName);
             } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
-                        BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
-                EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
-
+                // TODO: Should reset files like above?
+                mReporter.onPackageBackupQuotaExceeded(packageName);
             } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
-                Slog.i(TAG, "Transport lost data, retrying package");
-                mBackupManagerService.addBackupTrace(
-                        "Transport lost data, retrying package:" + pkgName);
-                BackupManagerMonitorUtils.monitorEvent(
-                        mMonitor,
-                        BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED,
-                        mCurrentPackage,
-                        BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
-                        /*extras=*/ null);
-
+                mReporter.onPackageBackupNonIncrementalRequired(mCurrentPackage);
                 mBackupDataFile.delete();
                 mSavedStateFile.delete();
                 mNewStateFile.delete();
 
                 // Immediately retry the package by adding it back to the front of the queue.
                 // We cannot add @pm@ to the queue because we back it up separately at the start
-                // of the backup pass in state BACKUP_PM. Instead we retry this state (see
-                // below).
-                if (!PACKAGE_MANAGER_SENTINEL.equals(pkgName)) {
-                    mQueue.add(0, new BackupRequest(pkgName));
+                // of the backup pass in state BACKUP_PM. See below.
+                if (!PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
+                    mQueue.add(0, new BackupRequest(packageName));
                 }
-
             } else {
-                // Actual transport-level failure to communicate the data to the backend
-                BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
-                        BackupManager.ERROR_TRANSPORT_ABORTED);
-                EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
+                mReporter.onPackageBackupTransportFailure(packageName);
             }
         } catch (Exception e) {
-            BackupObserverUtils.sendBackupOnPackageResult(mObserver, pkgName,
-                    BackupManager.ERROR_TRANSPORT_ABORTED);
-            Slog.e(TAG, "Transport error backing up " + pkgName, e);
-            EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
+            mReporter.onPackageBackupError(packageName, e);
             mStatus = BackupTransport.TRANSPORT_ERROR;
         } finally {
-            try {
-                if (backupData != null) {
-                    backupData.close();
-                }
-            } catch (IOException e) {
-                Slog.w(TAG, "Error closing backup data file-descriptor");
-            }
+            tryCloseFileDescriptor(backupData, "backup data");
         }
 
         final BackupState nextState;
         if (mStatus == BackupTransport.TRANSPORT_OK
                 || mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
-            // Success or single-package rejection.  Proceed with the next app if any,
-            // otherwise we're done.
             nextState = BackupState.RUNNING_QUEUE;
 
         } else if (mStatus == BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED) {
             // We want to immediately retry the current package.
-            if (PACKAGE_MANAGER_SENTINEL.equals(pkgName)) {
+            if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
                 nextState = BackupState.BACKUP_PM;
             } else {
                 // This is an ordinary package so we will have added it back into the queue
@@ -1185,25 +965,21 @@
             }
 
         } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
-            if (MORE_DEBUG) {
-                Slog.d(TAG, "Package " + mCurrentPackage.packageName +
-                        " hit quota limit on key-value backup");
-            }
             if (mAgentBinder != null) {
                 try {
                     IBackupTransport transport =
-                            mTransportClient.connectOrThrow("KVBT.handleAgentResult()");
+                            mTransportClient.connectOrThrow("KVBT.sendDataToTransport()");
                     long quota = transport.getBackupQuota(mCurrentPackage.packageName, false);
                     mAgentBinder.doQuotaExceeded(size, quota);
                 } catch (Exception e) {
-                    Slog.e(TAG, "Unable to notify about quota exceeded: " + e.getMessage());
+                    mReporter.onAgentDoQuotaExceededError(e);
                 }
             }
             nextState = BackupState.RUNNING_QUEUE;
         } else {
             // Any other error here indicates a transport-level failure.  That means
             // we need to halt everything and reschedule everything for next time.
-            revertAndEndBackup();
+            revertBackup();
             nextState = BackupState.FINAL;
         }
 
@@ -1223,10 +999,9 @@
      */
     @Override
     public void handleCancel(boolean cancelAll) {
+        // This is called in a thread different from the one that executes method run().
         Preconditions.checkArgument(cancelAll, "Can't partially cancel a key-value backup task");
-        if (MORE_DEBUG) {
-            Slog.v(TAG, "Cancel received");
-        }
+        mReporter.onCancel();
         mCancelled = true;
         RemoteCall pendingCall = mPendingCall;
         if (pendingCall != null) {
@@ -1236,66 +1011,35 @@
     }
 
     private void handleAgentTimeout() {
-        String packageName = getPackageNameForLog();
-        Slog.i(TAG, "Agent " + packageName + " timed out");
-        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
-        mBackupManagerService.addBackupTrace("timeout of " + packageName);
-        mMonitor =
-                BackupManagerMonitorUtils.monitorEvent(
-                        mMonitor,
-                        BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
-                        mCurrentPackage,
-                        BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
-                        BackupManagerMonitorUtils.putMonitoringExtra(
-                                null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, false));
+        mReporter.onAgentTimedOut(mCurrentPackage);
         errorCleanup();
     }
 
     private void handleAgentCancelled() {
-        String packageName = getPackageNameForLog();
-        Slog.i(TAG, "Cancel backing up " + packageName);
-        EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
-        mBackupManagerService.addBackupTrace("cancel of " + packageName);
+        mReporter.onAgentCancelled(mCurrentPackage);
         errorCleanup();
     }
 
-    private void finalizeCancelledBackup() {
-        mMonitor =
-                BackupManagerMonitorUtils.monitorEvent(
-                        mMonitor,
-                        BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
-                        mCurrentPackage,
-                        BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
-                        BackupManagerMonitorUtils.putMonitoringExtra(
-                                null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, true));
-        finalizeBackup();
+    private void finishCancelledBackup() {
+        finishBackup();
         // finalizeBackup() may call the transport, so we only acknowledge the cancellation here.
         mCancelAcknowledged.open();
     }
 
-    private String getPackageNameForLog() {
-        return (mCurrentPackage != null) ? mCurrentPackage.packageName : "no_package_yet";
-    }
-
-    private void revertAndEndBackup() {
-        if (MORE_DEBUG) {
-            Slog.i(TAG, "Reverting backup queue, re-staging everything");
-        }
-        mBackupManagerService.addBackupTrace("transport error; reverting");
-
-        // We want to reset the backup schedule based on whatever the transport suggests
-        // by way of retry/backoff time.
+    private void revertBackup() {
+        mReporter.onRevertBackup();
         long delay;
         try {
             IBackupTransport transport =
-                    mTransportClient.connectOrThrow("KVBT.revertAndEndBackup()");
+                    mTransportClient.connectOrThrow("KVBT.revertBackup()");
             delay = transport.requestBackupTime();
         } catch (Exception e) {
-            Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e);
-            delay = 0;  // use the scheduler's default
+            mReporter.onTransportRequestBackupTimeError(e);
+            // Use the scheduler's default.
+            delay = 0;
         }
-        KeyValueBackupJob.schedule(mBackupManagerService.getContext(), delay,
-                mBackupManagerService.getConstants());
+        KeyValueBackupJob.schedule(
+                mBackupManagerService.getContext(), delay, mBackupManagerService.getConstants());
 
         for (BackupRequest request : mOriginalQueue) {
             mBackupManagerService.dataChangedImpl(request.packageName);
@@ -1308,50 +1052,37 @@
         clearAgentState();
     }
 
-    // Cleanup common to both success and failure cases
     private void clearAgentState() {
-        try {
-            if (mSavedState != null) {
-                mSavedState.close();
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Error closing old state file-descriptor");
-        }
-        try {
-            if (mBackupData != null) {
-                mBackupData.close();
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Error closing backup data file-descriptor");
-        }
-        try {
-            if (mNewState != null) {
-                mNewState.close();
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Error closing new state file-descriptor");
-        }
+        // Cleanup common to both success and failure cases.
+        tryCloseFileDescriptor(mSavedState, "old state");
+        tryCloseFileDescriptor(mBackupData, "backup data");
+        tryCloseFileDescriptor(mNewState, "new state");
         synchronized (mBackupManagerService.getCurrentOpLock()) {
-            // Current-operation callback handling requires the validity of these various
-            // bits of internal state as an invariant of the operation still being live.
-            // This means we make sure to clear all of the state in unison inside the lock.
+            // TODO: Do we still need this?
             mSavedState = mBackupData = mNewState = null;
         }
 
-        // If this was a pseudo-package there's no associated Activity Manager state
+        // For PM metadata (for which applicationInfo is null) there is no agent-bound state.
         if (mCurrentPackage.applicationInfo != null) {
-            mBackupManagerService.addBackupTrace("unbinding " + mCurrentPackage.packageName);
             mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);
         }
     }
 
+    private void tryCloseFileDescriptor(@Nullable Closeable closeable, String logName) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (IOException e) {
+                mReporter.onCloseFileDescriptorError(logName);
+            }
+        }
+    }
+
     private RemoteResult remoteCall(RemoteCallable<IBackupCallback> remoteCallable, long timeoutMs)
             throws RemoteException {
         mPendingCall = new RemoteCall(mCancelled, remoteCallable, timeoutMs);
         RemoteResult result = mPendingCall.call();
-        if (MORE_DEBUG) {
-            Slog.v(TAG, "Agent call returned " + result);
-        }
+        mReporter.onRemoteCallReturned(result);
         mPendingCall = null;
         return result;
     }
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 28e9b77..9af952d 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -136,7 +136,14 @@
     /**
      * Checks if the app is in a stopped state.  This is not part of the general "eligible for
      * backup?" check because we *do* still need to restore data to apps in this state (e.g.
-     * newly-installing ones)
+     * newly-installing ones).
+     *
+     * <p>Reasons for such state:
+     * <ul>
+     *     <li>The app has been force-stopped.
+     *     <li>The app has been cleared.
+     *     <li>The app has just been installed.
+     * </ul>
      */
     public static boolean appIsStopped(ApplicationInfo app) {
         return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
index b23781d..6f08376 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
@@ -21,6 +21,7 @@
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.TAG;
 
+import android.annotation.Nullable;
 import android.app.backup.BackupManagerMonitor;
 import android.app.backup.IBackupManagerMonitor;
 import android.content.pm.PackageInfo;
@@ -44,8 +45,13 @@
      * @param extras - additional event data.
      * @return <code>monitor</code> if call succeeded and <code>null</code> otherwise.
      */
-    public static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id,
-            PackageInfo pkg, int category, Bundle extras) {
+    @Nullable
+    public static IBackupManagerMonitor monitorEvent(
+            @Nullable IBackupManagerMonitor monitor,
+            int id,
+            PackageInfo pkg,
+            int category,
+            Bundle extras) {
         if (monitor != null) {
             try {
                 Bundle bundle = new Bundle();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6b3f8f8..914404b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2194,8 +2194,7 @@
                     break;
                 }
                 case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
-                    Integer score = (Integer) msg.obj;
-                    if (score != null) updateNetworkScore(nai, score.intValue());
+                    updateNetworkScore(nai, msg.arg1);
                     break;
                 }
                 case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index d06e785..f4d20b3 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1014,12 +1014,7 @@
                     Bundle finalExtras = new Bundle(extras);
                     String packageName = syncAdapterInfo.componentName.getPackageName();
                     // If the app did not run and has no account access, done
-                    try {
-                        if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
-                            continue;
-                        }
-                    } catch (IllegalArgumentException e) {
-                        // Package not found, race with an uninstall
+                    if (!wasPackageEverLaunched(packageName, userId)) {
                         continue;
                     }
                     mAccountManagerInternal.requestAccountAccess(account.account,
@@ -3352,7 +3347,7 @@
                     String packageName = op.owningPackage;
                     final int userId = UserHandle.getUserId(op.owningUid);
                     // If the app did not run and has no account access, done
-                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+                    if (!wasPackageEverLaunched(packageName, userId)) {
                         return;
                     }
                     mAccountManagerInternal.requestAccountAccess(op.target.account,
@@ -4059,4 +4054,12 @@
     public void resetTodayStats() {
         mSyncStorageEngine.resetTodayStats(/*force=*/ true);
     }
+
+    private boolean wasPackageEverLaunched(String packageName, int userId) {
+        try {
+            return mPackageManagerInternal.wasPackageEverLaunched(packageName, userId);
+        } catch (IllegalArgumentException e) {
+            return false; // Package has been removed.
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3f57faf..f487200 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2144,6 +2144,10 @@
             enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
 
             mPreferencesHelper.setEnabled(pkg, uid, enabled);
+            mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
+                    .setType(MetricsEvent.TYPE_ACTION)
+                    .setPackageName(pkg)
+                    .setSubtype(enabled ? 1 : 0));
             // Now, cancel any outstanding notifications that are part of a just-disabled app
             if (!enabled) {
                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ed1dc58..5769207 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -917,6 +917,7 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                             android.Manifest.permission.USER_ACTIVITY);
+                    break;
                 case MSG_RINGER_TOGGLE_CHORD:
                     handleRingerChordGesture();
                     break;
@@ -2452,11 +2453,13 @@
                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
                 break;
             case TYPE_STATUS_BAR:
+
                 // If the Keyguard is in a hidden state (occluded by another window), we force to
-                // remove the keyguard flag so that any change in-flight after setting
-                // the keyguard as occluded wouldn't set the flag again.
+                // remove the wallpaper and keyguard flag so that any change in-flight after setting
+                // the keyguard as occluded wouldn't set these flags again.
                 // See {@link #processKeyguardSetHiddenResultLw}.
                 if (mKeyguardOccluded) {
+                    attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
                 }
                 break;
@@ -5517,13 +5520,17 @@
             mKeyguardDelegate.setOccluded(false, true /* animate */);
             if (mStatusBar != null) {
                 mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+                if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
+                    mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+                }
             }
             return true;
         } else if (isOccluded && changed && showing) {
             mKeyguardOccluded = true;
-            mKeyguardDelegate.setOccluded(true, !mShowingDream /* animate */);
+            mKeyguardDelegate.setOccluded(true, false /* animate */);
             if (mStatusBar != null) {
                 mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+                mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
             }
             return true;
         } else if (changed) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3ae5ced..b55adeb 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1711,8 +1711,8 @@
     }
 
     /**
-     * Requests that the WindowManager sends WindowManagerPolicy#ACTION_USER_ACTIVITY_NOTIFICATION
-     * on the next user activity.
+     * Requests that the WindowManager sends
+     * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity.
      */
     public void requestUserActivityNotification();
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7ee35e7..d73606f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1557,7 +1557,7 @@
         if (isKeyguardGoingAwayTransit(transit) && enter) {
             a = loadKeyguardExitAnimation(transit);
         } else if (transit == TRANSIT_KEYGUARD_OCCLUDE) {
-            a = loadAnimationRes(lp, com.android.internal.R.anim.keyguard_occlude_open_enter);
+            a = null;
         } else if (transit == TRANSIT_KEYGUARD_UNOCCLUDE && !enter) {
             a = loadAnimationRes(lp, com.android.internal.R.anim.wallpaper_open_exit);
         } else if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 44d0187..ae2256a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2128,6 +2128,8 @@
                 }
             }
             mService.mAnimator.removeDisplayLocked(mDisplayId);
+            mWindowingLayer.release();
+            mOverlayLayer.release();
         } finally {
             mRemovingDisplay = false;
         }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index b5566a7..dea4076 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -361,6 +361,11 @@
                     new RemoteAnimationTarget[appAnimations.size()]);
             mPendingStart = false;
 
+            // Perform layout if it was scheduled before to make sure that we get correct content
+            // insets for the target app window after a rotation
+            final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
+            displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+
             final Rect minimizedHomeBounds = mTargetAppToken != null
                     && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
                             ? mMinimizedHomeBounds
@@ -369,8 +374,7 @@
                     && mTargetAppToken.findMainWindow() != null
                             ? mTargetAppToken.findMainWindow().mContentInsets
                             : null;
-            mRunner.onAnimationStart(mController, appTargets, contentInsets,
-                    minimizedHomeBounds);
+            mRunner.onAnimationStart(mController, appTargets, contentInsets, minimizedHomeBounds);
             if (DEBUG_RECENTS_ANIMATIONS) {
                 Slog.d(TAG, "startAnimation(): Notify animation start:");
                 for (int i = 0; i < mPendingAnimations.size(); i++) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b6f3d3b..c82c242 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -28,6 +28,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
+import android.database.sqlite.SQLiteGlobal;
 import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
@@ -355,6 +356,10 @@
             Binder.setWarnOnBlocking(true);
             // The system server should always load safe labels
             PackageItemInfo.setForceSafeLabels(true);
+
+            // Default to FULL within the system server.
+            SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;
+
             // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
             SQLiteCompatibilityWalFlags.init(null);
 
diff --git a/services/robotests/README b/services/robotests/README
new file mode 100644
index 0000000..3c68292
--- /dev/null
+++ b/services/robotests/README
@@ -0,0 +1,23 @@
+This folder is for Robolectric tests inside the platform.
+
+To add a test class annotate it as follows:
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderClasses({ClassUnderTest.class, DependencyClasses.class})
+@SystemLoaderPackages({"com.android.server.yourmodule"})
+
+Robolectric loads some classes that it decides from versioned jars of the framework. Since we are
+part of the framework some of our classes get loaded from these jars. This is NOT what we want, we
+want to test against what we wrote in the tree. Because of this we use a custom test runner,
+FrameworkRobolectricTestRunner, that bypasses these jars and loads certain classes from the system
+class loader.
+
+To specify which classes to load use either @SystemLoaderClasses or @SystemLoaderPackages. In
+practice:
+* You MUST put the class under test here.
+* If you encounter any exceptions that might be caused by a different version of the class being
+loaded, such as NoSuchMethodException, put the class involved in the exception in this annotation
+and try again.
+
+Check Android.mk file for more info.
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index de22201..e316d5b 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -1382,6 +1382,7 @@
         verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
         assertEventLogged(EventLogTags.BACKUP_QUOTA_EXCEEDED, PACKAGE_1.packageName);
         assertBackupNotPendingFor(PACKAGE_1);
+        // TODO: Assert about state/staging files (possible bug)
     }
 
     @Test
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 25851e3..b7ccee5 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -16,16 +16,16 @@
 
 package android.telephony;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS;
-import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_HSDPA;
-import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_HSPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
 
+import android.os.Parcel;
+import android.os.Parcelable;
 
 
 /**
@@ -100,6 +100,39 @@
         mCid = cid;
     }
 
+    /** @hide */
+    public NeighboringCellInfo(final CellInfoGsm info) {
+        mNetworkType = TelephonyManager.NETWORK_TYPE_GPRS;
+
+        mRssi = info.getCellSignalStrength().getAsuLevel();
+        if (mRssi == Integer.MAX_VALUE) mRssi = UNKNOWN_RSSI;
+
+        mLac = info.getCellIdentity().getLac();
+        if (mLac == Integer.MAX_VALUE) mLac = UNKNOWN_CID;
+
+        mCid = info.getCellIdentity().getCid();
+        if (mCid == Integer.MAX_VALUE) mCid = UNKNOWN_CID;
+
+        mPsc = UNKNOWN_CID;
+    }
+
+    /** @hide */
+    public NeighboringCellInfo(final CellInfoWcdma info) {
+        mNetworkType = TelephonyManager.NETWORK_TYPE_UMTS;
+
+        mRssi = info.getCellSignalStrength().getAsuLevel();
+        if (mRssi == Integer.MAX_VALUE) mRssi = UNKNOWN_RSSI;
+
+        mLac = info.getCellIdentity().getLac();
+        if (mLac == Integer.MAX_VALUE) mLac = UNKNOWN_CID;
+
+        mCid = info.getCellIdentity().getCid();
+        if (mCid == Integer.MAX_VALUE) mCid = UNKNOWN_CID;
+
+        mPsc = info.getCellIdentity().getPsc();
+        if (mPsc == Integer.MAX_VALUE) mPsc = UNKNOWN_CID;
+    }
+
     /**
      * Initialize the object from rssi, location string, and radioType
      * radioType is one of following
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b2eb5e0..8782a41 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1544,7 +1544,7 @@
      * @return List of NeighboringCellInfo or null if info unavailable.
      *
      * @deprecated Use {@link #getAllCellInfo} which returns a superset of the information
-     *             from NeighboringCellInfo.
+     *             from NeighboringCellInfo, including LTE cell information.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index c6f8622..e924a25 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -16,10 +16,14 @@
 
 package android.telephony.ims;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Provides the result to the update operation for the supplementary service configuration.
  *
@@ -34,6 +38,30 @@
     public static final int DISABLED = 0;
     public static final int ENABLED = 1;
 
+    /**
+     * Provision status of service
+     */
+    /** @hide */
+    @IntDef({
+            SERVICE_PROVISIONING_UNKNOWN,
+            SERVICE_NOT_PROVISIONED,
+            SERVICE_PROVISIONED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ServiceProvisionStatus {}
+    /**
+     * Unknown provision status for the service.
+     */
+    public static final int SERVICE_PROVISIONING_UNKNOWN = (-1);
+    /**
+     * Service is not provisioned.
+     */
+    public static final int SERVICE_NOT_PROVISIONED = 0;
+    /**
+     * Service is provisioned.
+     */
+    public static final int SERVICE_PROVISIONED = 1;
+
     // 0: disabled, 1: enabled
     /** @hide */
     // TODO: Make private, do not modify this field directly, use getter!
@@ -41,6 +69,8 @@
     /** @hide */
     // TODO: Make private, do not modify this field directly, use getter!
     public String mIcbNum;
+    /** @hide */
+    public int mProvisionStatus = SERVICE_PROVISIONING_UNKNOWN;
 
     /**@hide*/
     // TODO: Remove! Do not use this constructor, instead use public version.
@@ -74,16 +104,30 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mStatus);
         out.writeString(mIcbNum);
+        out.writeInt(mProvisionStatus);
     }
 
     @Override
     public String toString() {
-        return super.toString() + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled");
+        return super.toString() + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled")
+                + ", ProvisionStatus: " + provisionStatusToString(mProvisionStatus);
+    }
+
+    private static String provisionStatusToString(int pStatus) {
+        switch (pStatus) {
+            case SERVICE_NOT_PROVISIONED:
+                return "Service not provisioned";
+             case SERVICE_PROVISIONED:
+                return "Service provisioned";
+             default:
+                return "Service provisioning unknown";
+        }
     }
 
     private void readFromParcel(Parcel in) {
         mStatus = in.readInt();
         mIcbNum = in.readString();
+        mProvisionStatus = in.readInt();
     }
 
     public static final Creator<ImsSsInfo> CREATOR =
@@ -112,4 +156,15 @@
     public String getIcbNum() {
         return mIcbNum;
     }
+
+    /**
+     * @return Supplementary Service Provision status. Valid Values are:
+     *     {@link #SERVICE_PROVISIONING_UNKNOWN},
+     *     {@link #SERVICE_NOT_PROVISIONED},
+     *     {@link #SERVICE_PROVISIONED}
+     */
+    @ServiceProvisionStatus
+    public int getProvisionStatus() {
+        return mProvisionStatus;
+    }
 }