Merge "MediaStore should reflect state on disk."
diff --git a/Android.bp b/Android.bp
index 391bcd5..cd0720d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -634,6 +634,7 @@
         "wifi/java/android/net/wifi/rtt/IRttCallback.aidl",
         "wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
         "wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
+        "wifi/java/android/net/wifi/IDppCallback.aidl",
         "wifi/java/android/net/wifi/IWifiScanner.aidl",
         "packages/services/PacProcessor/com/android/net/IProxyService.aidl",
         "packages/services/Proxy/com/android/net/IProxyCallback.aidl",
diff --git a/api/current.txt b/api/current.txt
index c107e58..fad607c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29555,6 +29555,7 @@
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
     method public boolean isDeviceToApRttSupported();
+    method public boolean isDppSupported();
     method public boolean isEnhancedPowerReportingSupported();
     method public boolean isOweSupported();
     method public boolean isP2pSupported();
diff --git a/api/system-current.txt b/api/system-current.txt
index 7f3c152..e27c29f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1221,7 +1221,6 @@
   public abstract class PackageManager {
     method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
-    method public boolean canSuspendPackage(java.lang.String);
     method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
     method public android.content.pm.ApplicationInfo getApplicationInfoAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.dex.ArtManager getArtManager();
@@ -1235,6 +1234,7 @@
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
     method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public java.lang.String[] getUnsuspendablePackages(java.lang.String[]);
     method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -3001,6 +3001,7 @@
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
     field public static final int FLAG_FROM_KEY = 65536; // 0x10000
+    field public static final int SUCCESS = 0; // 0x0
   }
 
   public static abstract class AudioManager.AudioServerStateCallback {
@@ -3117,8 +3118,10 @@
     method public int detachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
     method public int getFocusDuckingBehavior();
     method public int getStatus();
+    method public int removeUidDeviceAffinity(int);
     method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setRegistration(java.lang.String);
+    method public int setUidDeviceAffinity(int, java.util.List<android.media.AudioDeviceInfo>);
     method public java.lang.String toLogFriendlyString();
     field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
@@ -3715,6 +3718,26 @@
 
 package android.net.wifi {
 
+  public abstract class DppStatusCallback {
+    ctor public DppStatusCallback();
+    method public abstract void onConfiguratorSuccess(int);
+    method public abstract void onEnrolleeSuccess(int);
+    method public abstract void onFailure(int);
+    method public abstract void onProgress(int);
+    field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
+    field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+    field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+    field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+    field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+    field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+    field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+    field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+    field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+    field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+    field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+  }
+
   public deprecated class RttManager {
     method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
@@ -3944,7 +3967,10 @@
     method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
     method public void setDeviceMobilityState(int);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+    method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
+    method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
     method public boolean startScan(android.os.WorkSource);
+    method public void stopDppSession();
     method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -3954,6 +3980,8 @@
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+    field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
+    field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
     field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
     field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/api/test-current.txt b/api/test-current.txt
index c1e4162..9c51c9f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -72,6 +72,7 @@
     method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
     method public void resizeStack(int, android.graphics.Rect, boolean);
     method public void resizeTask(int, android.graphics.Rect);
+    method public void setDisplayToSingleTaskInstance(int);
     method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
     method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
     method public void startSystemLockTaskMode(int);
@@ -1153,6 +1154,20 @@
     method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
   }
 
+  public final class CompositeUserData implements android.os.Parcelable {
+    ctor public CompositeUserData(android.service.autofill.UserData, android.service.autofill.UserData);
+    method public int describeContents();
+    method public java.lang.String[] getCategoryIds();
+    method public android.os.Bundle getDefaultFieldClassificationArgs();
+    method public java.lang.String getFieldClassificationAlgorithm();
+    method public java.lang.String getFieldClassificationAlgorithmForCategory(java.lang.String);
+    method public android.util.ArrayMap<java.lang.String, java.lang.String> getFieldClassificationAlgorithms();
+    method public android.util.ArrayMap<java.lang.String, android.os.Bundle> getFieldClassificationArgs();
+    method public java.lang.String[] getValues();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.autofill.CompositeUserData> CREATOR;
+  }
+
   public final class CustomDescription implements android.os.Parcelable {
     method public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions();
   }
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 498eebc..04d4f9a 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -114,7 +114,7 @@
         virtual void shutdown() {}
     };
 
-    BootAnimation(sp<Callbacks> callbacks);
+    explicit BootAnimation(sp<Callbacks> callbacks);
 
     sp<SurfaceComposerClient> session() const;
 
@@ -128,7 +128,7 @@
 
     class TimeCheckThread : public Thread {
     public:
-        TimeCheckThread(BootAnimation* bootAnimation);
+        explicit TimeCheckThread(BootAnimation* bootAnimation);
         virtual ~TimeCheckThread();
     private:
         virtual status_t    readyToRun();
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index fe7099b..abe18ba 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,6 +23,7 @@
     ],
     tidy_flags: [
         "-system-headers",
+        "-warnings-as-errors=*",
     ],
 }
 
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 4d8c856..7eab5db 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -430,4 +430,17 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Makes the display with the given id a single task instance display. I.e the display can only
+     * contain one task.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+    public void setDisplayToSingleTaskInstance(int displayId) {
+        try {
+            getService().setDisplayToSingleTaskInstance(displayId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 680fed8..0b5776e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -83,6 +83,9 @@
     private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
     private Surface mTmpSurface = new Surface();
 
+    /** The ActivityView is only allowed to contain one task. */
+    private final boolean mSingleTaskInstance;
+
     @UnsupportedAppUsage
     public ActivityView(Context context) {
         this(context, null /* attrs */);
@@ -93,7 +96,13 @@
     }
 
     public ActivityView(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, false /*singleTaskInstance*/);
+    }
+
+    public ActivityView(
+            Context context, AttributeSet attrs, int defStyle, boolean singleTaskInstance) {
         super(context, attrs, defStyle);
+        mSingleTaskInstance = singleTaskInstance;
 
         mActivityTaskManager = ActivityTaskManager.getService();
         mSurfaceView = new SurfaceView(context);
@@ -379,6 +388,9 @@
         try {
             wm.reparentDisplayContent(displayId, mRootSurfaceControl.getHandle());
             wm.dontOverrideDisplayInfo(displayId);
+            if (mSingleTaskInstance) {
+                mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);
+            }
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 17529a6..94983e1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2299,9 +2299,9 @@
     }
 
     @Override
-    public boolean canSuspendPackage(String packageName) {
+    public String[] getUnsuspendablePackages(String[] packageNames) {
         try {
-            return mPM.canSuspendPackageForUser(packageName, mContext.getUserId());
+            return mPM.getUnsuspendablePackagesForUser(packageNames, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index f549e18..dd87dc3 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -452,4 +452,10 @@
      * Clears launch params for given packages.
      */
     void clearLaunchParamsForPackages(in List<String> packageNames);
+
+    /**
+     * Makes the display with the given id a single task instance display. I.e the display can only
+     * contain one task.
+     */
+    void setDisplayToSingleTaskInstance(int displayId);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1e3908c..3492200 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9169,7 +9169,7 @@
      * @param extras The new set of extras in the Intent, or null to erase
      * all extras.
      */
-    public @NonNull Intent replaceExtras(@NonNull Bundle extras) {
+    public @NonNull Intent replaceExtras(@Nullable Bundle extras) {
         mExtras = extras != null ? new Bundle(extras) : null;
         return this;
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 502fb78..2978058 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -639,6 +639,21 @@
      */
     public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;
 
+    /**
+     * Indicate whether this application prefers code integrity, that is, run only code that is
+     * signed. This requires android:extractNativeLibs to be "false", as well as .dex and .so (if
+     * any) stored uncompressed inside the APK, which is signed. At run time, the implications
+     * include:
+     *
+     * <ul>
+     * <li>ART will JIT the dex code directly from the APK. There may be performance characteristic
+     * changes depend on the actual workload.
+     * </ul>
+     *
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_PREFER_CODE_INTEGRITY = 1 << 25;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
             PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -654,6 +669,7 @@
             PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,
             PRIVATE_FLAG_OEM,
             PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
+            PRIVATE_FLAG_PREFER_CODE_INTEGRITY,
             PRIVATE_FLAG_PRIVILEGED,
             PRIVATE_FLAG_PRODUCT,
             PRIVATE_FLAG_PRODUCT_SERVICES,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a4ea513..64a4479b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -277,7 +277,7 @@
             in PersistableBundle appExtras, in PersistableBundle launcherExtras,
             in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
 
-    boolean canSuspendPackageForUser(String packageName, int userId);
+    String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
 
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2608796..6110557 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5969,27 +5969,28 @@
     }
 
     /**
-     * Returns whether or not a given package can be suspended via a call to {@link
+     * Returns any packages in a given set of packages that cannot be suspended via a call to {@link
      * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
      * SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
      * packages to keep the device in a functioning state, e.g. the default dialer.
      * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this api.
      *
      * <p>
-     * Note that this set of critical packages can change with time, so <em>a value of {@code true}
-     * returned by this api does not guarantee that a following call to {@link
-     * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
-     * SuspendDialogInfo) setPackagesSuspended} for the same package will succeed</em>, especially
-     * if considerable time elapsed between the two calls.
+     * Note that this set of critical packages can change with time, so even though a package name
+     * was not returned by this call, it does not guarantee that a subsequent call to
+     * {@link #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+     * SuspendDialogInfo) setPackagesSuspended} for that package will succeed, especially if
+     * significant time elapsed between the two calls.
      *
-     * @param packageName The package to check.
-     * @return {@code true} if the given package can be suspended, {@code false} otherwise.
+     * @param packageNames The packages to check.
+     * @return A list of packages that can not be currently suspended by the system.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.SUSPEND_APPS)
-    public boolean canSuspendPackage(@NonNull String packageName) {
-        throw new UnsupportedOperationException("canSuspendPackage not implemented");
+    @NonNull
+    public String[] getUnsuspendablePackages(@NonNull String[] packageNames) {
+        throw new UnsupportedOperationException("canSuspendPackages not implemented");
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e38b294..2b266b7 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -475,6 +475,7 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
         public final boolean isSplitRequired;
+        public final boolean preferCodeIntegrity;
 
         public ApkLite(String codePath, String packageName, String splitName,
                 boolean isFeatureSplit,
@@ -483,7 +484,7 @@
                 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
                 SigningDetails signingDetails, boolean coreApp,
                 boolean debuggable, boolean multiArch, boolean use32bitAbi,
-                boolean extractNativeLibs, boolean isolatedSplits) {
+                boolean preferCodeIntegrity, boolean extractNativeLibs, boolean isolatedSplits) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
@@ -500,6 +501,7 @@
             this.debuggable = debuggable;
             this.multiArch = multiArch;
             this.use32bitAbi = use32bitAbi;
+            this.preferCodeIntegrity = preferCodeIntegrity;
             this.extractNativeLibs = extractNativeLibs;
             this.isolatedSplits = isolatedSplits;
             this.isSplitRequired = isSplitRequired;
@@ -1722,6 +1724,7 @@
         boolean isolatedSplits = false;
         boolean isFeatureSplit = false;
         boolean isSplitRequired = false;
+        boolean preferCodeIntegrity = false;
         String configForSplit = null;
         String usesSplitName = null;
 
@@ -1784,6 +1787,9 @@
                     if ("extractNativeLibs".equals(attr)) {
                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                     }
+                    if ("preferCodeIntegrity".equals(attr)) {
+                        preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false);
+                    }
                 }
             } else if (TAG_USES_SPLIT.equals(parser.getName())) {
                 if (usesSplitName != null) {
@@ -1800,10 +1806,16 @@
             }
         }
 
+        if (preferCodeIntegrity && extractNativeLibs) {
+            throw new PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Can't request both preferCodeIntegrity and extractNativeLibs");
+        }
+
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
                 revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
-                multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
+                multiArch, use32bitAbi, preferCodeIntegrity, extractNativeLibs, isolatedSplits);
     }
 
     /**
@@ -3655,6 +3667,12 @@
         }
 
         if (sa.getBoolean(
+                R.styleable.AndroidManifestApplication_preferCodeIntegrity,
+                false)) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY;
+        }
+
+        if (sa.getBoolean(
                 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
                 false)) {
             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index a4c1332..dd782ec 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -60,6 +60,13 @@
         return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
     }
 
+    /**
+     * Returns {@code true} if display white balance is supported by the device.
+     */
+    public static boolean isDisplayWhiteBalanceAvailable(Context context) {
+        return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
+    }
+
     private static class ColorDisplayManagerInternal {
 
         private static ColorDisplayManagerInternal sInstance;
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index bac23b3..1630b06 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -975,14 +975,11 @@
             mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
         }
         final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
-        if (msg == null) {
-            return;
-        }
         final int clientInfo = acquireInfo == FACE_ACQUIRED_VENDOR
                 ? (vendorCode + FACE_ACQUIRED_VENDOR_BASE) : acquireInfo;
         if (mEnrollmentCallback != null) {
             mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
-        } else if (mAuthenticationCallback != null) {
+        } else if (mAuthenticationCallback != null && msg != null) {
             mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
         }
     }
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index f3810bd..fdadfbe 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -58,7 +58,7 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "GraphicsEnvironment";
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
-    private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0";
+    private static final String GUP_WHITELIST_FILENAME = "whitelist.txt";
     private static final String ANGLE_RULES_FILE = "a4a_rules.json";
     private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
     private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
@@ -567,22 +567,11 @@
 
     private static boolean onWhitelist(Context context, String driverPackageName,
             String applicationPackageName) {
-        String whitelistName = SystemProperties.get(PROPERTY_GFX_DRIVER_WHITELIST);
-
-        // Empty whitelist implies no updatable graphics driver. Typically, the pre-installed
-        // updatable graphics driver is supposed to be a place holder and contains no graphics
-        // driver and whitelist.
-        if (whitelistName == null || whitelistName.isEmpty()) {
-            if (DEBUG) {
-                Log.w(TAG, "No whitelist found.");
-            }
-            return false;
-        }
         try {
             Context driverContext = context.createPackageContext(driverPackageName,
                                                                  Context.CONTEXT_RESTRICTED);
             AssetManager assets = driverContext.getAssets();
-            InputStream stream = assets.open(whitelistName);
+            InputStream stream = assets.open(GUP_WHITELIST_FILENAME);
             BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
             for (String packageName; (packageName = reader.readLine()) != null; ) {
                 if (packageName.equals(applicationPackageName)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d93985c..65514b6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7957,6 +7957,15 @@
                 "night_display_last_activated_time";
 
         /**
+         * Control whether display white balance is currently enabled.
+         * @hide
+         */
+        public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled";
+
+        private static final Validator DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
+        /**
          * Names of the service components that the current user has explicitly allowed to
          * be a VR mode listener, separated by ':'.
          *
@@ -8405,6 +8414,7 @@
             NIGHT_DISPLAY_CUSTOM_END_TIME,
             NIGHT_DISPLAY_COLOR_TEMPERATURE,
             NIGHT_DISPLAY_AUTO_MODE,
+            DISPLAY_WHITE_BALANCE_ENABLED,
             SYNC_PARENT_SOUNDS,
             CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
             SWIPE_UP_TO_SWITCH_APPS_ENABLED,
@@ -8552,6 +8562,7 @@
             VALIDATORS.put(NIGHT_DISPLAY_COLOR_TEMPERATURE,
                     NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR);
             VALIDATORS.put(NIGHT_DISPLAY_AUTO_MODE, NIGHT_DISPLAY_AUTO_MODE_VALIDATOR);
+            VALIDATORS.put(DISPLAY_WHITE_BALANCE_ENABLED, DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR);
             VALIDATORS.put(SYNC_PARENT_SOUNDS, SYNC_PARENT_SOUNDS_VALIDATOR);
             VALIDATORS.put(CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
                     CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR);
diff --git a/core/java/android/service/autofill/CompositeUserData.java b/core/java/android/service/autofill/CompositeUserData.java
new file mode 100644
index 0000000..2df4ddf
--- /dev/null
+++ b/core/java/android/service/autofill/CompositeUserData.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Holds both a generic and package-specific userData used for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * @hide
+ */
+@TestApi
+public final class CompositeUserData implements FieldClassificationUserData, Parcelable {
+
+    private final UserData mGenericUserData;
+    private final UserData mPackageUserData;
+
+    private final String[] mCategories;
+    private final String[] mValues;
+
+    public CompositeUserData(@Nullable UserData genericUserData,
+            @NonNull UserData packageUserData) {
+        mGenericUserData = genericUserData;
+        mPackageUserData = packageUserData;
+
+        final String[] packageCategoryIds = mPackageUserData.getCategoryIds();
+        final String[] packageValues = mPackageUserData.getValues();
+
+        final ArrayList<String> categoryIds = new ArrayList<>(packageCategoryIds.length);
+        final ArrayList<String> values = new ArrayList<>(packageValues.length);
+
+        Collections.addAll(categoryIds, packageCategoryIds);
+        Collections.addAll(values, packageValues);
+
+        if (mGenericUserData != null) {
+            final String[] genericCategoryIds = mGenericUserData.getCategoryIds();
+            final String[] genericValues = mGenericUserData.getValues();
+            final int size = mGenericUserData.getCategoryIds().length;
+            for (int i = 0; i < size; i++) {
+                if (!categoryIds.contains(genericCategoryIds[i])) {
+                    categoryIds.add(genericCategoryIds[i]);
+                    values.add(genericValues[i]);
+                }
+            }
+        }
+
+        mCategories = new String[categoryIds.size()];
+        categoryIds.toArray(mCategories);
+        mValues = new String[values.size()];
+        values.toArray(mValues);
+    }
+
+    @Nullable
+    @Override
+    public String getFieldClassificationAlgorithm() {
+        final String packageDefaultAlgo = mPackageUserData.getFieldClassificationAlgorithm();
+        if (packageDefaultAlgo != null) {
+            return packageDefaultAlgo;
+        } else {
+            return mGenericUserData == null ? null :
+                    mGenericUserData.getFieldClassificationAlgorithm();
+        }
+    }
+
+    @Override
+    public Bundle getDefaultFieldClassificationArgs() {
+        final Bundle packageDefaultArgs = mPackageUserData.getDefaultFieldClassificationArgs();
+        if (packageDefaultArgs != null) {
+            return packageDefaultArgs;
+        } else {
+            return mGenericUserData == null ? null :
+                    mGenericUserData.getDefaultFieldClassificationArgs();
+        }
+    }
+
+    @Nullable
+    @Override
+    public String getFieldClassificationAlgorithmForCategory(@NonNull String categoryId) {
+        Preconditions.checkNotNull(categoryId);
+        final ArrayMap<String, String> categoryAlgorithms = getFieldClassificationAlgorithms();
+        if (categoryAlgorithms == null || !categoryAlgorithms.containsKey(categoryId)) {
+            return null;
+        }
+        return categoryAlgorithms.get(categoryId);
+    }
+
+    @Override
+    public ArrayMap<String, String> getFieldClassificationAlgorithms() {
+        final ArrayMap<String, String> packageAlgos = mPackageUserData
+                .getFieldClassificationAlgorithms();
+        final ArrayMap<String, String> genericAlgos = mGenericUserData == null ? null :
+                mGenericUserData.getFieldClassificationAlgorithms();
+
+        ArrayMap<String, String> categoryAlgorithms = null;
+        if (packageAlgos != null || genericAlgos != null) {
+            categoryAlgorithms = new ArrayMap<>();
+            if (genericAlgos != null) {
+                categoryAlgorithms.putAll(genericAlgos);
+            }
+            if (packageAlgos != null) {
+                categoryAlgorithms.putAll(packageAlgos);
+            }
+        }
+
+        return categoryAlgorithms;
+    }
+
+    @Override
+    public ArrayMap<String, Bundle> getFieldClassificationArgs() {
+        final ArrayMap<String, Bundle> packageArgs = mPackageUserData.getFieldClassificationArgs();
+        final ArrayMap<String, Bundle> genericArgs = mGenericUserData == null ? null :
+                mGenericUserData.getFieldClassificationArgs();
+
+        ArrayMap<String, Bundle> categoryArgs = null;
+        if (packageArgs != null || genericArgs != null) {
+            categoryArgs = new ArrayMap<>();
+            if (genericArgs != null) {
+                categoryArgs.putAll(genericArgs);
+            }
+            if (packageArgs != null) {
+                categoryArgs.putAll(packageArgs);
+            }
+        }
+
+        return categoryArgs;
+    }
+
+    @Override
+    public String[] getCategoryIds() {
+        return mCategories;
+    }
+
+    @Override
+    public String[] getValues() {
+        return mValues;
+    }
+
+    /////////////////////////////////////
+    // Object "contract" methods. //
+    /////////////////////////////////////
+    @Override
+    public String toString() {
+        if (!sDebug) return super.toString();
+
+        // OK to print UserData because UserData.toString() is PII-aware
+        final StringBuilder builder = new StringBuilder("genericUserData=")
+                .append(mGenericUserData)
+                .append(", packageUserData=").append(mPackageUserData);
+        return builder.toString();
+    }
+
+    /////////////////////////////////////
+    // Parcelable "contract" methods. //
+    /////////////////////////////////////
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mGenericUserData, 0);
+        parcel.writeParcelable(mPackageUserData, 0);
+    }
+
+    public static final Parcelable.Creator<CompositeUserData> CREATOR =
+            new Parcelable.Creator<CompositeUserData>() {
+                @Override
+                public CompositeUserData createFromParcel(Parcel parcel) {
+                    // Always go through the builder to ensure the data ingested by
+                    // the system obeys the contract of the builder to avoid attacks
+                    // using specially crafted parcels.
+                    final UserData genericUserData = parcel.readParcelable(null);
+                    final UserData packageUserData = parcel.readParcelable(null);
+                    return new CompositeUserData(genericUserData, packageUserData);
+                }
+
+                @Override
+                public CompositeUserData[] newArray(int size) {
+                    return new CompositeUserData[size];
+                }
+            };
+}
diff --git a/core/java/android/service/autofill/FieldClassificationUserData.java b/core/java/android/service/autofill/FieldClassificationUserData.java
new file mode 100644
index 0000000..3d6cac4
--- /dev/null
+++ b/core/java/android/service/autofill/FieldClassificationUserData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import android.os.Bundle;
+import android.util.ArrayMap;
+
+/**
+ * Class used to define a generic UserData for field classification
+ *
+ * @hide
+ */
+public interface FieldClassificationUserData {
+    /**
+     * Gets the name of the default algorithm that is used to calculate
+     * {@link FieldClassification.Match#getScore()} match scores}.
+     */
+    String getFieldClassificationAlgorithm();
+
+    /**
+     * Gets the default field classification args.
+     */
+    Bundle getDefaultFieldClassificationArgs();
+
+    /**
+     * Gets the name of the field classification algorithm for a specific category.
+     *
+     * @param categoryId id of the specific category.
+     */
+    String getFieldClassificationAlgorithmForCategory(String categoryId);
+
+    /**
+     * Gets all field classification algorithms for specific categories.
+     */
+    ArrayMap<String, String> getFieldClassificationAlgorithms();
+
+    /**
+     * Gets all field classification args for specific categories.
+     */
+    ArrayMap<String, Bundle> getFieldClassificationArgs();
+
+    /**
+     * Gets all category ids
+     */
+    String[] getCategoryIds();
+
+    /**
+     * Gets all string values for field classification
+     */
+    String[] getValues();
+}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d408e9a..93ee8c3 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -516,6 +516,9 @@
         /**
          * Sets a specific {@link UserData} for field classification for this request only.
          *
+         * <p>Any fields in this UserData will override corresponding fields in the generic
+         * UserData object
+         *
          * @return this builder
          * @throws IllegalStateException if the FillResponse
          * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index 37f1923..a793e09 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -48,7 +48,7 @@
  * Defines the user data used for
  * <a href="AutofillService.html#FieldClassification">field classification</a>.
  */
-public final class UserData implements Parcelable {
+public final class UserData implements FieldClassificationUserData, Parcelable {
 
     private static final String TAG = "UserData";
 
@@ -86,11 +86,13 @@
      * {@link Match#getScore()} match scores}.
      */
     @Nullable
+    @Override
     public String getFieldClassificationAlgorithm() {
         return mDefaultAlgorithm;
     }
 
     /** @hide */
+    @Override
     public Bundle getDefaultFieldClassificationArgs() {
         return mDefaultArgs;
     }
@@ -104,6 +106,7 @@
      * @return String name of algorithm, null if none found.
      */
     @Nullable
+    @Override
     public String getFieldClassificationAlgorithmForCategory(@NonNull String categoryId) {
         Preconditions.checkNotNull(categoryId);
         if (mCategoryAlgorithms == null || !mCategoryAlgorithms.containsKey(categoryId)) {
@@ -120,22 +123,26 @@
     }
 
     /** @hide */
+    @Override
     public String[] getCategoryIds() {
         return mCategoryIds;
     }
 
     /** @hide */
+    @Override
     public String[] getValues() {
         return mValues;
     }
 
     /** @hide */
     @TestApi
+    @Override
     public ArrayMap<String, String> getFieldClassificationAlgorithms() {
         return mCategoryAlgorithms;
     }
 
     /** @hide */
+    @Override
     public ArrayMap<String, Bundle> getFieldClassificationArgs() {
         return mCategoryArgs;
     }
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 5524506..f31ddd9 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -28,7 +28,7 @@
  * "integers from 1 to 100 inclusive."
  * </p>
  * <p>
- * All ranges are bounded, and the left side of the range is always {@code >=}
+ * All ranges are bounded, and the left side of the range is always {@code <=}
  * the right side of the range.
  * </p>
  *
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index a4d3ce7..be81c06 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -921,129 +921,129 @@
             AttributeSet attrs) throws XmlPullParserException, IOException {
         int type;
 
-        if (parent instanceof ViewGroup) {
-            // Apply a theme wrapper, if requested. This is sort of a weird
-            // edge case, since developers think the <include> overwrites
-            // values in the AttributeSet of the included View. So, if the
-            // included View has a theme attribute, we'll need to ignore it.
-            final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
-            final int themeResId = ta.getResourceId(0, 0);
-            final boolean hasThemeOverride = themeResId != 0;
-            if (hasThemeOverride) {
-                context = new ContextThemeWrapper(context, themeResId);
-            }
-            ta.recycle();
-
-            // If the layout is pointing to a theme attribute, we have to
-            // massage the value to get a resource identifier out of it.
-            int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
-            if (layout == 0) {
-                final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
-                if (value == null || value.length() <= 0) {
-                    throw new InflateException("You must specify a layout in the"
-                            + " include tag: <include layout=\"@layout/layoutID\" />");
-                }
-
-                // Attempt to resolve the "?attr/name" string to an attribute
-                // within the default (e.g. application) package.
-                layout = context.getResources().getIdentifier(
-                        value.substring(1), "attr", context.getPackageName());
-
-            }
-
-            // The layout might be referencing a theme attribute.
-            if (mTempValue == null) {
-                mTempValue = new TypedValue();
-            }
-            if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
-                layout = mTempValue.resourceId;
-            }
-
-            if (layout == 0) {
-                final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
-                throw new InflateException("You must specify a valid layout "
-                        + "reference. The layout ID " + value + " is not valid.");
-            } else {
-                final XmlResourceParser childParser = context.getResources().getLayout(layout);
-
-                try {
-                    final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
-
-                    while ((type = childParser.next()) != XmlPullParser.START_TAG &&
-                            type != XmlPullParser.END_DOCUMENT) {
-                        // Empty.
-                    }
-
-                    if (type != XmlPullParser.START_TAG) {
-                        throw new InflateException(childParser.getPositionDescription() +
-                                ": No start tag found!");
-                    }
-
-                    final String childName = childParser.getName();
-
-                    if (TAG_MERGE.equals(childName)) {
-                        // The <merge> tag doesn't support android:theme, so
-                        // nothing special to do here.
-                        rInflate(childParser, parent, context, childAttrs, false);
-                    } else {
-                        final View view = createViewFromTag(parent, childName,
-                                context, childAttrs, hasThemeOverride);
-                        final ViewGroup group = (ViewGroup) parent;
-
-                        final TypedArray a = context.obtainStyledAttributes(
-                                attrs, R.styleable.Include);
-                        final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
-                        final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                        a.recycle();
-
-                        // We try to load the layout params set in the <include /> tag.
-                        // If the parent can't generate layout params (ex. missing width
-                        // or height for the framework ViewGroups, though this is not
-                        // necessarily true of all ViewGroups) then we expect it to throw
-                        // a runtime exception.
-                        // We catch this exception and set localParams accordingly: true
-                        // means we successfully loaded layout params from the <include>
-                        // tag, false means we need to rely on the included layout params.
-                        ViewGroup.LayoutParams params = null;
-                        try {
-                            params = group.generateLayoutParams(attrs);
-                        } catch (RuntimeException e) {
-                            // Ignore, just fail over to child attrs.
-                        }
-                        if (params == null) {
-                            params = group.generateLayoutParams(childAttrs);
-                        }
-                        view.setLayoutParams(params);
-
-                        // Inflate all children.
-                        rInflateChildren(childParser, view, childAttrs, true);
-
-                        if (id != View.NO_ID) {
-                            view.setId(id);
-                        }
-
-                        switch (visibility) {
-                            case 0:
-                                view.setVisibility(View.VISIBLE);
-                                break;
-                            case 1:
-                                view.setVisibility(View.INVISIBLE);
-                                break;
-                            case 2:
-                                view.setVisibility(View.GONE);
-                                break;
-                        }
-
-                        group.addView(view);
-                    }
-                } finally {
-                    childParser.close();
-                }
-            }
-        } else {
+        if (!(parent instanceof ViewGroup)) {
             throw new InflateException("<include /> can only be used inside of a ViewGroup");
         }
 
+        // Apply a theme wrapper, if requested. This is sort of a weird
+        // edge case, since developers think the <include> overwrites
+        // values in the AttributeSet of the included View. So, if the
+        // included View has a theme attribute, we'll need to ignore it.
+        final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+        final int themeResId = ta.getResourceId(0, 0);
+        final boolean hasThemeOverride = themeResId != 0;
+        if (hasThemeOverride) {
+            context = new ContextThemeWrapper(context, themeResId);
+        }
+        ta.recycle();
+
+        // If the layout is pointing to a theme attribute, we have to
+        // massage the value to get a resource identifier out of it.
+        int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
+        if (layout == 0) {
+            final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+            if (value == null || value.length() <= 0) {
+                throw new InflateException("You must specify a layout in the"
+                    + " include tag: <include layout=\"@layout/layoutID\" />");
+            }
+
+            // Attempt to resolve the "?attr/name" string to an attribute
+            // within the default (e.g. application) package.
+            layout = context.getResources().getIdentifier(
+                value.substring(1), "attr", context.getPackageName());
+
+        }
+
+        // The layout might be referencing a theme attribute.
+        if (mTempValue == null) {
+            mTempValue = new TypedValue();
+        }
+        if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
+            layout = mTempValue.resourceId;
+        }
+
+        if (layout == 0) {
+            final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+            throw new InflateException("You must specify a valid layout "
+                + "reference. The layout ID " + value + " is not valid.");
+        }
+
+        final XmlResourceParser childParser = context.getResources().getLayout(layout);
+
+        try {
+            final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+
+            while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                type != XmlPullParser.END_DOCUMENT) {
+                // Empty.
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new InflateException(childParser.getPositionDescription() +
+                    ": No start tag found!");
+            }
+
+            final String childName = childParser.getName();
+
+            if (TAG_MERGE.equals(childName)) {
+                // The <merge> tag doesn't support android:theme, so
+                // nothing special to do here.
+                rInflate(childParser, parent, context, childAttrs, false);
+            } else {
+                final View view = createViewFromTag(parent, childName,
+                    context, childAttrs, hasThemeOverride);
+                final ViewGroup group = (ViewGroup) parent;
+
+                final TypedArray a = context.obtainStyledAttributes(
+                    attrs, R.styleable.Include);
+                final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                a.recycle();
+
+                // We try to load the layout params set in the <include /> tag.
+                // If the parent can't generate layout params (ex. missing width
+                // or height for the framework ViewGroups, though this is not
+                // necessarily true of all ViewGroups) then we expect it to throw
+                // a runtime exception.
+                // We catch this exception and set localParams accordingly: true
+                // means we successfully loaded layout params from the <include>
+                // tag, false means we need to rely on the included layout params.
+                ViewGroup.LayoutParams params = null;
+                try {
+                    params = group.generateLayoutParams(attrs);
+                } catch (RuntimeException e) {
+                    // Ignore, just fail over to child attrs.
+                }
+                if (params == null) {
+                    params = group.generateLayoutParams(childAttrs);
+                }
+                view.setLayoutParams(params);
+
+                // Inflate all children.
+                rInflateChildren(childParser, view, childAttrs, true);
+
+                if (id != View.NO_ID) {
+                    view.setId(id);
+                }
+
+                switch (visibility) {
+                    case 0:
+                        view.setVisibility(View.VISIBLE);
+                        break;
+                    case 1:
+                        view.setVisibility(View.INVISIBLE);
+                        break;
+                    case 2:
+                        view.setVisibility(View.GONE);
+                        break;
+                }
+
+                group.addView(view);
+            }
+        } finally {
+            childParser.close();
+        }
+
         LayoutInflater.consumeChildElements(parser);
     }
 
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index ea6f2fe..92e0187 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -258,14 +258,27 @@
             }
             mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
         }
-        mEvents.add(event);
+
+        if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+            final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
+
+            // TODO(b/121045053): check if flags match
+            if (lastEvent.getType() == TYPE_VIEW_TEXT_CHANGED
+                    && lastEvent.getId().equals(event.getId())) {
+                if (VERBOSE) {
+                    Log.v(mTag, "Buffering VIEW_TEXT_CHANGED event, updated text = "
+                            + event.getText());
+                }
+                lastEvent.setText(event.getText());
+            } else {
+                mEvents.add(event);
+            }
+        } else {
+            mEvents.add(event);
+        }
 
         final int numberEvents = mEvents.size();
 
-        // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are
-        // buffered (either total or per autofillid). For
-        // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer
-        // "a" and "b" then send "abc".
         final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
 
         if (bufferEvent && !forceFlush) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 414cb8f..bad2dbf 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -850,7 +850,7 @@
 
     /**
      * Asynchronously evaluates JavaScript in the context of the currently displayed page.
-     * If non-null, |resultCallback| will be invoked with any result returned from that
+     * If non-null, {@code resultCallback} will be invoked with any result returned from that
      * execution. This method must be called on the UI thread and the callback will
      * be made on the UI thread.
      * <p>
diff --git a/core/jni/android/graphics/text/LineBreaker.cpp b/core/jni/android/graphics/text/LineBreaker.cpp
index e1f2f2b..c23f1e9 100644
--- a/core/jni/android/graphics/text/LineBreaker.cpp
+++ b/core/jni/android/graphics/text/LineBreaker.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "LineBreaker"
 
-#include "unicode/locid.h"
-#include "unicode/brkiter.h"
 #include "utils/misc.h"
 #include "utils/Log.h"
 #include <nativehelper/ScopedStringChars.h>
diff --git a/core/jni/android/graphics/text/MeasuredText.cpp b/core/jni/android/graphics/text/MeasuredText.cpp
index d7d96fb..68ba38b 100644
--- a/core/jni/android/graphics/text/MeasuredText.cpp
+++ b/core/jni/android/graphics/text/MeasuredText.cpp
@@ -17,8 +17,6 @@
 #define LOG_TAG "MeasuredText"
 
 #include "GraphicsJNI.h"
-#include "unicode/locid.h"
-#include "unicode/brkiter.h"
 #include "utils/misc.h"
 #include "utils/Log.h"
 #include <nativehelper/ScopedStringChars.h>
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 29d8f30..80560f8 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1906,6 +1906,53 @@
     return jStatus;
 }
 
+static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
+        jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) {
+    if (deviceTypes == nullptr || deviceAddresses == nullptr) {
+        return (jint) AUDIO_JAVA_BAD_VALUE;
+    }
+    jsize nb = env->GetArrayLength(deviceTypes);
+    if (nb == 0 || nb != env->GetArrayLength(deviceAddresses)) {
+        return (jint) AUDIO_JAVA_BAD_VALUE;
+    }
+    // retrieve all device types
+    std::vector<audio_devices_t> deviceTypesVector;
+    jint* typesPtr = nullptr;
+    typesPtr = env->GetIntArrayElements(deviceTypes, 0);
+    if (typesPtr == nullptr) {
+        return (jint) AUDIO_JAVA_BAD_VALUE;
+    }
+    for (jint i = 0; i < nb; i++) {
+        deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
+    }
+    env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
+
+    // check each address is a string and add device type/address to list for device affinity
+    Vector<AudioDeviceTypeAddr> deviceVector;
+    jclass stringClass = FindClassOrDie(env, "java/lang/String");
+    for (jint i = 0; i < nb; i++) {
+        jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
+        if (!env->IsInstanceOf(addrJobj, stringClass)) {
+            return (jint) AUDIO_JAVA_BAD_VALUE;
+        }
+        String8 address = String8(env->GetStringUTFChars((jstring) addrJobj, NULL));
+        AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
+        deviceVector.add(dev);
+    }
+
+    status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
+    return (jint) nativeToJavaStatus(status);
+}
+
+static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, jobject clazz,
+        jint uid) {
+
+    //###
+    status_t status = NO_ERROR;//AudioSystem::removeUidDeviceAffinities();
+    return (jint) nativeToJavaStatus(status);
+}
+
+
 static jint
 android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
 {
@@ -2133,6 +2180,10 @@
                                     (void *)android_media_AudioSystem_getAudioHwSyncForSession},
     {"registerPolicyMixes",    "(Ljava/util/ArrayList;Z)I",
                                             (void *)android_media_AudioSystem_registerPolicyMixes},
+    {"setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+                                        (void *)android_media_AudioSystem_setUidDeviceAffinities},
+    {"removeUidDeviceAffinities", "(I)I",
+                                        (void *)android_media_AudioSystem_removeUidDeviceAffinities},
     {"native_register_dynamic_policy_callback", "()V",
                                     (void *)android_media_AudioSystem_registerDynPolicyCallback},
     {"native_register_recording_callback", "()V",
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 60561bd..6f9a564 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -82,6 +82,7 @@
     repeated ActivityStackProto stacks = 3;
     optional int32 focused_stack_id = 4;
     optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
+    optional bool single_task_instance = 6;
 }
 
 message ActivityStackProto {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dd51cb6..54f6c63 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1112,6 +1112,11 @@
          resource] to be present in order to function. Default value is false. -->
     <attr name="isSplitRequired" format="boolean" />
 
+    <!-- Flag to specify if this app prioritizes code integrity. The system may choose
+         to run with better integrity guarantee in various components if possible based on the app's
+         <code>targetSdkVersion</code>. -->
+    <attr name="preferCodeIntegrity" format="boolean" />
+
     <!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or
          {@code <application>} tag. If specified on the {@code <application>}
          tag these will be considered defaults for all activities in the
@@ -1580,6 +1585,7 @@
              to honor this flag as well. -->
         <attr name="usesCleartextTraffic" />
         <attr name="multiArch" />
+        <attr name="preferCodeIntegrity" />
         <attr name="extractNativeLibs" />
         <attr name="defaultToDeviceProtectedStorage" format="boolean" />
         <attr name="directBootAware" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 11cc1f5..e4abf8f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -929,6 +929,9 @@
          in hardware. -->
     <bool name="config_setColorTransformAccelerated">false</bool>
 
+    <!-- Boolean indicating whether display white balance is supported. -->
+    <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
     <!-- Control whether Night display is available. This should only be enabled on devices
          that have a HWC implementation that can apply the matrix passed to setColorTransform
          without impacting power, performance, and app compatibility (e.g. protected content). -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d383362..2b95dd0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3072,7 +3072,7 @@
     <!-- Title of intent resolver dialog when selecting a viewer application that opens URI
          and a previously used application is known [CHAR LIMIT=128]. -->
     <string name="whichGiveAccessToApplicationNamed">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with <xliff:g id="application" example="Gmail">%2$s</xliff:g></string>
-    <!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=16] -->
+    <!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=18] -->
     <string name="whichGiveAccessToApplicationLabel">Give access</string>
     <!-- Title of intent resolver dialog when selecting an editor application to run. -->
     <string name="whichEditApplication">Edit with</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 7c95d1e..200ef2f 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -355,6 +355,30 @@
         <item name="fontFamily">@string/config_bodyFontFamilyMedium</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Widget.Toolbar.Title" parent="TextAppearance.DeviceDefault.Widget.ActionBar.Title"/>
+    <style name="TextAppearance.DeviceDefault.Widget.Toolbar.Subtitle" parent="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.Body1" parent="TextAppearance.Material.Body1">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Body2" parent="TextAppearance.Material.Body2">
+        <item name="fontFamily">@string/config_bodyFontFamilyMedium</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Subhead" parent="TextAppearance.Material.Subhead">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Headline" parent="TextAppearance.Material.Headline">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Display1" parent="TextAppearance.Material.Display1">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Title" parent="TextAppearance.Material.Title">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.Caption" parent="TextAppearance.Material.Caption">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
+    <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead"/>
+    <style name="TextAppearance.DeviceDefault.ListItemSecondary" parent="TextAppearance.DeviceDefault.Body1"/>
 
     <!-- Preference Styles -->
     <style name="Preference.DeviceDefault" parent="Preference.Material"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eda25b3..e8cbf66 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3028,6 +3028,7 @@
   <java-symbol type="drawable" name="ic_doc_generic" />
 
   <java-symbol type="bool" name="config_setColorTransformAccelerated" />
+  <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
   <java-symbol type="bool" name="config_nightDisplayAvailable" />
   <java-symbol type="bool" name="config_allowDisablingAssistDisclosure" />
   <java-symbol type="integer" name="config_defaultNightDisplayAutoMode" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 56265cc..0f4ca66 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -68,6 +68,10 @@
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
 
+        <item name="textAppearanceListItem">@style/TextAppearance.DeviceDefault.ListItem</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.DeviceDefault.ListItem</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.DeviceDefault.ListItemSecondary</item>
+
         <!-- Button styles -->
         <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
         <item name="buttonStyle">@style/Widget.DeviceDefault.Button</item>
@@ -783,7 +787,6 @@
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
         <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
-
         <item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
         <item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
         <item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
@@ -792,11 +795,12 @@
         <item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
         <item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
         <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
-
         <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
-
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+        <item name="textAppearanceListItem">@style/TextAppearance.DeviceDefault.ListItem</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.DeviceDefault.ListItem</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.DeviceDefault.ListItemSecondary</item>
 
         <!-- Button styles -->
         <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
@@ -1439,19 +1443,23 @@
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
-    <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
+    <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault.Light">
+        <!-- From Theme.Material.Light.LightStatusBar -->
+        <item name="windowLightStatusBar">true</item>
+
+        <!-- From Theme.Material.Settings -->
+        <item name="homeAsUpIndicator">@drawable/ic_ab_back_material_settings</item>
+        <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
+        <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
+        <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
+
         <!-- action bar -->
-        <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
         <item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar</item>
         <item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
 
         <!-- Color palette -->
-        <item name="colorBackground">@color/background_device_default_light</item>
-        <item name="colorPrimary">@color/primary_device_default_settings_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
-        <item name="colorAccent">@color/accent_device_default_light</item>
-        <item name="colorError">@color/error_color_device_default_light</item>
         <item name="colorEdgeEffect">@android:color/black</item>
 
         <!-- Add white nav bar with divider that matches material -->
@@ -1459,24 +1467,9 @@
         <item name="navigationBarColor">@android:color/white</item>
         <item name="windowLightNavigationBar">true</item>
 
-        <!-- Dialog attributes -->
-        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
-        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
-
-        <!-- Text styles -->
-        <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
-
         <!-- Button styles -->
-        <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
         <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
 
-        <!-- Progress bar attributes -->
-        <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
-        <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
-
-        <!-- Toolbar attributes -->
-        <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
-
         <item name="listDivider">@color/list_divider_color_light</item>
     </style>
 
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index bd1e6c5..14e3a32 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -41,14 +41,10 @@
 X(DrawImageNine) 
 X(DrawImageRect) 
 X(DrawImageLattice)
-X(DrawText) 
-X(DrawPosText) 
-X(DrawPosTextH)
-X(DrawTextRSXform) 
 X(DrawTextBlob)
 X(DrawPatch) 
 X(DrawPoints) 
 X(DrawVertices) 
 X(DrawAtlas) 
 X(DrawShadowRec)
-X(DrawVectorDrawable)
\ No newline at end of file
+X(DrawVectorDrawable)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4de25f9..6dc9d34 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -373,61 +373,6 @@
     }
 };
 
-struct DrawText final : Op {
-    static const auto kType = Type::DrawText;
-    DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint)
-            : bytes(bytes), x(x), y(y), paint(paint) {}
-    size_t bytes;
-    SkScalar x, y;
-    SkPaint paint;
-    void draw(SkCanvas* c, const SkMatrix&) const {
-        c->drawText(pod<void>(this), bytes, x, y, paint);
-    }
-};
-struct DrawPosText final : Op {
-    static const auto kType = Type::DrawPosText;
-    DrawPosText(size_t bytes, const SkPaint& paint, int n) : bytes(bytes), paint(paint), n(n) {}
-    size_t bytes;
-    SkPaint paint;
-    int n;
-    void draw(SkCanvas* c, const SkMatrix&) const {
-        auto points = pod<SkPoint>(this);
-        auto text = pod<void>(this, n * sizeof(SkPoint));
-        c->drawPosText(text, bytes, points, paint);
-    }
-};
-struct DrawPosTextH final : Op {
-    static const auto kType = Type::DrawPosTextH;
-    DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n)
-            : bytes(bytes), y(y), paint(paint), n(n) {}
-    size_t bytes;
-    SkScalar y;
-    SkPaint paint;
-    int n;
-    void draw(SkCanvas* c, const SkMatrix&) const {
-        auto xs = pod<SkScalar>(this);
-        auto text = pod<void>(this, n * sizeof(SkScalar));
-        c->drawPosTextH(text, bytes, xs, y, paint);
-    }
-};
-struct DrawTextRSXform final : Op {
-    static const auto kType = Type::DrawTextRSXform;
-    DrawTextRSXform(size_t bytes, int xforms, const SkRect* cull, const SkPaint& paint)
-            : bytes(bytes), xforms(xforms), paint(paint) {
-        if (cull) {
-            this->cull = *cull;
-        }
-    }
-    size_t bytes;
-    int xforms;
-    SkRect cull = kUnset;
-    SkPaint paint;
-    void draw(SkCanvas* c, const SkMatrix&) const {
-        // For alignment, the SkRSXforms are first in the pod section, followed by the text.
-        c->drawTextRSXform(pod<void>(this, xforms * sizeof(SkRSXform)), bytes, pod<SkRSXform>(this),
-                           maybe_unset(cull), paint);
-    }
-};
 struct DrawTextBlob final : Op {
     static const auto kType = Type::DrawTextBlob;
     DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
@@ -682,33 +627,6 @@
            fs);
 }
 
-void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y,
-                               const SkPaint& paint) {
-    void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
-    copy_v(pod, (const char*)text, bytes);
-    mHasText = true;
-}
-void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[],
-                                  const SkPaint& paint) {
-    int n = paint.countText(text, bytes);
-    void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n);
-    copy_v(pod, pos, n, (const char*)text, bytes);
-    mHasText = true;
-}
-void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y,
-                                   const SkPaint& paint) {
-    int n = paint.countText(text, bytes);
-    void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n);
-    copy_v(pod, xs, n, (const char*)text, bytes);
-    mHasText = true;
-}
-void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[],
-                                      const SkRect* cull, const SkPaint& paint) {
-    int n = paint.countText(text, bytes);
-    void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint);
-    copy_v(pod, xforms, n, (const char*)text, bytes);
-    mHasText = true;
-}
 void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                    const SkPaint& paint) {
     this->push<DrawTextBlob>(0, blob, x, y, paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index ae3c4f05..caaef67 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -101,10 +101,6 @@
     void drawDrawable(SkDrawable*, const SkMatrix*);
     void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
 
-    void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&);
-    void drawPosText(const void*, size_t, const SkPoint[], const SkPaint&);
-    void drawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&);
-    void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&);
     void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
 
     void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index 9a1ee54..4111bd2 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -16,7 +16,7 @@
 
 #include "TestSceneBase.h"
 #include "tests/common/TestListViewSceneBase.h"
-
+#include <SkFont.h>
 #include <cstdio>
 
 class ListViewAnimation;
@@ -46,11 +46,13 @@
                 SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
                 128 * 3;
         paint.setColor(bgDark ? Color::White : Color::Grey_700);
-        paint.setTextSize(size / 2);
+
+	SkFont font;
+        font.setSize(size / 2);
         char charToShow = 'A' + (rand() % 26);
-        const SkPoint pos[] = {{SkIntToScalar(size / 2),
-                                /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
-        canvas.drawPosText(&charToShow, 1, pos, paint);
+        const SkPoint pos = {SkIntToScalar(size / 2),
+                                /*approximate centering*/ SkFloatToScalar(size * 0.7f)};
+        canvas.drawSimpleText(&charToShow, 1, kUTF8_SkTextEncoding, pos.fX, pos.fY, font, paint);
         return bitmap;
     }
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 63eefe0..30b5480 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4280,9 +4280,8 @@
      * Return codes for listAudioPorts(), createAudioPatch() ...
      */
 
-    /** @hide
-     * CANDIDATE FOR PUBLIC API
-     */
+    /** @hide */
+    @SystemApi
     public static final int SUCCESS = AudioSystem.SUCCESS;
     /**
      * A default error code.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 58fc1ab..45cde0f 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -916,6 +916,13 @@
 
     public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
 
+    /** see AudioPolicy.setUidDeviceAffinities() */
+    public static native int setUidDeviceAffinities(int uid, @NonNull int[] types,
+            @NonNull String[] addresses);
+
+    /** see AudioPolicy.removeUidDeviceAffinities() */
+    public static native int removeUidDeviceAffinities(int uid);
+
     public static native int systemReady();
 
     public static native float getStreamVolumeDB(int stream, int index, int device);
diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java
index 2601ff7..a62db5f 100644
--- a/media/java/android/media/Controller2Link.java
+++ b/media/java/android/media/Controller2Link.java
@@ -25,8 +25,7 @@
 import java.util.Objects;
 
 /**
- * Handles incoming commands from {@link MediaSession2} and {@link MediaLibrarySession}
- * to both {@link MediaController2} and {@link MediaBrowser2}.
+ * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
  * @hide
  */
 // @SystemApi
@@ -90,7 +89,7 @@
         try {
             mIController.notifyConnected(seq, connectionResult);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
         }
     }
 
@@ -99,7 +98,7 @@
         try {
             mIController.notifyDisconnected(seq);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
         }
     }
 
@@ -109,7 +108,16 @@
         try {
             mIController.sendSessionCommand(seq, command, args, resultReceiver);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaController2.cancelSessionCommand */
+    public void cancelSessionCommand(int seq) {
+        try {
+            mIController.cancelSessionCommand(seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -133,6 +141,11 @@
         mController.onSessionCommand(seq, command, args, resultReceiver);
     }
 
+    /** Stub implementation for IMediaController2.cancelSessionCommand */
+    public void onCancelCommand(int seq) {
+        mController.onCancelCommand(seq);
+    }
+
     private class Controller2Stub extends IMediaController2.Stub {
         @Override
         public void notifyConnected(int seq, Bundle connectionResult) {
@@ -149,5 +162,10 @@
                 ResultReceiver resultReceiver) {
             Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
         }
+
+        @Override
+        public void cancelSessionCommand(int seq) {
+            Controller2Link.this.onCancelCommand(seq);
+        }
     }
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index abd6411..9fbd7ea 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -223,6 +223,11 @@
 
     boolean isAudioServerRunning();
 
+    int setUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid, in int[] deviceTypes,
+             in String[] deviceAddresses);
+
+    int removeUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid);
+
     // WARNING: read warning at top of file, new methods that need to be used by native
     // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/IMediaController2.aidl b/media/java/android/media/IMediaController2.aidl
index df34a11..ca5394f 100644
--- a/media/java/android/media/IMediaController2.aidl
+++ b/media/java/android/media/IMediaController2.aidl
@@ -33,4 +33,6 @@
     void notifyDisconnected(int seq) = 1;
     void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
             in ResultReceiver resultReceiver) = 2;
+    void cancelSessionCommand(int seq) = 3;
+    // Next Id : 4
 }
diff --git a/media/java/android/media/IMediaSession2.aidl b/media/java/android/media/IMediaSession2.aidl
index f6e74cf..26e717b 100644
--- a/media/java/android/media/IMediaSession2.aidl
+++ b/media/java/android/media/IMediaSession2.aidl
@@ -34,5 +34,6 @@
     void disconnect(in Controller2Link caller, int seq) = 1;
     void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand,
             in Bundle args, in ResultReceiver resultReceiver) = 2;
-    // Next Id : 3
+    void cancelSessionCommand(in Controller2Link caller, int seq) = 3;
+    // Next Id : 4
 }
diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java
index ffdca16d8..275b0ac 100644
--- a/media/java/android/media/MediaConstants.java
+++ b/media/java/android/media/MediaConstants.java
@@ -16,7 +16,6 @@
 
 package android.media;
 
-// Code for AML only
 class MediaConstants {
     // Bundle key for int
     static final String KEY_PID = "android.media.key.PID";
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 4ef56c8..7665c92 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -20,6 +20,8 @@
 import static android.media.MediaConstants.KEY_PACKAGE_NAME;
 import static android.media.MediaConstants.KEY_PID;
 import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
 
 import android.annotation.NonNull;
@@ -31,6 +33,8 @@
 import android.os.IBinder;
 import android.os.Process;
 import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 
 import java.util.concurrent.Executor;
@@ -69,6 +73,21 @@
     private Session2CommandGroup mAllowedCommands;
     //@GuardedBy("mLock")
     private Session2Token mConnectedToken;
+    //@GuardedBy("mLock")
+    private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+    //@GuardedBy("mLock")
+    private ArraySet<Integer> mRequestedCommandSeqNumbers;
+
+    /**
+     * Create a {@link MediaController2} from the {@link Session2Token}.
+     * This connects to the session and may wake up the service if it's not available.
+     *
+     * @param context Context
+     * @param token token to connect to
+     */
+    public MediaController2(@NonNull Context context, @NonNull Session2Token token) {
+        this(context, token, context.getMainExecutor(), new ControllerCallback() {});
+    }
 
     /**
      * Create a {@link MediaController2} from the {@link Session2Token}.
@@ -77,31 +96,27 @@
      * @param context Context
      * @param token token to connect to
      * @param executor executor to run callbacks on.
-     * @param callback controller callback to receive changes in
+     * @param callback controller callback to receive changes in.
      */
-    public MediaController2(@NonNull final Context context, @NonNull final Session2Token token,
-            @NonNull final Executor executor, @NonNull final ControllerCallback callback) {
+    public MediaController2(@NonNull Context context, @NonNull Session2Token token,
+            @NonNull Executor executor, @NonNull ControllerCallback callback) {
         if (context == null) {
             throw new IllegalArgumentException("context shouldn't be null");
         }
         if (token == null) {
             throw new IllegalArgumentException("token shouldn't be null");
         }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback shouldn't be null");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("executor shouldn't be null");
-        }
         mContext = context;
         mSessionToken = token;
-        mCallbackExecutor = executor;
-        mCallback = callback;
+        mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor;
+        mCallback = (callback == null) ? new ControllerCallback() { } : callback;
         mControllerStub = new Controller2Link(this);
         // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
         mResultHandler = new Handler(context.getMainLooper());
 
         mNextSeqNumber = 0;
+        mPendingCommands = new ArrayMap<>();
+        mRequestedCommandSeqNumbers = new ArraySet<>();
 
         if (token.getType() == TYPE_SESSION) {
             connectToSession();
@@ -116,11 +131,13 @@
             if (mSessionBinder != null) {
                 try {
                     mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
-                    mSessionBinder.disconnect(mControllerStub, mNextSeqNumber++);
+                    mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
                 } catch (RuntimeException e)  {
                     // No-op
                 }
             }
+            mPendingCommands.clear();
+            mRequestedCommandSeqNumbers.clear();
             mCallbackExecutor.execute(() -> {
                 mCallback.onDisconnected(MediaController2.this);
             });
@@ -134,9 +151,8 @@
      * @param command the session command
      * @param args optional arguments
      * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
-     *     when its result is received.
+     *        when its result is received.
      */
-    // TODO: make cancelable.
     public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
@@ -144,26 +160,50 @@
 
         ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
             protected void onReceiveResult(int resultCode, Bundle resultData) {
+                synchronized (mLock) {
+                    mPendingCommands.remove(this);
+                }
                 mCallbackExecutor.execute(() -> {
                     mCallback.onCommandResult(MediaController2.this, this,
-                            command, resultData);
+                            command, new Session2Command.Result(resultCode, resultData));
                 });
             }
         };
 
         synchronized (mLock) {
             if (mSessionBinder != null) {
+                int seq = getNextSeqNumber();
+                mPendingCommands.put(resultReceiver, seq);
                 try {
-                    mSessionBinder.sendSessionCommand(mControllerStub, mNextSeqNumber++,
-                            command, args, resultReceiver);
+                    mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args,
+                            resultReceiver);
                 } catch (RuntimeException e)  {
-                    // No-op
+                    mPendingCommands.remove(resultReceiver);
+                    resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
                 }
             }
         }
         return resultReceiver;
     }
 
+    /**
+     * Cancels the session command previously sent.
+     *
+     * @param token the token which is returned from {@link #sendSessionCommand}.
+     */
+    public void cancelSessionCommand(@NonNull Object token) {
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        synchronized (mLock) {
+            if (mSessionBinder == null) return;
+            Integer seq = mPendingCommands.remove(token);
+            if (seq != null) {
+                mSessionBinder.cancelSessionCommand(mControllerStub, seq);
+            }
+        }
+    }
+
     // Called by Controller2Link.onConnected
     void onConnected(int seq, Bundle connectionResult) {
         final long token = Binder.clearCallingIdentity();
@@ -213,10 +253,26 @@
             @Nullable ResultReceiver resultReceiver) {
         final long token = Binder.clearCallingIdentity();
         try {
+            synchronized (mLock) {
+                mRequestedCommandSeqNumbers.add(seq);
+            }
             mCallbackExecutor.execute(() -> {
-                Bundle result = mCallback.onSessionCommand(MediaController2.this, command, args);
+                boolean isCanceled;
+                synchronized (mLock) {
+                    isCanceled = !mRequestedCommandSeqNumbers.remove(seq);
+                }
+                if (isCanceled) {
+                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
+                    return;
+                }
+                Session2Command.Result result = mCallback.onSessionCommand(
+                        MediaController2.this, command, args);
                 if (resultReceiver != null) {
-                    resultReceiver.send(0, result);
+                    if (result == null) {
+                        throw new RuntimeException("onSessionCommand shouldn't return null");
+                    } else {
+                        resultReceiver.send(result.getResultCode(), result.getResultData());
+                    }
                 }
             });
         } finally {
@@ -224,6 +280,18 @@
         }
     }
 
+    // Called by Controller2Link.onSessionCommand
+    void onCancelCommand(int seq) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                mRequestedCommandSeqNumbers.remove(seq);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private int getNextSeqNumber() {
         synchronized (mLock) {
             return mNextSeqNumber++;
@@ -278,9 +346,11 @@
          * @param controller the controller for this event
          * @param command the session command
          * @param args optional arguments
-         * @return the result for the session command
+         * @return the result for the session command. A runtime exception will be thrown if null
+         *         is returned.
          */
-        public Bundle onSessionCommand(@NonNull MediaController2 controller,
+        @NonNull
+        public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
                 @NonNull Session2Command command, @Nullable Bundle args) {
             return null;
         }
@@ -294,7 +364,6 @@
          * @param result the result of the session command
          */
         public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
-                @NonNull Session2Command command, @Nullable Bundle result) {
-        }
+                @NonNull Session2Command command, @NonNull Session2Command.Result result) { }
     }
 }
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index d67c662..b874ba46 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -20,6 +20,8 @@
 import static android.media.MediaConstants.KEY_PACKAGE_NAME;
 import static android.media.MediaConstants.KEY_PID;
 import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
 import static android.media.Session2Token.TYPE_SESSION;
 
 import android.annotation.NonNull;
@@ -34,6 +36,8 @@
 import android.os.Handler;
 import android.os.Process;
 import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -112,7 +116,7 @@
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() {
         try {
             synchronized (MediaSession2.class) {
                 SESSION_ID_LIST.remove(mSessionId);
@@ -120,6 +124,7 @@
             Collection<ControllerInfo> controllerInfos;
             synchronized (mLock) {
                 controllerInfos = mConnectedControllers.values();
+                mConnectedControllers.clear();
                 mClosed = true;
             }
             for (ControllerInfo info : controllerInfos) {
@@ -131,6 +136,22 @@
     }
 
     /**
+     * Returns the session ID
+     */
+    @NonNull
+    public String getSessionId() {
+        return mSessionId;
+    }
+
+    /**
+     * Returns the {@link Session2Token} for creating {@link MediaController2}.
+     */
+    @NonNull
+    public Session2Token getSessionToken() {
+        return mSessionToken;
+    }
+
+    /**
      * Broadcasts a session command to all the connected controllers
      * <p>
      * @param command the session command
@@ -158,7 +179,6 @@
      * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
      *     when its result is received.
      */
-    // TODO: make cancelable.
     public Object sendSessionCommand(@NonNull ControllerInfo controller,
             @NonNull Session2Command command, @Nullable Bundle args) {
         if (controller == null) {
@@ -169,9 +189,10 @@
         }
         ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
             protected void onReceiveResult(int resultCode, Bundle resultData) {
+                controller.receiveCommandResult(this);
                 mCallbackExecutor.execute(() -> {
                     mCallback.onCommandResult(MediaSession2.this, controller, this,
-                            command, resultData);
+                            command, new Session2Command.Result(resultCode, resultData));
                 });
             }
         };
@@ -179,6 +200,19 @@
         return resultReceiver;
     }
 
+    /**
+     * Cancels the session command previously sent.
+     *
+     * @param controller the controller to get the session command
+     * @param token the token which is returned from {@link #sendSessionCommand}.
+     */
+    public void cancelSessionCommand(ControllerInfo controller, Object token) {
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        controller.cancelSessionCommand(token);
+    }
+
     boolean isClosed() {
         synchronized (mLock) {
             return mClosed;
@@ -296,15 +330,23 @@
         // TODO: check allowed commands.
         final long token = Binder.clearCallingIdentity();
         try {
+            synchronized (mLock) {
+                controllerInfo.addRequestedCommandSeqNumber(seq);
+            }
+
             mCallbackExecutor.execute(() -> {
-                try {
-                    Bundle result = mCallback.onSessionCommand(
-                            MediaSession2.this, controllerInfo, command, args);
-                    if (resultReceiver != null) {
-                        resultReceiver.send(0, result);
+                if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
+                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
+                    return;
+                }
+                Session2Command.Result result = mCallback.onSessionCommand(
+                        MediaSession2.this, controllerInfo, command, args);
+                if (resultReceiver != null) {
+                    if (result == null) {
+                        throw new RuntimeException("onSessionCommand shouldn't return null");
+                    } else {
+                        resultReceiver.send(result.getResultCode(), result.getResultData());
                     }
-                } catch (RuntimeException e) {
-                    // Controller may be died prematurely.
                 }
             });
         } finally {
@@ -312,6 +354,24 @@
         }
     }
 
+    // Called by Session2Link.onCancelCommand
+    void onCancelCommand(final Controller2Link controller, final int seq) {
+        final ControllerInfo controllerInfo;
+        synchronized (mLock) {
+            controllerInfo = mConnectedControllers.get(controller);
+        }
+        if (controllerInfo == null) {
+            return;
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            controllerInfo.removeRequestedCommandSeqNumber(seq);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     /**
      * Builder for {@link MediaSession2}.
      * <p>
@@ -417,7 +477,13 @@
         private final RemoteUserInfo mRemoteUserInfo;
         private final boolean mIsTrusted;
         private final Controller2Link mControllerBinder;
+        private final Object mLock = new Object();
+        //@GuardedBy("mLock")
         private int mNextSeqNumber;
+        //@GuardedBy("mLock")
+        private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+        //@GuardedBy("mLock")
+        private ArraySet<Integer> mRequestedCommandSeqNumbers;
 
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         Session2CommandGroup mAllowedCommands;
@@ -425,15 +491,15 @@
         /**
          * @param remoteUserInfo remote user info
          * @param trusted {@code true} if trusted, {@code false} otherwise
-         * @param controllerBinder Controller2Link. Can be {@code null} only when a
-         *           MediaBrowserCompat connects to MediaSessionService and ControllerInfo is
-         *           needed for SessionCallback#onConnected().
+         * @param controllerBinder Controller2Link for the connected controller.
          */
         ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
                 @Nullable Controller2Link controllerBinder) {
             mRemoteUserInfo = remoteUserInfo;
             mIsTrusted = trusted;
             mControllerBinder = controllerBinder;
+            mPendingCommands = new ArrayMap<>();
+            mRequestedCommandSeqNumbers = new ArraySet<>();
         }
 
         /**
@@ -517,16 +583,53 @@
         void sendSessionCommand(Session2Command command, Bundle args,
                 ResultReceiver resultReceiver) {
             if (mControllerBinder == null) return;
+
             try {
                 int seq = getNextSeqNumber();
+                synchronized (mLock) {
+                    mPendingCommands.put(resultReceiver, seq);
+                }
                 mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
             } catch (RuntimeException e) {
                 // Controller may be died prematurely.
+                synchronized (mLock) {
+                    mPendingCommands.remove(resultReceiver);
+                }
+                resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
+            }
+        }
+
+        void cancelSessionCommand(@NonNull Object token) {
+            if (mControllerBinder == null) return;
+            Integer seq;
+            synchronized (mLock) {
+                seq = mPendingCommands.remove(token);
+            }
+            if (seq != null) {
+                mControllerBinder.cancelSessionCommand(seq);
+            }
+        }
+
+        void receiveCommandResult(ResultReceiver resultReceiver) {
+            synchronized (mLock) {
+                mPendingCommands.remove(resultReceiver);
+            }
+        }
+
+        void addRequestedCommandSeqNumber(int seq) {
+            synchronized (mLock) {
+                mRequestedCommandSeqNumbers.add(seq);
+            }
+        }
+
+        boolean removeRequestedCommandSeqNumber(int seq) {
+            synchronized (mLock) {
+                return mRequestedCommandSeqNumbers.remove(seq);
             }
         }
 
         private int getNextSeqNumber() {
-            synchronized (this) {
+            synchronized (mLock) {
                 return mNextSeqNumber++;
             }
         }
@@ -575,9 +678,11 @@
          * @param controller controller information
          * @param command the session command
          * @param args optional arguments
-         * @return The result for the session command
+         * @return the result for the session command. A runtime exception will be thrown if null
+         *         is returned.
          */
-        public Bundle onSessionCommand(@NonNull MediaSession2 session,
+        @NonNull
+        public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Session2Command command,
                 @Nullable Bundle args) {
             return null;
@@ -594,8 +699,6 @@
          */
         public void onCommandResult(@NonNull MediaSession2 session,
                 @NonNull ControllerInfo controller, @NonNull Object token,
-                @NonNull Session2Command command, @Nullable Bundle result) {
-        }
+                @NonNull Session2Command command, @NonNull Session2Command.Result result) { }
     }
 }
-
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
index a5e2ae4..e46e64e 100644
--- a/media/java/android/media/Session2Command.java
+++ b/media/java/android/media/Session2Command.java
@@ -409,6 +409,112 @@
      */
     public static final int COMMAND_CODE_SESSION_SET_RATING = 40010;
 
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, /*prefix = "RESULT_CODE",*/ value = {
+            RESULT_SUCCESS,
+            RESULT_ERROR_UNKNOWN_ERROR,
+            RESULT_ERROR_INVALID_STATE,
+            RESULT_ERROR_BAD_VALUE,
+            RESULT_ERROR_PERMISSION_DENIED,
+            RESULT_ERROR_IO_ERROR,
+            RESULT_INFO_SKIPPED,
+            RESULT_ERROR_SESSION_DISCONNECTED,
+            RESULT_ERROR_NOT_SUPPORTED,
+            RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED,
+            RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED,
+            RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT,
+            RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED,
+            RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION,
+            RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED,
+            RESULT_ERROR_SESSION_SETUP_REQUIRED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResultCode {}
+
+    /**
+     * Result code representing that the command is skipped or canceled. For an example, a seek
+     * command can be skipped if it is followed by another seek command.
+     */
+    public static final int RESULT_INFO_SKIPPED = 1;
+
+    /**
+     * Result code representing that the command is successfully completed.
+     */
+    public static final int RESULT_SUCCESS = 0;
+
+    /**
+     * Result code represents that call is ended with an unknown error.
+     */
+    public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
+
+    /**
+     * Result code representing that the command cannot be completed because the current state is
+     * not valid for the command.
+     */
+    public static final int RESULT_ERROR_INVALID_STATE = -2;
+
+    /**
+     * Result code representing that an argument is illegal.
+     */
+    public static final int RESULT_ERROR_BAD_VALUE = -3;
+
+    /**
+     * Result code representing that the command is not allowed.
+     */
+    public static final int RESULT_ERROR_PERMISSION_DENIED = -4;
+
+    /**
+     * Result code representing a file or network related command error.
+     */
+    public static final int RESULT_ERROR_IO_ERROR = -5;
+
+    /**
+     * Result code representing that the command is not supported nor implemented.
+     */
+    public static final int RESULT_ERROR_NOT_SUPPORTED = -6;
+
+    /**
+     * Result code representing that the session and controller were disconnected.
+     */
+    public static final int RESULT_ERROR_SESSION_DISCONNECTED = -100;
+
+    /**
+     * Result code representing that the authentication has expired.
+     */
+    public static final int RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED = -102;
+
+    /**
+     * Result code representing that a premium account is required.
+     */
+    public static final int RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED = -103;
+
+    /**
+     * Result code representing that too many concurrent streams are detected.
+     */
+    public static final int RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT = -104;
+
+    /**
+     * Result code representing that the content is blocked due to parental controls.
+     */
+    public static final int RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED = -105;
+
+    /**
+     * Result code representing that the content is blocked due to being regionally unavailable.
+     */
+    public static final int RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION = -106;
+
+    /**
+     * Result code representing that the application cannot skip any more because the skip limit is
+     * reached.
+     */
+    public static final int RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED = -107;
+
+    /**
+     * Result code representing that the session needs user's manual intervention.
+     */
+    public static final int RESULT_ERROR_SESSION_SETUP_REQUIRED = -108;
+
     public static final Parcelable.Creator<Session2Command> CREATOR =
             new Parcelable.Creator<Session2Command>() {
                 @Override
@@ -582,6 +688,39 @@
         return Objects.hash(mCustomCommand, mCommandCode);
     }
 
+    /**
+     * Contains the result of {@link Session2Command}.
+     */
+    public static final class Result {
+        private final int mResultCode;
+        private final Bundle mResultData;
+
+        /**
+         * Constructor of {@link Result}.
+         *
+         * @param resultCode result code
+         * @param resultData result data
+         */
+        public Result(int resultCode, Bundle resultData) {
+            mResultCode = resultCode;
+            mResultData = resultData;
+        }
+
+        /**
+         * Returns the result code.
+         */
+        public int getResultCode() {
+            return mResultCode;
+        }
+
+        /**
+         * Returns the result data.
+         */
+        public Bundle getResultData() {
+            return mResultData;
+        }
+    }
+
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     static final class Range {
         public final int lower;
diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java
index 57c58dc..5fe558d 100644
--- a/media/java/android/media/Session2Link.java
+++ b/media/java/android/media/Session2Link.java
@@ -28,8 +28,7 @@
 import java.util.Objects;
 
 /**
- * Handles incoming commands from {@link MediaController2} and {@link MediaBrowser2}
- * to both {@link MediaSession2} and {@link MediaLibrarySession}.
+ * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}.
  * @hide
  */
 // @SystemApi
@@ -113,7 +112,7 @@
         try {
             mISession.connect(caller, seq, connectionRequest);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
         }
     }
 
@@ -122,7 +121,7 @@
         try {
             mISession.disconnect(caller, seq);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
         }
     }
 
@@ -132,7 +131,16 @@
         try {
             mISession.sendSessionCommand(caller, seq, command, args, resultReceiver);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaSession2.sendSessionCommand */
+    public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+        try {
+            mISession.cancelSessionCommand(caller, seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -152,6 +160,11 @@
         mSession.onSessionCommand(caller, seq, command, args, resultReceiver);
     }
 
+    /** Stub implementation for IMediaSession2.cancelSessionCommand */
+    public void onCancelCommand(final Controller2Link caller, final int seq) {
+        mSession.onCancelCommand(caller, seq);
+    }
+
     private class Session2Stub extends IMediaSession2.Stub {
         @Override
         public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
@@ -168,5 +181,10 @@
                 final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
             Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
         }
+
+        @Override
+        public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+            Session2Link.this.onCancelCommand(caller, seq);
+        }
     }
 }
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 7fb3aa6..1c6210e 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -165,6 +165,20 @@
     }
 
     /** @hide */
+    public boolean isRoutedToDevice(int deviceType, @NonNull String deviceAddress) {
+        if ((mRouteFlags & ROUTE_FLAG_RENDER) != ROUTE_FLAG_RENDER) {
+            return false;
+        }
+        if (deviceType != mDeviceSystemType) {
+            return false;
+        }
+        if (!deviceAddress.equals(mDeviceAddress)) {
+            return false;
+        }
+        return true;
+    }
+
+    /** @hide */
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 6103f557..65f3294 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFocusInfo;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -323,6 +324,80 @@
         }
     }
 
+    /**
+     * @hide
+     * Configures the audio framework so that all audio stream originating from the given UID
+     * can only come from a set of audio devices.
+     * For this routing to be operational, a number of {@link AudioMix} instances must have been
+     * previously registered on this policy, and routed to a super-set of the given audio devices
+     * with {@link AudioMix.Builder#setDevice(android.media.AudioDeviceInfo)}. Note that having
+     * multiple devices in the list doesn't imply the signals will be duplicated on the different
+     * audio devices, final routing will depend on the {@link AudioAttributes} of the sounds being
+     * played.
+     * @param uid UID of the application to affect.
+     * @param devices list of devices to which the audio stream of the application may be routed.
+     * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
+     *          otherwise.
+     */
+    @SystemApi
+    public int setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
+        if (devices == null) {
+            throw new IllegalArgumentException("Illegal null list of audio devices");
+        }
+        synchronized (mLock) {
+            if (mStatus != POLICY_STATUS_REGISTERED) {
+                throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+            }
+            final int[] deviceTypes = new int[devices.size()];
+            final String[] deviceAdresses = new String[devices.size()];
+            int i = 0;
+            for (AudioDeviceInfo device : devices) {
+                if (device == null) {
+                    throw new IllegalArgumentException(
+                            "Illegal null AudioDeviceInfo in setUidDeviceAffinity");
+                }
+                deviceTypes[i] =
+                        AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
+                deviceAdresses[i] = device.getAddress();
+                i++;
+            }
+            final IAudioService service = getService();
+            try {
+                final int status = service.setUidDeviceAffinity(this.cb(),
+                        uid, deviceTypes, deviceAdresses);
+                return status;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in setUidDeviceAffinity", e);
+                return AudioManager.ERROR;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Removes audio device affinity previously set by
+     * {@link #setUidDeviceAffinity(int, java.util.List)}.
+     * @param uid UID of the application affected.
+     * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
+     *          otherwise.
+     */
+    @SystemApi
+    public int removeUidDeviceAffinity(int uid) {
+        synchronized (mLock) {
+            if (mStatus != POLICY_STATUS_REGISTERED) {
+                throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+            }
+            final IAudioService service = getService();
+            try {
+                final int status = service.removeUidDeviceAffinity(this.cb(), uid);
+                return status;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in removeUidDeviceAffinity", e);
+                return AudioManager.ERROR;
+            }
+        }
+    }
+
     public void setRegistration(String regId) {
         synchronized (mLock) {
             mRegistrationId = regId;
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
index d5dd3c3..4ef926f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -28,7 +28,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher;
 
 /**
  * A view that forms the header of the notification panel. This view will ensure that any
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
index 5bf30ca..b36a7da 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
@@ -45,9 +45,7 @@
                     Log.d(TAG, "IVoiceInteractionSessionShowCallback onShown()");
                 }
             };
-
-    private static final String EXTRA_CAR_PUSH_TO_TALK =
-            "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
+    
     private final AssistUtils mAssistUtils;
 
     public AssitantButton(Context context, AttributeSet attrs) {
@@ -60,7 +58,6 @@
 
     private void showAssistant() {
         final Bundle args = new Bundle();
-        args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true);
         mAssistUtils.showSessionForActiveService(args,
                 SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, /*activityToken=*/ null);
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7028999c..dbddf71 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -280,7 +280,9 @@
         buildNavBarContent();
         attachNavBarWindows();
 
-        mNavigationBarController.createNavigationBars();
+        // There has been a car customized nav bar on the default display, so just create nav bars
+        // on external displays.
+        mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */);
     }
 
     private void buildNavBarContent() {
@@ -447,12 +449,6 @@
         }
     }
 
-
-    @Override
-    public View getNavigationBarWindow() {
-        return mNavigationBarWindow;
-    }
-
     @Override
     protected View.OnTouchListener getStatusBarWindowTouchListener() {
         // Usually, a touch on the background window will dismiss the notification shade. However,
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index 305862a..0a4b24c 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -168,6 +168,7 @@
         if (mDetailsId == 0) {
             detailsView.setVisibility(View.GONE);
         } else {
+            detailsView.setVisibility(View.VISIBLE);
             detailsView.setText(mDetailsId);
             detailsView.setOnClickListener(mDetailsOnClickListener);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 9af0670..4ac3ce4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -31,6 +31,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import java.time.Clock;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -56,11 +57,18 @@
     private final PackageManager mPackageManager;
     private final Context mContext;
     private final IconDrawableFactory mDrawableFactory;
+    private final Clock mClock;
 
     public RecentLocationAccesses(Context context) {
+        this(context, Clock.systemDefaultZone());
+    }
+
+    @VisibleForTesting
+    RecentLocationAccesses(Context context, Clock clock) {
         mContext = context;
         mPackageManager = context.getPackageManager();
         mDrawableFactory = IconDrawableFactory.newInstance(context);
+        mClock = clock;
     }
 
     /**
@@ -77,7 +85,7 @@
 
         // Process the AppOps list and generate a preference list.
         ArrayList<Access> accesses = new ArrayList<>(appOpsCount);
-        final long now = System.currentTimeMillis();
+        final long now = mClock.millis();
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         final List<UserHandle> profiles = um.getUserProfiles();
 
@@ -175,7 +183,7 @@
         public final CharSequence contentDescription;
         public final long accessFinishTime;
 
-        private Access(String packageName, UserHandle userHandle, Drawable icon,
+        public Access(String packageName, UserHandle userHandle, Drawable icon,
                 CharSequence label, CharSequence contentDescription,
                 long accessFinishTime) {
             this.packageName = packageName;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
new file mode 100644
index 0000000..d5b89ca
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -0,0 +1,162 @@
+package com.android.settingslib.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.PackageOps;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.time.Clock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+public class RecentLocationAccessesTest {
+
+    private static final int TEST_UID = 1234;
+    private static final long NOW = 1_000_000_000;  // Approximately 9/8/2001
+    private static final long ONE_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(1);
+    private static final long TWENTY_THREE_HOURS_AGO = NOW - TimeUnit.HOURS.toMillis(23);
+    private static final long TWO_DAYS_AGO = NOW - TimeUnit.DAYS.toMillis(2);
+    private static final String[] TEST_PACKAGE_NAMES =
+            {"package_1MinAgo", "package_14MinAgo", "package_20MinAgo"};
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private AppOpsManager mAppOpsManager;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private Clock mClock;
+    private Context mContext;
+    private int mTestUserId;
+    private RecentLocationAccesses mRecentLocationAccesses;
+
+    @Before
+    public void setUp() throws NameNotFoundException {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        when(mPackageManager.getApplicationLabel(isA(ApplicationInfo.class)))
+                .thenReturn("testApplicationLabel");
+        when(mPackageManager.getUserBadgedLabel(isA(CharSequence.class), isA(UserHandle.class)))
+                .thenReturn("testUserBadgedLabel");
+        mTestUserId = UserHandle.getUserId(TEST_UID);
+        when(mUserManager.getUserProfiles())
+                .thenReturn(Collections.singletonList(new UserHandle(mTestUserId)));
+
+        long[] testRequestTime = {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO};
+        List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
+        when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+                appOps);
+        mockTestApplicationInfos(mTestUserId, TEST_PACKAGE_NAMES);
+
+        when(mClock.millis()).thenReturn(NOW);
+        mRecentLocationAccesses = new RecentLocationAccesses(mContext, mClock);
+    }
+
+    @Test
+    public void testGetAppList_shouldFilterRecentAccesses() {
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        // Only two of the apps have requested location within 15 min.
+        assertThat(requests).hasSize(2);
+        // Make sure apps are ordered by recency
+        assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+        assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+        assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+        assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+    }
+
+    @Test
+    public void testGetAppList_shouldNotShowAndroidOS() throws NameNotFoundException {
+        // Add android OS to the list of apps.
+        PackageOps androidSystemPackageOps =
+                createPackageOps(
+                        RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME,
+                        Process.SYSTEM_UID,
+                        AppOpsManager.OP_FINE_LOCATION,
+                        ONE_MIN_AGO);
+        long[] testRequestTime =
+                {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO, ONE_MIN_AGO};
+        List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
+        appOps.add(androidSystemPackageOps);
+        when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+                appOps);
+        mockTestApplicationInfos(
+                Process.SYSTEM_UID, RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME);
+
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        // Android OS shouldn't show up in the list of apps.
+        assertThat(requests).hasSize(2);
+        // Make sure apps are ordered by recency
+        assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+        assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+        assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+        assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+    }
+
+    private void mockTestApplicationInfos(int userId, String... packageNameList)
+            throws NameNotFoundException {
+        for (String packageName : packageNameList) {
+            ApplicationInfo appInfo = new ApplicationInfo();
+            appInfo.packageName = packageName;
+            when(mPackageManager.getApplicationInfoAsUser(
+                    packageName, PackageManager.GET_META_DATA, userId)).thenReturn(appInfo);
+        }
+    }
+
+    private List<PackageOps> createTestPackageOpsList(String[] packageNameList, long[] time) {
+        List<PackageOps> packageOpsList = new ArrayList<>();
+        for (int i = 0; i < packageNameList.length; i++) {
+            PackageOps packageOps = createPackageOps(
+                    packageNameList[i],
+                    TEST_UID,
+                    AppOpsManager.OP_FINE_LOCATION,
+                    time[i]);
+            packageOpsList.add(packageOps);
+        }
+        return packageOpsList;
+    }
+
+    private PackageOps createPackageOps(String packageName, int uid, int op, long time) {
+        return new PackageOps(
+                packageName,
+                uid,
+                Collections.singletonList(createOpEntryWithTime(op, time)));
+    }
+
+    private OpEntry createOpEntryWithTime(int op, long time) {
+        final long[] times = new long[AppOpsManager._NUM_UID_STATE];
+        // Slot for background access timestamp.
+        times[AppOpsManager.UID_STATE_LAST_NON_RESTRICTED + 1] = time;
+        final long[] rejectTimes = new long[AppOpsManager._NUM_UID_STATE];
+        return new OpEntry(op, AppOpsManager.MODE_ALLOWED, times, rejectTimes, 0 /* duration */,
+                0 /* proxyUid */, "" /* proxyPackage */);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 375b45c..96e8995 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -81,6 +81,20 @@
     }
 
     @Test
+    public void onBindViewHolder_notSetDetailsRes_barChartDetailsViewIsGoneThenReappears() {
+        // We don't call BarChartPreference#setBarChartDetails yet.
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
+
+        mPreference.setBarChartDetails(R.string.debug_app);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mDetailsView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
+    }
+
+    @Test
     public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
         mPreference.setBarChartDetails(R.string.debug_app);
         mPreference.onBindViewHolder(mHolder);
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index 0d681ed..ac97adb 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -10,7 +10,7 @@
     ../src/com/android/providers/settings/SettingsState.java \
     ../src/com/android/providers/settings/SettingsHelper.java
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 
 LOCAL_JAVA_LIBRARIES := android.test.base
 
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 71e0b15..87a4f60 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -29,7 +29,7 @@
     </application>
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.providers.setting.test"
         android:label="Settings Provider Tests" />
 
diff --git a/packages/SettingsProvider/test/AndroidTest.xml b/packages/SettingsProvider/test/AndroidTest.xml
index 46b8f94..9d23526 100644
--- a/packages/SettingsProvider/test/AndroidTest.xml
+++ b/packages/SettingsProvider/test/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="SettingsProviderTest" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.providers.setting.test" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index ab23af3..68efa67 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -25,9 +25,12 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import libcore.io.Streams;
+
 import org.junit.runner.RunWith;
 
 import java.io.FileInputStream;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
index 5587cba..df4656a 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -24,8 +24,9 @@
 import android.os.Bundle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import libcore.io.Streams;
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
index d8ee9b6..863b035 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
@@ -26,10 +26,11 @@
 import android.os.SystemClock;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
index 1074957..54f8688 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -24,8 +24,10 @@
 import android.net.Uri;
 import android.os.Build;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index 6fa014d..d112fac 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -17,19 +17,10 @@
 package com.android.providers.settings;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertSame;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.fail;
-
-import com.android.internal.app.LocalePicker;
-import com.android.providers.settings.SettingsHelper;
 
 import android.os.LocaleList;
-import android.support.test.runner.AndroidJUnit4;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml b/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
deleted file mode 100644
index 2d77949..0000000
--- a/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="@color/recents_task_view_lock_to_app_button_color"
-        android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
-</vector>
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
deleted file mode 100644
index 5f9341c..0000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <corners android:topLeftRadius="@dimen/recents_task_view_rounded_corners_radius"
-             android:topRightRadius="@dimen/recents_task_view_rounded_corners_radius"/>
-    <solid android:color="#00000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
deleted file mode 100644
index 9a060b4..0000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <group
-            android:translateX="-286.000000"
-            android:translateY="-602.000000">
-        <group
-                android:translateX="109.000000"
-                android:translateY="514.000000">
-            <group
-                    android:translateX="178.000000"
-                    android:translateY="89.000000">
-                <path
-                    android:strokeColor="@color/recents_task_bar_dark_icon_color"
-                    android:strokeWidth="2"
-                    android:pathData="M10,12 L10,3 L19,3 L19,5 L19,11 L19,12 L10,12 Z" />
-                <path
-                    android:strokeColor="@color/recents_task_bar_dark_icon_color"
-                    android:strokeWidth="2"
-                    android:pathData="M15,17 L5,17 L5,7 L5,17 Z" />
-            </group>
-        </group>
-    </group>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
deleted file mode 100644
index b8acedb..0000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <group
-            android:translateX="-286.000000"
-            android:translateY="-602.000000">
-        <group
-                android:translateX="109.000000"
-                android:translateY="514.000000">
-            <group
-                    android:translateX="178.000000"
-                    android:translateY="89.000000">
-                <path
-                    android:strokeColor="@color/recents_task_bar_light_icon_color"
-                    android:strokeWidth="2"
-                    android:pathData="M10,12 L10,3 L19,3 L19,5 L19,11 L19,12 L10,12 Z" />
-                <path
-                    android:strokeColor="@color/recents_task_bar_light_icon_color"
-                    android:strokeWidth="2"
-                    android:pathData="M15,17 L5,17 L5,7 L5,17 Z" />
-            </group>
-        </group>
-    </group>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
new file mode 100644
index 0000000..c7bc858
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -0,0 +1,128 @@
+/*
+ * 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 android.graphics.Color;
+import android.graphics.Rect;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area and dark
+ * intensity. Accessible through {@link PluginDependency}
+ */
+@ProvidesInterface(version = DarkIconDispatcher.VERSION)
+@DependsOn(target = DarkReceiver.class)
+public interface DarkIconDispatcher {
+    int VERSION = 1;
+
+    /**
+     * Sets the dark area so {@link #applyDark} only affects the icons in the specified area.
+     *
+     * @param r the area in which icons should change its tint, in logical screen
+     *                 coordinates
+     */
+    void setIconsDarkArea(Rect r);
+
+    /**
+     * Adds a receiver to receive callbacks onDarkChanged
+     */
+    void addDarkReceiver(DarkReceiver receiver);
+
+    /**
+     * Adds a receiver to receive callbacks onDarkChanged
+     */
+    void addDarkReceiver(ImageView imageView);
+
+    /**
+     * Must have been previously been added through one of the addDarkReceive methods above.
+     */
+    void removeDarkReceiver(DarkReceiver object);
+
+    /**
+     * Must have been previously been added through one of the addDarkReceive methods above.
+     */
+    void removeDarkReceiver(ImageView object);
+
+    /**
+     * Used to reapply darkness on an object, must have previously been added through
+     * addDarkReceiver.
+      */
+    void applyDark(DarkReceiver object);
+
+    int DEFAULT_ICON_TINT = Color.WHITE;
+    Rect sTmpRect = new Rect();
+    int[] sTmpInt2 = new int[2];
+
+    /**
+     * @return the tint to apply to view depending on the desired tint color and
+     *         the screen tintArea in which to apply that tint
+     */
+    static int getTint(Rect tintArea, View view, int color) {
+        if (isInArea(tintArea, view)) {
+            return color;
+        } else {
+            return DEFAULT_ICON_TINT;
+        }
+    }
+
+    /**
+     * @return the dark intensity to apply to view depending on the desired dark
+     *         intensity and the screen tintArea in which to apply that intensity
+     */
+    static float getDarkIntensity(Rect tintArea, View view, float intensity) {
+        if (isInArea(tintArea, view)) {
+            return intensity;
+        } else {
+            return 0f;
+        }
+    }
+
+    /**
+     * @return true if more than half of the view area are in area, false
+     *         otherwise
+     */
+    static boolean isInArea(Rect area, View view) {
+        if (area.isEmpty()) {
+            return true;
+        }
+        sTmpRect.set(area);
+        view.getLocationOnScreen(sTmpInt2);
+        int left = sTmpInt2[0];
+
+        int intersectStart = Math.max(left, area.left);
+        int intersectEnd = Math.min(left + view.getWidth(), area.right);
+        int intersectAmount = Math.max(0, intersectEnd - intersectStart);
+
+        boolean coversFullStatusBar = area.top <= 0;
+        boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
+        return majorityOfWidth && coversFullStatusBar;
+    }
+
+    /**
+     * Receives a callback on darkness changes
+     */
+    @ProvidesInterface(version = DarkReceiver.VERSION)
+    interface DarkReceiver {
+        int VERSION = 1;
+        void onDarkChanged(Rect area, float darkIntensity, int tint);
+    }
+}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 73f5116..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png
deleted file mode 100755
index 9afd8fa..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 552a3d1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/search_panel_scrim.xml b/packages/SystemUI/res/drawable-land/search_panel_scrim.xml
deleted file mode 100644
index 102cc9c..0000000
--- a/packages/SystemUI/res/drawable-land/search_panel_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <gradient
-            android:type="linear"
-            android:angle="180"
-            android:startColor="#55000000"
-            android:endColor="#00000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 787e259..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png
deleted file mode 100755
index 35737aa..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 48b96d8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml b/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml
deleted file mode 100644
index f663a66..0000000
--- a/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    >
-    <corners
-        android:radius="8dp" />
-    <solid
-        android:color="#ffff0000" />
-</shape>
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 23ec6db..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index e450058..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index d18e419..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 00a751c..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml b/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml
deleted file mode 100644
index bbb2617..0000000
--- a/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <gradient
-            android:type="linear"
-            android:angle="90"
-            android:startColor="#55000000"
-            android:endColor="#00000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png
deleted file mode 100644
index b336ccd..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 6ebbc83..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png
deleted file mode 100755
index f1bfa89..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index e49db34..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index b91704a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/dismiss_all_shape.xml b/packages/SystemUI/res/drawable/dismiss_all_shape.xml
deleted file mode 100644
index fb371c6..0000000
--- a/packages/SystemUI/res/drawable/dismiss_all_shape.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="17dp"
-    android:width="85dp"
-    android:viewportHeight="48"
-    android:viewportWidth="260" >
-    <group
-        android:name="dismiss_all"
-        android:translateX="48"
-        android:translateY="6" >
-        <group
-            android:name="3"
-            android:translateX="-24"
-            android:translateY="36" >
-            <path
-                android:name="rectangle_path_1_2"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-        <group
-            android:name="2"
-            android:translateX="-12"
-            android:translateY="18" >
-            <path
-                android:name="rectangle_path_1_1"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-        <group
-            android:name="1" >
-            <path
-                android:name="rectangle_path_1"
-                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
-                android:fillColor="#FFFFFFFF"
-                android:fillAlpha="1" />
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/fingerprint_icon.xml b/packages/SystemUI/res/drawable/fingerprint_icon.xml
deleted file mode 100644
index 76a86ae..0000000
--- a/packages/SystemUI/res/drawable/fingerprint_icon.xml
+++ /dev/null
@@ -1,107 +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
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="60dp"
-    android:height="60dp"
-    android:viewportWidth="60"
-    android:viewportHeight="60">
-
-    <path
-        android:fillColor="#1A73E8"
-        android:fillType="evenOdd"
-        android:strokeWidth="1"
-        android:pathData="M 30 0 C 46.5685424949 0 60 13.4314575051 60 30 C 60 46.5685424949 46.5685424949 60 30 60 C 13.4314575051 60 0 46.5685424949 0 30 C 0 13.4314575051 13.4314575051 0 30 0 Z" />
-    <group
-        android:translateX="17.727273"
-        android:translateY="16.363636">
-        <path
-            android:fillColor="#FFFFFF"
-            android:strokeWidth="1"
-            android:pathData="M20.3065726,3.44516129 C20.1974817,3.44516129 20.0883908,3.41788856
-19.9929362,3.36334311 C17.3747544,2.01334311 15.111118,1.44061584
-12.3974817,1.44061584 C9.69748166,1.44061584 7.1338453,2.08152493
-4.80202711,3.36334311 C4.47475439,3.54061584 4.06566348,3.41788856
-3.87475439,3.09061584 C3.69748166,2.76334311 3.82020893,2.34061584
-4.14748166,2.16334311 C6.6838453,0.786070381 9.46566348,0.0769794721
-12.3974817,0.0769794721 C15.3020271,0.0769794721 17.8383908,0.717888563
-20.6202089,2.14970674 C20.961118,2.32697947 21.0838453,2.73607038
-20.9065726,3.06334311 C20.7838453,3.30879765 20.5520271,3.44516129
-20.3065726,3.44516129 L20.3065726,3.44516129 Z M0.792936205,10.6042522
-C0.656572568,10.6042522 0.520208932,10.5633431 0.397481659,10.4815249
-C0.0838452956,10.2633431 0.0156634774,9.84061584 0.233845296,9.52697947
-C1.5838453,7.61788856 3.30202711,6.11788856 5.34748166,5.06788856
-C9.62929984,2.85879765 15.111118,2.84516129 19.4065726,5.0542522
-C21.4520271,6.1042522 23.1702089,7.59061584 24.5202089,9.48607038
-C24.7383908,9.78607038 24.6702089,10.222434 24.3565726,10.4406158
-C24.0429362,10.6587977 23.6202089,10.5906158 23.4020271,10.2769795
-C22.1747544,8.55879765 20.6202089,7.20879765 18.7792998,6.26788856
-C14.8656635,4.26334311 9.86111802,4.26334311 5.96111802,6.28152493
-C4.10657257,7.23607038 2.55202711,8.59970674 1.32475439,10.3178886
-C1.21566348,10.5087977 1.01111802,10.6042522 0.792936205,10.6042522
-L0.792936205,10.6042522 Z M9.31566348,27.0633431 C9.13839075,27.0633431
-8.96111802,26.9951613 8.83839075,26.8587977 C7.65202711,25.672434
-7.01111802,24.9087977 6.09748166,23.2587977 C5.15657257,21.5815249
-4.66566348,19.5360704 4.66566348,17.3406158 C4.66566348,13.2906158
-8.12929984,9.99061584 12.3838453,9.99061584 C16.6383908,9.99061584
-20.1020271,13.2906158 20.1020271,17.3406158 C20.1020271,17.722434
-19.8020271,18.022434 19.4202089,18.022434 C19.0383908,18.022434
-18.7383908,17.722434 18.7383908,17.3406158 C18.7383908,14.0406158
-15.8883908,11.3542522 12.3838453,11.3542522 C8.87929984,11.3542522
-6.02929984,14.0406158 6.02929984,17.3406158 C6.02929984,19.3042522
-6.46566348,21.1178886 7.29748166,22.5906158 C8.17020893,24.1587977
-8.77020893,24.8269795 9.82020893,25.8906158 C10.0792998,26.1633431
-10.0792998,26.5860704 9.82020893,26.8587977 C9.67020893,26.9951613
-9.4929362,27.0633431 9.31566348,27.0633431 Z M19.0929362,24.5406158
-C17.4702089,24.5406158 16.0383908,24.1315249 14.8656635,23.3269795
-C12.8338453,21.9497067 11.6202089,19.7133431 11.6202089,17.3406158
-C11.6202089,16.9587977 11.9202089,16.6587977 12.3020271,16.6587977
-C12.6838453,16.6587977 12.9838453,16.9587977 12.9838453,17.3406158
-C12.9838453,19.2633431 13.9656635,21.0769795 15.6292998,22.1951613
-C16.5974817,22.8497067 17.7292998,23.1633431 19.0929362,23.1633431
-C19.4202089,23.1633431 19.9656635,23.122434 20.511118,23.0269795
-C20.8792998,22.9587977 21.2338453,23.2042522 21.3020271,23.5860704
-C21.3702089,23.9542522 21.1247544,24.3087977 20.7429362,24.3769795
-C19.9656635,24.5269795 19.2838453,24.5406158 19.0929362,24.5406158
-L19.0929362,24.5406158 Z M16.3520271,27.3497067 C16.2974817,27.3497067
-16.2292998,27.3360704 16.1747544,27.322434 C14.0065726,26.722434
-12.5883908,25.9178886 11.1020271,24.4587977 C9.1929362,22.5633431
-8.1429362,20.0406158 8.1429362,17.3406158 C8.1429362,15.1315249
-10.0247544,13.3315249 12.3429362,13.3315249 C14.661118,13.3315249
-16.5429362,15.1315249 16.5429362,17.3406158 C16.5429362,18.7997067
-17.811118,19.9860704 19.3792998,19.9860704 C20.9474817,19.9860704
-22.2156635,18.7997067 22.2156635,17.3406158 C22.2156635,12.1997067
-17.7838453,8.02697947 12.3292998,8.02697947 C8.45657257,8.02697947
-4.91111802,10.1815249 3.31566348,13.522434 C2.7838453,14.6269795
-2.51111802,15.922434 2.51111802,17.3406158 C2.51111802,18.4042522
-2.60657257,20.0815249 3.42475439,22.2633431 C3.56111802,22.6178886
-3.3838453,23.0133431 3.02929984,23.1360704 C2.67475439,23.272434
-2.27929984,23.0815249 2.15657257,22.7406158 C1.48839075,20.9542522
-1.16111802,19.1815249 1.16111802,17.3406158 C1.16111802,15.7042522
-1.47475439,14.2178886 2.08839075,12.922434 C3.90202711,9.11788856
-7.92475439,6.64970674 12.3292998,6.64970674 C18.5338453,6.64970674
-23.5792998,11.4360704 23.5792998,17.3269795 C23.5792998,19.5360704
-21.6974817,21.3360704 19.3792998,21.3360704 C17.061118,21.3360704
-15.1792998,19.5360704 15.1792998,17.3269795 C15.1792998,15.8678886
-13.911118,14.6815249 12.3429362,14.6815249 C10.7747544,14.6815249
-9.50657257,15.8678886 9.50657257,17.3269795 C9.50657257,19.6587977
-10.4065726,21.8406158 12.0565726,23.4769795 C13.3520271,24.7587977
-14.5929362,25.4678886 16.5156635,25.9997067 C16.8838453,26.0951613
-17.0883908,26.4769795 16.9929362,26.8315249 C16.9247544,27.1451613
-16.6383908,27.3497067 16.3520271,27.3497067 L16.3520271,27.3497067 Z" />
-    </group>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/header_dot.xml b/packages/SystemUI/res/drawable/header_dot.xml
deleted file mode 100644
index dbc6b37..0000000
--- a/packages/SystemUI/res/drawable/header_dot.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2015, 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.
--->
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval"
-    android:tint="?android:attr/colorControlNormal">
-
-    <solid
-        android:color="#FFFFFF"/>
-
-    <size
-        android:width="3dp"
-        android:height="3dp"/>
-</shape>
diff --git a/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml b/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml
deleted file mode 100644
index 6134b8f..0000000
--- a/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M11.0,22.98l0.0,-8.98 -4.0,0.0 6.0,-13.0 0.0,9.0 4.0,0.0z"
-        android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cast.xml b/packages/SystemUI/res/drawable/ic_cast.xml
deleted file mode 100644
index b86dfea..0000000
--- a/packages/SystemUI/res/drawable/ic_cast.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M1 18v2c0 .55 .45 1 1 1h2c0-1.66-1.34-3-3-3zm0-2.94c-.01 .51 .32 .93 .82 1.02
-2.08 .36 3.74 2 4.1 4.08 .09 .48 .5 .84 .99 .84 .61 0 1.09-.54 1-1.14a6.996
-6.996 0 0 0-5.8-5.78c-.59-.09-1.09 .38 -1.11 .98 zm0-4.03c-.01 .52 .34 .96 .85
-1.01 4.26 .43 7.68 3.82 8.1 8.08 .05 .5 .48 .88 .99 .88 .59 0 1.06-.51
-1-1.1-.52-5.21-4.66-9.34-9.87-9.85-.57-.05-1.05 .4 -1.07 .98 zM21 3H3c-1.1 0-2
-.9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_chevron_left.xml b/packages/SystemUI/res/drawable/ic_chevron_left.xml
deleted file mode 100644
index 379382b..0000000
--- a/packages/SystemUI/res/drawable/ic_chevron_left.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="36.0"
-        android:viewportHeight="36.0">
-
-    <path
-        android:fillColor="#ffffffff"
-        android:pathData="M23.1,11.1l-2.1000004,-2.1000004 -9.0,9.0 9.0,9.0 2.1000004,-2.1000004 -6.8999996,-6.8999996z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_off.xml b/packages/SystemUI/res/drawable/ic_data_off.xml
deleted file mode 100644
index b97ddae..0000000
--- a/packages/SystemUI/res/drawable/ic_data_off.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-    Copyright (C) 2017 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M21.6,21.6L10.8,10.9L2.1,2.1L0.8,3.4l3.3,3.3C3.1,8.2 2.5,10.0 2.5,12.0c0.0,5.2 4.3,9.5 9.5,9.5c2.0,0.0 3.8,-0.6 5.3,-1.6l3.0,3.0L21.6,21.6zM9.6,12.2l0.7,0.7L9.6,12.9L9.6,12.2zM13.9,18.6c-0.2,0.2 -0.5,0.2 -0.6,0.0l-2.4,-3.7l1.5,0.0l2.4,2.4L13.9,18.6z"
-        android:fillColor="#ffffff"/>
-    <path
-        android:pathData="M12.0,2.5c-2.0,0.0 -3.8,0.6 -5.3,1.6l2.5,2.5L10.0,5.4c0.2,-0.2 0.5,-0.2 0.6,0.0L13.0,9.1l-1.4,0.0l2.0,2.0l0.6,0.0l0.0,0.6l5.6,5.6c1.0,-1.5 1.6,-3.3 1.6,-5.3C21.5,6.8 17.2,2.5 12.0,2.5z"
-        android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_on.xml b/packages/SystemUI/res/drawable/ic_data_on.xml
deleted file mode 100644
index a65dc79..0000000
--- a/packages/SystemUI/res/drawable/ic_data_on.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-    Copyright (C) 2017 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M12.0,12.0m-9.5,0.0a9.5,9.5 0.0,1.0 1.0,19.0 0.0a9.5,9.5 0.0,1.0 1.0,-19.0 0.0
-        M10.6,5.4c-0.2,-0.2 -0.5,-0.2 -0.6,0.0L7.6,9.1l2.0,0.0l0.0,3.8L11.0,12.900001L11.0,9.1l2.0,0.0L10.6,5.4z
-        M13.3,18.6c0.2,0.2 0.5,0.2 0.6,0.0l2.4,-3.7l-2.0,0.0l0.0,-3.8l-1.4,0.0l0.0,3.8l-2.0,0.0L13.3,18.6z"
-        android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_unavailable.xml b/packages/SystemUI/res/drawable/ic_data_unavailable.xml
deleted file mode 100644
index ffb2af7..0000000
--- a/packages/SystemUI/res/drawable/ic_data_unavailable.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-    Copyright (C) 2017 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M15.8,12.9l3.7,0.0c0.0,-0.3 0.0,-0.6 0.0,-0.9c0.0,-5.2 -4.3,-9.5 -9.5,-9.5S0.6,6.8 0.6,12.0s4.3,9.5 9.5,9.5c2.1,0.0 4.1,-0.7 5.7,-1.9L15.8,12.9zM5.7,9.1l2.4,-3.7c0.2,-0.2 0.5,-0.2 0.6,0.0l2.4,3.7l-2.0,0.0l0.0,3.8L7.8,12.900001L7.8,9.1L5.7,9.1zM11.4,18.6L9.0,14.9l2.0,0.0l0.0,-3.8l1.4,0.0l0.0,3.8l2.0,0.0L12.0,18.6C11.9,18.8 11.6,18.8 11.4,18.6z"
-        android:fillColor="#FFFFFF"/>
-    <path
-        android:pathData="M23.4,19.4l-2.1,-2.1 2.1,-2.199999 -1.1,-1.0 -2.099998,2.1 -2.1,-2.1 -1.1,1.099999 2.1,2.099999 -2.1,2.1 1.1,1.1 2.1,-2.200001 2.099998,2.200001z"
-        android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_expand_less.xml b/packages/SystemUI/res/drawable/ic_expand_less.xml
deleted file mode 100644
index e968013..0000000
--- a/packages/SystemUI/res/drawable/ic_expand_less.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="20.0dp"
-        android:height="20.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M12.000000,8.000000l-6.000000,6.000000 1.400000,1.400000 4.600000,-4.599999 4.600000,4.599999 1.400000,-1.400000z"
-        android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_expand_more.xml b/packages/SystemUI/res/drawable/ic_expand_more.xml
deleted file mode 100644
index 72e98ec..0000000
--- a/packages/SystemUI/res/drawable/ic_expand_more.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="20.0dp"
-        android:height="20.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
-        android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_history.xml b/packages/SystemUI/res/drawable/ic_history.xml
deleted file mode 100644
index e936864..0000000
--- a/packages/SystemUI/res/drawable/ic_history.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89 .07 .14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7
-7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13
-21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54 .72 -1.21-3.5-2.08V8H12z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml b/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
deleted file mode 100644
index 3a47261..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-          android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_back.xml b/packages/SystemUI/res/drawable/ic_qs_back.xml
deleted file mode 100644
index f00ba03..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_back.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M20.0,11.0L7.8,11.0l5.6,-5.6L12.0,4.0l-8.0,8.0l8.0,8.0l1.4,-1.4L7.8,13.0L20.0,13.0L20.0,11.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml b/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
deleted file mode 100644
index 7b29740..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="32.0dp"
-        android:height="32.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:pathData="M5,3
-        l3.5,0 l0,-1.5 l7,0 l0,1.5 l3.5,0 l0,19.5 l-14,0z
-        M10.5,8.5 l0,3 l-3,0 l0,3 l3,0 l0,3 l3,0 l0,-3 l3,0 l0,-3 l-3,0 l0,-3 z"
-        android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock.xml b/packages/SystemUI/res/drawable/ic_qs_lock.xml
deleted file mode 100644
index 204af7e..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_lock.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="@color/keyguard_affordance"
-        android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
deleted file mode 100644
index c877f06..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="@color/keyguard_affordance"
-        android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
deleted file mode 100644
index 7bdf50c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-
-<!-- Placeholder icon for network logging until the real icon is finalized-->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-  android:width="12.0dp"
-  android:height="12.0dp"
-  android:viewportWidth="24.0"
-  android:viewportHeight="24.0">
-    <path
-      android:fillColor="#FFFFFFFF"
-      android:pathData="M2,24v-4h12v4H2z M2,16v-4h20v4H2z M5,7 12,0 19,7 14,7 14,15 10,15 10,7z"/>
-
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
deleted file mode 100644
index 2974157..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C7.64,5.36 6,7.92 6,11v6H4v2h10h0.38H20v-2H18zM16,17H8v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5V17z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
deleted file mode 100644
index 6db508c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M16,16L2.81,2.81L1.39,4.22l4.85,4.85C6.09,9.68 6,10.33 6,11v6H4v2h12.17l3.61,3.61l1.41,-1.41L16,16zM8,17c0,0 0.01,-6.11 0.01,-6.16L14.17,17H8z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,6.5c2.49,0 4,2.02 4,4.5v2.17l2,2V11c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C9.72,4.86 9.05,5.2 8.46,5.63L9.93,7.1C10.51,6.73 11.2,6.5 12,6.5z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
deleted file mode 100644
index c87b595..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
deleted file mode 100644
index 4a2bd54..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_signal_workmode_disable" >
-    <target
-        android:name="mask_1"
-        android:animation="@anim/ic_signal_workmode_disable_mask_1_animation" />
-    <target
-        android:name="whole"
-        android:animation="@anim/ic_signal_workmode_disable_whole_animation" />
-    <target
-        android:name="rectangle_path_3_position"
-        android:animation="@anim/ic_signal_workmode_disable_rectangle_path_3_position_animation" />
-    <target
-        android:name="rectangle_path_3"
-        android:animation="@anim/ic_signal_workmode_disable_rectangle_path_3_animation" />
-    <target
-        android:name="rectangle_path_4_position"
-        android:animation="@anim/ic_signal_workmode_disable_rectangle_path_4_position_animation" />
-    <target
-        android:name="rectangle_path_4"
-        android:animation="@anim/ic_signal_workmode_disable_rectangle_path_4_animation" />
-    <target
-        android:name="left"
-        android:animation="@anim/ic_signal_workmode_disable_left_animation" />
-    <target
-        android:name="right"
-        android:animation="@anim/ic_signal_workmode_disable_right_animation" />
-    <target
-        android:name="stick"
-        android:animation="@anim/ic_signal_workmode_disable_stick_animation" />
-    <target
-        android:name="ic_signal_workmode_disable"
-        android:animation="@anim/ic_signal_workmode_disable_stickito_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
deleted file mode 100644
index 2d4f0b5..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_signal_workmode_enable"
-    android:width="42dp"
-    android:viewportWidth="42"
-    android:height="42dp"
-    android:viewportHeight="42" >
-    <group
-        android:name="suitcase"
-        android:translateX="21"
-        android:translateY="36.9375"
-        android:scaleX="0.1"
-        android:scaleY="0.1" >
-        <group
-            android:name="suitcase_pivot"
-            android:translateY="-158" >
-            <clip-path
-                android:name="mask_1"
-                android:pathData="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 480.0,480.0 480.0,480.0 c 0.0,0.0 -20.7500915527,20.75 -20.7500915527,20.75 c 0.0,0.0 -479.999908447,-480.000015259 -479.999908447,-480.000015259 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z" />
-            <group
-                android:name="whole"
-                android:translateX="-1.11523"
-                android:translateY="32.0918"
-                android:scaleX="0"
-                android:scaleY="0" >
-                <path
-                    android:name="rectangle_path_1"
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeWidth="65"
-                    android:pathData="M 0.0,-66.5 l 0.0,0.0 c 36.7269358617,0.0 66.5,29.7730641383 66.5,66.5 l 0.0,0.0 c 0.0,36.7269358617 -29.7730641383,66.5 -66.5,66.5 l 0.0,0.0 c -36.7269358617,0.0 -66.5,-29.7730641383 -66.5,-66.5 l 0.0,0.0 c 0.0,-36.7269358617 29.7730641383,-66.5 66.5,-66.5 Z" />
-            </group>
-            <group
-                android:name="handle"
-                android:translateY="-100" >
-                <path
-                    android:name="rectangle_path_2"
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeWidth="35"
-                    android:pathData="M -34.0,-50.0 l 68.0,0.0 c 8.8365559968,0.0 16.0,7.1634440032 16.0,16.0 l 0.0,68.0 c 0.0,8.8365559968 -7.1634440032,16.0 -16.0,16.0 l -68.0,0.0 c -8.8365559968,0.0 -16.0,-7.1634440032 -16.0,-16.0 l 0.0,-68.0 c 0.0,-8.8365559968 7.1634440032,-16.0 16.0,-16.0 Z" />
-            </group>
-            <group
-                android:name="case"
-                android:translateY="32.68518" >
-                <group
-                    android:name="case_pivot"
-                    android:translateY="-32.68518" >
-                    <group
-                        android:name="bottom"
-                        android:translateY="-97.62964" >
-                        <group
-                            android:name="bottom_pivot"
-                            android:translateY="40" >
-                            <group
-                                android:name="rectangle_path_3_position"
-                                android:translateY="25" >
-                                <path
-                                    android:name="rectangle_path_3"
-                                    android:fillColor="#FFFFFFFF"
-                                    android:pathData="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
-                            </group>
-                        </group>
-                    </group>
-                    <group
-                        android:name="top"
-                        android:translateY="163" >
-                        <group
-                            android:name="top_pivot"
-                            android:translateY="-40" >
-                            <group
-                                android:name="rectangle_path_4_position"
-                                android:translateY="-25" >
-                                <path
-                                    android:name="rectangle_path_4"
-                                    android:fillColor="#FFFFFFFF"
-                                    android:pathData="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
-                            </group>
-                        </group>
-                    </group>
-                    <group
-                        android:name="left"
-                        android:translateX="-175.00635"
-                        android:translateY="30"
-                        android:scaleX="1.8" >
-                        <group
-                            android:name="left_pivot"
-                            android:translateX="50.00635" >
-                            <path
-                                android:name="rectangle_path_5"
-                                android:fillColor="#FFFFFFFF"
-                                android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                        </group>
-                    </group>
-                    <group
-                        android:name="right"
-                        android:translateX="174.97778"
-                        android:translateY="30"
-                        android:scaleX="1.8" >
-                        <group
-                            android:name="right_pivot"
-                            android:translateX="-49.97778" >
-                            <path
-                                android:name="rectangle_path_6"
-                                android:fillColor="#FFFFFFFF"
-                                android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                        </group>
-                    </group>
-                </group>
-            </group>
-            <group
-                android:name="stick"
-                android:translateX="-166.59082"
-                android:translateY="-156.51367"
-                android:rotation="-45" >
-                <group
-                    android:name="stick_pivot"
-                    android:translateX="0.18161"
-                    android:translateY="243.8158" >
-                    <path
-                        android:name="stickito"
-                        android:fillColor="#FFFFFFFF"
-                        android:fillAlpha="1"
-                        android:pathData="M -16.5,-243.999885 l 33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 l -33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                </group>
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
deleted file mode 100644
index c98f800..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/ic_signal_workmode_enable" >
-    <target
-        android:name="mask_1"
-        android:animation="@anim/ic_signal_workmode_enable_mask_1_animation" />
-    <target
-        android:name="whole"
-        android:animation="@anim/ic_signal_workmode_enable_whole_animation" />
-    <target
-        android:name="rectangle_path_3_position"
-        android:animation="@anim/ic_signal_workmode_enable_rectangle_path_3_position_animation" />
-    <target
-        android:name="rectangle_path_3"
-        android:animation="@anim/ic_signal_workmode_enable_rectangle_path_3_animation" />
-    <target
-        android:name="rectangle_path_4_position"
-        android:animation="@anim/ic_signal_workmode_enable_rectangle_path_4_position_animation" />
-    <target
-        android:name="rectangle_path_4"
-        android:animation="@anim/ic_signal_workmode_enable_rectangle_path_4_animation" />
-    <target
-        android:name="left"
-        android:animation="@anim/ic_signal_workmode_enable_left_animation" />
-    <target
-        android:name="right"
-        android:animation="@anim/ic_signal_workmode_enable_right_animation" />
-    <target
-        android:name="stick"
-        android:animation="@anim/ic_signal_workmode_enable_stick_animation" />
-    <target
-        android:name="ic_signal_workmode_enable"
-        android:animation="@anim/ic_signal_workmode_enable_stickito_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_sim.xml b/packages/SystemUI/res/drawable/ic_sim.xml
deleted file mode 100644
index a9a1902..0000000
--- a/packages/SystemUI/res/drawable/ic_sim.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-    Copyright (C) 2017 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M18,2h-8L4,8v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM18,4v16H6V8.83L10.83,4L18,4L18,4z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M7,17h2v2h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M15,17h2v2h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M7,11h2v4h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,15h2v4h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,11h2v2h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M15,11h2v4h-2z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker.xml b/packages/SystemUI/res/drawable/ic_speaker.xml
deleted file mode 100644
index 1ea293c..0000000
--- a/packages/SystemUI/res/drawable/ic_speaker.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal" >
-    <path
-        android:pathData="M17,2L7,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,1.99 2,1.99L17,22c1.1,0 2,-0.9 2,-2L19,4c0,-1.1 -0.9,-2 -2,-2zM12,4c1.1,0 2,0.9 2,2s-0.9,2 -2,2c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2zM12,20c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"
-        android:fillColor="#FFFFFFFF"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_speaker_group.xml b/packages/SystemUI/res/drawable/ic_speaker_group.xml
deleted file mode 100644
index d6867d7..0000000
--- a/packages/SystemUI/res/drawable/ic_speaker_group.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal" >
-    <path
-        android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"
-        android:fillColor="#FFFFFFFF"/>
-    <path
-        android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
-        android:fillColor="#FFFFFFFF"/>
-    <path
-        android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z"
-        android:fillColor="#FFFFFFFF"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_swap.xml b/packages/SystemUI/res/drawable/ic_swap.xml
deleted file mode 100644
index 30da2a9..0000000
--- a/packages/SystemUI/res/drawable/ic_swap.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-    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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorForeground">
-    <path
-        android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
-        android:fillColor="#FFFFFF"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_tv.xml b/packages/SystemUI/res/drawable/ic_tv.xml
deleted file mode 100644
index cc2ae91..0000000
--- a/packages/SystemUI/res/drawable/ic_tv.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal" >
-    <path
-        android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"
-        android:fillColor="#FFFFFFFF"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_zen_all.xml b/packages/SystemUI/res/drawable/ic_zen_all.xml
deleted file mode 100644
index 5df2447..0000000
--- a/packages/SystemUI/res/drawable/ic_zen_all.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="18dp"
-        android:height="18dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_zen_important.xml b/packages/SystemUI/res/drawable/ic_zen_important.xml
deleted file mode 100644
index c2a59b8..0000000
--- a/packages/SystemUI/res/drawable/ic_zen_important.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="18dp"
-        android:height="18dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_zen_none.xml b/packages/SystemUI/res/drawable/ic_zen_none.xml
deleted file mode 100644
index 99014f2..0000000
--- a/packages/SystemUI/res/drawable/ic_zen_none.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="18dp"
-        android:height="18dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml b/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
deleted file mode 100644
index b812d43..0000000
--- a/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <solid android:color="#1a000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_expand_more.xml b/packages/SystemUI/res/drawable/notification_expand_more.xml
deleted file mode 100644
index 430fb0d..0000000
--- a/packages/SystemUI/res/drawable/notification_expand_more.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2015 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._more
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="22.0dp"
-    android:height="22.0dp"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
-        android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pip_dismiss.xml b/packages/SystemUI/res/drawable/pip_dismiss.xml
deleted file mode 100644
index f656eeb..0000000
--- a/packages/SystemUI/res/drawable/pip_dismiss.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="42.0dp"
-        android:height="42.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_notification_icon.xml b/packages/SystemUI/res/drawable/pip_notification_icon.xml
deleted file mode 100644
index 592bc60..0000000
--- a/packages/SystemUI/res/drawable/pip_notification_icon.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pop_ball.xml b/packages/SystemUI/res/drawable/pop_ball.xml
deleted file mode 100644
index ee1220f..0000000
--- a/packages/SystemUI/res/drawable/pop_ball.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M0,50 a50,50 0 1 1 100,0
-                                a50,50 0 1 1 -100,0"
-        android:fillColor="#FFFF1744"/>
-    <path
-        android:pathData="M16,36 A24,24 0 1 1 64,36
-                          M64,36 A24,24 0 1 1 16,36"
-        android:fillColor="#20FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_belt.xml b/packages/SystemUI/res/drawable/pop_belt.xml
deleted file mode 100644
index e0ea575..0000000
--- a/packages/SystemUI/res/drawable/pop_belt.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000m-47.599998,0.000000a47.599998,47.599998 0.000000,1.000000 1.000000,95.199997 0.000000a47.599998,47.599998 0.000000,1.000000 1.000000,-95.199997 0.000000"
-        android:fillColor="#9C27B0"/>
-    <path
-        android:pathData="M50.000000,2.429000c-26.337999,0.000000 -47.688999,21.351000 -47.688999,47.688999c0.000000,13.168000 5.337000,25.091000 13.968000,33.722000l67.444000,-67.443001C75.092003,7.766000 63.168999,2.429000 50.000000,2.429000z"
-        android:fillColor="#BA68C8"/>
-    <path
-        android:pathData="M0.000000,41.573002l100.000000,0.000000l0.000000,17.090000l-100.000000,0.000000z"
-        android:fillColor="#9C27B0"/>
-    <path
-        android:pathData="M0.000000,58.662998l0.000000,-17.089996 100.000000,0.000000z"
-        android:fillColor="#BA68C8"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_droid.xml b/packages/SystemUI/res/drawable/pop_droid.xml
deleted file mode 100644
index eed325c..0000000
--- a/packages/SystemUI/res/drawable/pop_droid.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
-        android:fillColor="#9E9D24"/>
-    <path
-        android:pathData="M30.775999,24.528000m-4.209000,0.000000a4.209000,4.209000 0.000000,1.000000 1.000000,8.418000 0.000000a4.209000,4.209000 0.000000,1.000000 1.000000,-8.418000 0.000000"
-        android:fillColor="#FFFFFF"/>
-    <path
-        android:pathData="M69.226997,24.528000m-4.210000,0.000000a4.210000,4.210000 0.000000,1.000000 1.000000,8.420000 0.000000a4.210000,4.210000 0.000000,1.000000 1.000000,-8.420000 0.000000"
-        android:fillColor="#FFFFFF"/>
-    <path
-        android:pathData="M85.352997,14.648000C65.829002,-4.877000 34.168999,-4.877000 14.646000,14.646000C4.882000,24.410000 0.002000,37.207001 0.000000,50.000999l99.996002,0.002000C99.996002,37.207001 95.115997,24.410000 85.352997,14.648000z"
-        android:fillColor="#C0CA33"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_pizza.xml b/packages/SystemUI/res/drawable/pop_pizza.xml
deleted file mode 100644
index 1806b5a..0000000
--- a/packages/SystemUI/res/drawable/pop_pizza.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M14.645000,14.645000C5.597000,23.693001 0.000000,36.193001 0.000000,50.000000l50.000000,0.000000L14.645000,14.645000z"
-        android:fillColor="#2979FF"/>
-    <path
-        android:pathData="M100.000000,50.000000c0.000000,-13.807000 -5.597000,-26.306999 -14.645000,-35.355000L50.000000,50.000000L100.000000,50.000000z"
-        android:fillColor="#FF1744"/>
-    <path
-        android:pathData="M85.355003,14.645000C76.306999,5.597000 63.806999,0.000000 50.000000,0.000000l0.000000,50.000000L85.355003,14.645000z"
-        android:fillColor="#0F9D58"/>
-    <path
-        android:pathData="M50.000000,0.000000C36.193001,0.000000 23.693001,5.597000 14.645000,14.645000L50.000000,50.000000L50.000000,0.000000z"
-        android:fillColor="#FFBC00"/>
-    <path
-        android:pathData="M50.000000,50.000000l35.355000,35.355000C94.403000,76.307999 100.000000,63.807999 100.000000,50.000000L50.000000,50.000000z"
-        android:fillColor="#2979FF"/>
-    <path
-        android:pathData="M50.000000,100.000000c13.807000,0.000000 26.306999,-5.596000 35.355000,-14.645000L50.000000,50.000000L50.000000,100.000000z"
-        android:fillColor="#FFBC00"/>
-    <path
-        android:pathData="M14.645000,85.355003C23.693001,94.403999 36.193001,100.000000 50.000000,100.000000L50.000000,50.000000L14.645000,85.355003z"
-        android:fillColor="#0F9D58"/>
-    <path
-        android:pathData="M0.000000,50.000000c0.000000,13.808000 5.597000,26.308001 14.645000,35.355000L50.000000,50.000000L0.000000,50.000000z"
-        android:fillColor="#FF1744"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_stripes.xml b/packages/SystemUI/res/drawable/pop_stripes.xml
deleted file mode 100644
index ef6c8e8..0000000
--- a/packages/SystemUI/res/drawable/pop_stripes.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
-        android:fillColor="#F57C00"/>
-    <path
-        android:pathData="M50.000999,100.000000c14.136000,0.000000 26.893000,-5.876000 35.987000,-15.308000L14.013000,84.692001C23.106001,94.124001 35.862999,100.000000 50.000999,100.000000z"
-        android:fillColor="#E65100"/>
-    <path
-        android:pathData="M50.000999,0.000000C35.862999,0.000000 23.106001,5.876000 14.013000,15.308000l71.974998,0.000000C76.893997,5.876000 64.137001,0.000000 50.000999,0.000000z"
-        android:fillColor="#FFA726"/>
-    <path
-        android:pathData="M96.501999,31.631001c-2.423000,-6.127000 -6.020000,-11.660000 -10.514000,-16.323000L14.013000,15.308001C9.517000,19.971001 5.922000,25.503000 3.499000,31.631001L96.501999,31.631001z"
-        android:fillColor="#FB8C00"/>
-    <path
-        android:pathData="M3.499000,68.370003c2.423000,6.128000 6.018000,11.658000 10.514000,16.322001l71.974998,0.000000c4.494000,-4.664000 8.091000,-10.194000 10.514000,-16.322001L3.499000,68.370003z"
-        android:fillColor="#EF6C00"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_swirl.xml b/packages/SystemUI/res/drawable/pop_swirl.xml
deleted file mode 100644
index f87569b..0000000
--- a/packages/SystemUI/res/drawable/pop_swirl.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000C86.898003,27.834999 79.244003,11.688000 76.177002,7.399000c-7.240000,-4.459000 -15.703000,-7.112000 -24.770000,-7.363000C56.247002,2.253000 70.815002,12.456000 50.000000,50.000000z"
-        android:fillColor="#FFFFFA"/>
-    <path
-        android:pathData="M50.000000,50.000000c20.815001,-37.543999 6.247000,-47.747002 1.407000,-49.964001C50.938000,0.022000 50.472000,0.000000 50.000000,0.000000c-8.627000,0.000000 -16.743999,2.186000 -23.827000,6.032000C31.392000,5.514000 49.251999,6.903000 50.000000,50.000000z"
-        android:fillColor="#76FF03"/>
-    <path
-        android:pathData="M50.000000,50.000000c37.543999,20.816000 47.747002,6.248000 49.965000,1.408000C99.977997,50.938000 100.000000,50.473000 100.000000,50.000000c0.000000,-8.627000 -2.186000,-16.743999 -6.032000,-23.827000C94.486000,31.393000 93.098000,49.251999 50.000000,50.000000z"
-        android:fillColor="#76FF03"/>
-    <path
-        android:pathData="M50.000000,50.000000c43.098000,-0.748000 44.486000,-18.607000 43.967999,-23.827000c-4.186000,-7.708000 -10.344000,-14.188000 -17.791000,-18.773001C79.244003,11.688000 86.898003,27.834999 50.000000,50.000000z"
-        android:fillColor="#303F9F"/>
-    <path
-        android:pathData="M50.000000,50.000000C27.834000,13.103000 11.687000,20.757000 7.398000,23.823999C2.940000,31.063000 0.287000,39.527000 0.035000,48.592999C2.253000,43.752998 12.456000,29.184999 50.000000,50.000000z"
-        android:fillColor="#FFFFFA"/>
-    <path
-        android:pathData="M50.000000,50.000000C49.251999,6.903000 31.392000,5.514000 26.173000,6.032000c-7.709000,4.187000 -14.188000,10.344000 -18.774000,17.792000C11.687000,20.757000 27.834000,13.103000 50.000000,50.000000z"
-        android:fillColor="#303F9F"/>
-    <path
-        android:pathData="M50.000000,50.000000C12.456000,29.184999 2.253000,43.752998 0.035000,48.592999C0.022000,49.062000 0.000000,49.528000 0.000000,50.000000c0.000000,8.628000 2.186000,16.743999 6.032000,23.827999C5.514000,68.609001 6.902000,50.749001 50.000000,50.000000z"
-        android:fillColor="#76FF03"/>
-    <path
-        android:pathData="M50.000000,50.000000c0.748000,43.098000 18.608000,44.486000 23.827000,43.969002c7.709000,-4.187000 14.188000,-10.344000 18.774000,-17.791000C88.313004,79.244003 72.166000,86.898003 50.000000,50.000000z"
-        android:fillColor="#303F9F"/>
-    <path
-        android:pathData="M50.000000,50.000000c22.166000,36.897999 38.313000,29.243999 42.602001,26.177999c4.458000,-7.240000 7.111000,-15.703000 7.363000,-24.770000C97.747002,56.248001 87.543999,70.816002 50.000000,50.000000z"
-        android:fillColor="#FFFFFA"/>
-    <path
-        android:pathData="M50.000000,50.000000c-20.815001,37.544998 -6.247000,47.748001 -1.407000,49.965000C49.062000,99.978996 49.528000,100.000000 50.000000,100.000000c8.627000,0.000000 16.743999,-2.185000 23.827000,-6.031000C68.608002,94.486000 50.748001,93.098000 50.000000,50.000000z"
-        android:fillColor="#76FF03"/>
-    <path
-        android:pathData="M50.000000,50.000000C13.103000,72.166000 20.757000,88.313004 23.823000,92.601997c7.240000,4.459000 15.703000,7.112000 24.770000,7.363000C43.752998,97.748001 29.184999,87.544998 50.000000,50.000000z"
-        android:fillColor="#FFFFFA"/>
-    <path
-        android:pathData="M50.000000,50.000000C6.902000,50.749001 5.514000,68.609001 6.032000,73.828003c4.186000,7.708000 10.344000,14.188000 17.791000,18.773001C20.757000,88.313004 13.103000,72.166000 50.000000,50.000000z"
-        android:fillColor="#303F9F"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_vortex.xml b/packages/SystemUI/res/drawable/pop_vortex.xml
deleted file mode 100644
index 2380e68..0000000
--- a/packages/SystemUI/res/drawable/pop_vortex.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
-        android:fillColor="#F8F8FF"/>
-    <path
-        android:pathData="M58.658001,89.648003c-19.330000,0.000000 -35.000000,-15.670000 -35.000000,-35.000000c0.000000,-13.531000 10.969000,-24.500000 24.500000,-24.500000c9.472000,0.000000 17.150000,7.679000 17.150000,17.150000c0.000000,6.631000 -5.375000,12.006000 -12.006000,12.006000c-3.798000,0.000000 -7.004000,-2.522000 -8.045000,-5.982000c1.021000,1.136000 2.497000,1.854000 4.145000,1.854000c2.644000,0.000000 4.853000,-1.841000 5.428000,-4.310000c0.175000,-0.558000 0.271000,-1.150000 0.271000,-1.766000c0.000000,-4.642000 -3.763000,-8.404000 -8.403000,-8.404000c-6.631000,0.000000 -12.006000,5.375000 -12.006000,12.006000c0.000000,9.472000 7.679000,17.149000 17.150000,17.149000c13.531000,0.000000 24.500000,-10.969000 24.500000,-24.500000c0.000000,-19.330000 -15.670000,-35.000000 -35.000000,-35.000000c-12.963000,0.000000 -24.773001,4.935000 -33.657001,13.025000C2.824000,31.087000 0.000000,40.212002 0.000000,50.000000c0.000000,27.615000 22.386000,50.000000 50.000000,50.000000c17.825001,0.000000 33.462002,-9.335000 42.313999,-23.375999C83.431000,84.714996 71.621002,89.648003 58.658001,89.648003z"
-        android:fillColor="#7BAAF7"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_vortex2.xml b/packages/SystemUI/res/drawable/pop_vortex2.xml
deleted file mode 100644
index 0a96b74..0000000
--- a/packages/SystemUI/res/drawable/pop_vortex2.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="100.0dp"
-        android:height="100.0dp"
-        android:viewportWidth="100.0"
-        android:viewportHeight="100.0">
-    <path
-        android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
-        android:fillColor="#D81B60"/>
-    <path
-        android:pathData="M21.250000,78.369003c-13.200000,-16.000000 -10.930000,-39.671001 5.070000,-52.870998c12.799000,-10.560000 31.737000,-8.743000 42.294998,4.057000c8.448000,10.239000 6.996000,25.389000 -3.244000,33.837002c-8.191000,6.759000 -20.311001,5.596000 -27.068001,-2.596000c-5.408000,-6.554000 -4.478000,-16.249001 2.076000,-21.656000c5.242000,-4.325000 12.998000,-3.581000 17.323999,1.661000c3.460000,4.194000 2.865000,10.399000 -1.330000,13.859000c-3.354000,2.769000 -8.318000,2.293000 -11.087000,-1.062000c-2.214000,-2.685000 -1.833000,-6.655000 0.851000,-8.870000c2.147000,-1.771000 5.324000,-1.468000 7.096000,0.681000c1.393000,1.688000 1.174000,4.165000 -0.464000,5.596000c0.409000,-0.564000 0.657000,-1.253000 0.657000,-2.004000c0.000000,-1.021000 -0.455000,-1.928000 -1.165000,-2.556000c-0.067000,-0.112000 -0.134000,-0.226000 -0.220000,-0.329000c-1.135000,-1.373000 -3.168000,-1.568000 -4.542000,-0.435000c-1.719000,1.417000 -1.962000,3.958000 -0.544000,5.677000c1.771000,2.146000 4.949000,2.451000 7.096000,0.680000c2.684000,-2.215000 3.064000,-6.186000 0.851000,-8.870000c-2.769000,-3.356000 -7.732000,-3.831000 -11.087000,-1.063000c-4.195000,3.460000 -4.790000,9.665000 -1.330000,13.859000c4.326000,5.244000 12.082000,5.987000 17.323999,1.662000c6.554000,-5.407000 7.484000,-15.102000 2.076000,-21.656000c-6.758000,-8.191000 -18.875999,-9.354000 -27.069000,-2.596000c-10.239000,8.448000 -11.691000,23.598000 -3.244000,33.837002c10.560000,12.800000 29.497000,14.616000 42.296001,4.056000c16.000000,-13.199000 18.270000,-36.869999 5.070000,-52.868999C68.397003,5.620000 52.516998,-0.139000 37.205002,1.659000c-8.665000,2.287000 -16.410999,6.836000 -22.561001,12.985000C5.597000,23.693001 0.000000,36.193001 0.000000,50.000000c0.000000,13.808000 5.597000,26.308001 14.645000,35.355000C23.693001,94.403999 36.193001,100.000000 50.000000,100.000000c11.935000,0.000000 22.886999,-4.187000 31.482000,-11.164000C61.909000,100.523003 36.202999,96.495003 21.250000,78.369003z"
-        android:fillColor="#F06292"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/qs_subhead_caret.xml b/packages/SystemUI/res/drawable/qs_subhead_caret.xml
deleted file mode 100644
index 13a168d..0000000
--- a/packages/SystemUI/res/drawable/qs_subhead_caret.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-
-    <path
-        android:fillColor="@color/qs_subhead"
-        android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/qs_tile_background.xml b/packages/SystemUI/res/drawable/qs_tile_background.xml
deleted file mode 100644
index 96891c1..0000000
--- a/packages/SystemUI/res/drawable/qs_tile_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true">
-	<color android:color="#212121" />
-    </item>
-    <item>
-        <color android:color="#161616" />
-    </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/quick_header_bg.xml b/packages/SystemUI/res/drawable/quick_header_bg.xml
deleted file mode 100644
index 920e6f5..0000000
--- a/packages/SystemUI/res/drawable/quick_header_bg.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 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
-  -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight" >
-    <item android:drawable="?android:attr/colorPrimary"/>
-</ripple>
diff --git a/packages/SystemUI/res/drawable/scorecard_gameover.xml b/packages/SystemUI/res/drawable/scorecard_gameover.xml
deleted file mode 100644
index f663a66..0000000
--- a/packages/SystemUI/res/drawable/scorecard_gameover.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    >
-    <corners
-        android:radius="8dp" />
-    <solid
-        android:color="#ffff0000" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/stat_notify_more.xml b/packages/SystemUI/res/drawable/stat_notify_more.xml
deleted file mode 100644
index 50f1286..0000000
--- a/packages/SystemUI/res/drawable/stat_notify_more.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  ~ Copyright (C) 2014 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="16dp"
-        android:height="16dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M22.000000,3.000000L7.000000,3.000000C6.300000,3.000000 5.800000,3.400000 5.400000,3.900000L0.000000,12.000000l5.400000,8.100000c0.400000,0.500000 1.000000,0.900000 1.700000,0.900000L22.000000,21.000000c1.100000,0.000000 2.000000,-0.900000 2.000000,-2.000000L24.000000,5.000000C24.000000,3.900000 23.100000,3.000000 22.000000,3.000000zM9.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S9.800000,13.500000 9.000000,13.500000zM14.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S14.800000,13.500000 14.000000,13.500000zM19.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S19.799999,13.500000 19.000000,13.500000z"
-        android:fillColor="#FFFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
deleted file mode 100644
index ba0709e..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:height="17dp"
-        android:width="17dp"
-        android:viewportHeight="48"
-        android:viewportWidth="48" >
-        <group
-            android:name="ic_screen_rotation_48px_outlines"
-            android:translateX="24"
-            android:translateY="24" >
-            <group
-                android:name="ic_screen_rotation_48px_outlines_pivot"
-                android:translateX="-24.15"
-                android:translateY="-24.25" >
-                <group
-                    android:name="arrows"
-                    android:translateX="24.1"
-                    android:translateY="24.1" >
-                    <group
-                        android:name="arrows_pivot"
-                        android:translateX="-24.1"
-                        android:translateY="-24.1" >
-                        <path
-                            android:name="arrow_top"
-                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
-                            android:fillColor="#FFFFFFFF"
-                            android:fillAlpha="1" />
-                        <path
-                            android:name="arrow_bottom"
-                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
-                            android:fillColor="#FFFFFFFF"
-                            android:fillAlpha="1" />
-                    </group>
-                </group>
-                <group
-                    android:name="device"
-                    android:translateX="24.14999"
-                    android:translateY="24.25" >
-                    <path
-                        android:name="body"
-                        android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
-                        android:fillColor="#FFFFFFFF"
-                        android:fillAlpha="1" />
-                </group>
-            </group>
-        </group>
-    </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
deleted file mode 100644
index 46a1f35..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:height="17dp"
-        android:width="17dp"
-        android:viewportHeight="48"
-        android:viewportWidth="48" >
-        <group
-            android:name="icon"
-            android:translateX="24"
-            android:translateY="24" >
-            <group
-                android:name="icon_pivot"
-                android:translateX="-24.15"
-                android:translateY="-24.25" >
-                <group
-                    android:name="arrows"
-                    android:translateX="24.1"
-                    android:translateY="24.1" >
-                    <group
-                        android:name="arrows_pivot"
-                        android:translateX="-24.1"
-                        android:translateY="-24.1" >
-                        <path
-                            android:name="arrow_top"
-                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
-                            android:fillColor="#FFFFFFFF"
-                            android:fillAlpha="1" />
-                        <path
-                            android:name="arrow_bottom"
-                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
-                            android:fillColor="#FFFFFFFF"
-                            android:fillAlpha="1" />
-                    </group>
-                </group>
-                <group
-                    android:name="device"
-                    android:translateX="24.14999"
-                    android:translateY="24.25" >
-                    <path
-                        android:name="device_1"
-                        android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
-                        android:fillColor="#FFFFFFFF"
-                        android:fillAlpha="1" />
-                </group>
-            </group>
-        </group>
-    </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml
deleted file mode 100644
index 1dedd5d..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="23dp"
-        android:height="18dp"
-        android:viewportWidth="23.0"
-        android:viewportHeight="18.0">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19.4,16.6l-1.1,-1.1L8,5L5.1,2.2L4.2,3.1l2,2H5.7c-0.8,0 -1.4,0.6 -1.4,1.4v8c0,0.8 0.6,1.4 1.4,1.4h11.4l1.5,1.5L19.4,16.6zM18.7,6.5c0,-0.8 -0.6,-1.4 -1.4,-1.4h-2.9V3.6c0,-0.8 -0.6,-1.4 -1.4,-1.4h-3C9.2,2.1 8.6,2.8 8.6,3.6v0.2L18.7,14C18.7,14 18.7,6.5 18.7,6.5zM12.9,5.1H10V3.6h2.9V5.1z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml b/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
deleted file mode 100644
index 5c9be5c..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="17dp"
-    android:height="17dp"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h6v-3h2V9H12.09zM20,13h-2v3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H20V13z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
deleted file mode 100644
index 7e6e09b..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="in"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
deleted file mode 100644
index b7b6f0f..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="in"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
-    <path
-        android:name="out"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
deleted file mode 100644
index 910c035..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="out"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
deleted file mode 100644
index ba3d4e6..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="16.25dp"
-        android:height="15dp"
-        android:viewportWidth="26.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="in"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
deleted file mode 100644
index 1f3b68f..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="16.25dp"
-        android:height="15dp"
-        android:viewportWidth="26.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="in"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
-    <path
-        android:name="out"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
deleted file mode 100644
index 24c6b1e..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="16.25dp"
-        android:height="15dp"
-        android:viewportWidth="26.0"
-        android:viewportHeight="24.0">
-    <path
-        android:name="out"
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/sun2.xml b/packages/SystemUI/res/drawable/sun2.xml
deleted file mode 100644
index 6d2d504..0000000
--- a/packages/SystemUI/res/drawable/sun2.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48.0dp"
-        android:height="48.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
-    <path
-        android:pathData="M40.000000,17.400000L40.000000,8.000000l-9.400000,0.000000L24.000000,1.400000L17.400000,8.000000L8.000000,8.000000l0.000000,9.400000L1.400000,24.000000L8.000000,30.600000L8.000000,40.000000l9.400000,0.000000l6.600000,6.600000l6.600000,-6.600000L40.000000,40.000000l0.000000,-9.400000l6.600000,-6.600000L40.000000,17.400000zM24.000000,36.000000c-6.600000,0.000000 -12.000000,-5.400000 -12.000000,-12.000000s5.400000,-12.000000 12.000000,-12.000000c6.600000,0.000000 12.000000,5.400000 12.000000,12.000000S30.600000,36.000000 24.000000,36.000000zM24.000000,16.000000c-4.400000,0.000000 -8.000000,3.600000 -8.000000,8.000000c0.000000,4.400000 3.600000,8.000000 8.000000,8.000000s8.000000,-3.600000 8.000000,-8.000000C32.000000,19.600000 28.400000,16.000000 24.000000,16.000000z"
-        android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_outline.xml b/packages/SystemUI/res/drawable/tv_pip_outline.xml
deleted file mode 100644
index c84438c..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_outline.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <stroke android:width="2dp" android:color="#EEEEEE" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
deleted file mode 100644
index 996ac5e..0000000
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
-     Copyright (C) 2015 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" >
-    <solid android:color="?android:attr/colorBackgroundFloating" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 874cdcc..6864ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -48,14 +48,14 @@
 
 import com.android.settingslib.Utils;
 import com.android.settingslib.graph.BatteryMeterDrawableBase;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 08fa434..6e50429 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -38,6 +38,7 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.power.EnhancedEstimates;
@@ -45,7 +46,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.DisplayNavigationBarController;
+import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -79,7 +80,6 @@
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.ExtensionController;
@@ -244,7 +244,7 @@
     @Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
     @Inject Lazy<InitController> mInitController;
     @Inject Lazy<AppOpsController> mAppOpsController;
-    @Inject Lazy<DisplayNavigationBarController> mDisplayNavigationBarController;
+    @Inject Lazy<NavigationBarController> mNavigationBarController;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
     @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
     @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper;
@@ -410,8 +410,7 @@
 
         mProviders.put(AppOpsController.class, mAppOpsController::get);
 
-        mProviders.put(DisplayNavigationBarController.class,
-                mDisplayNavigationBarController::get);
+        mProviders.put(NavigationBarController.class, mNavigationBarController::get);
 
         mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
         mProviders.put(NotificationLockscreenUserManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index b93a5fd..1ee1dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -19,6 +19,7 @@
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
@@ -37,7 +38,6 @@
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastControllerImpl;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 import com.android.systemui.statusbar.policy.ExtensionController;
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index 2b521c5..5c9b999 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -41,6 +41,7 @@
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
+import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -170,6 +171,13 @@
 
     @Singleton
     @Provides
+    public NavigationBarController provideNavigationBarController(Context context,
+            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+        return new NavigationBarController(context, mainHandler);
+    }
+
+    @Singleton
+    @Provides
     public ConfigurationController provideConfigurationController(Context context) {
         return new ConfigurationControllerImpl(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index 47b56d0..fa5a114 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -22,22 +22,22 @@
 public interface DockManager {
 
     /**
-     * Uninitialized / unknown dock states
+     * Uninitialized / undocking dock states
      */
     int STATE_NONE = 0;
     /**
      * The state for docking
      */
-    int STATE_DOCKING = 1;
+    int STATE_DOCKED = 1;
     /**
-     * The state for undocking
+     * The state for docking without showing UI
      */
-    int STATE_UNDOCKING = 2;
+    int STATE_DOCKED_HIDE = 2;
 
     /**
      * Add a dock event listener into manager
      *
-     * @param callback A  {@link DockEventListener} which want to add
+     * @param callback A {@link DockEventListener} which want to add
      */
     void addListener(DockEventListener callback);
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 8cd42c7..9fc2234 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -18,11 +18,13 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.DozeMachine.State;
 
 import java.io.PrintWriter;
 
@@ -34,7 +36,6 @@
     private static final String TAG = "DozeDockHandler";
     private static final boolean DEBUG = DozeService.DEBUG;
 
-    private final Context mContext;
     private final DozeMachine mMachine;
     private final DozeHost mDozeHost;
     private final AmbientDisplayConfiguration mConfig;
@@ -42,11 +43,10 @@
     private final DockEventListener mDockEventListener = new DockEventListener();
     private final DockManager mDockManager;
 
-    private boolean mDocking;
+    private int mDockState = DockManager.STATE_NONE;
 
     public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
             AmbientDisplayConfiguration config, Handler handler) {
-        mContext = context;
         mMachine = machine;
         mDozeHost = dozeHost;
         mConfig = config;
@@ -60,34 +60,35 @@
             case INITIALIZED:
                 mDockEventListener.register();
                 break;
-            case DOZE:
             case DOZE_AOD:
-                mHandler.post(() -> requestPulse());
+                if (mDockState == DockManager.STATE_DOCKED_HIDE) {
+                    mMachine.requestState(State.DOZE);
+                    break;
+                }
+                // continue below
+            case DOZE:
+                if (mDockState == DockManager.STATE_DOCKED) {
+                    mHandler.post(() -> requestPulse(newState));
+                }
                 break;
             case FINISH:
                 mDockEventListener.unregister();
                 break;
             default:
+                // no-op
         }
     }
 
-    private void requestPulse() {
-        if (!mDocking || mDozeHost.isPulsingBlocked() || !canPulse()) {
+    private void requestPulse(State dozeState) {
+        if (mDozeHost.isPulsingBlocked() || !dozeState.canPulse()) {
             return;
         }
 
         mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING);
     }
 
-    private boolean canPulse() {
-        return mMachine.getState() == DozeMachine.State.DOZE
-                || mMachine.getState() == DozeMachine.State.DOZE_AOD;
-    }
-
-    private void requestPulseOutNow() {
-        final DozeMachine.State state = mMachine.getState();
-        if (state == DozeMachine.State.DOZE_PULSING
-                || state == DozeMachine.State.DOZE_REQUEST_PULSE) {
+    private void requestPulseOutNow(State dozeState) {
+        if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING) {
             final int pulseReason = mMachine.getPulseReason();
             if (pulseReason == DozeLog.PULSE_REASON_DOCKING) {
                 mDozeHost.stopPulsing();
@@ -95,9 +96,14 @@
         }
     }
 
+    private boolean isDocked() {
+        return mDockState == DockManager.STATE_DOCKED
+                || mDockState == DockManager.STATE_DOCKED_HIDE;
+    }
+
     @Override
     public void dump(PrintWriter pw) {
-        pw.print(" DozeDockTriggers docking="); pw.println(mDocking);
+        pw.print(" DozeDockTriggers docking="); pw.println(isDocked());
     }
 
     private class DockEventListener implements DockManager.DockEventListener {
@@ -106,14 +112,21 @@
         @Override
         public void onEvent(int event) {
             if (DEBUG) Log.d(TAG, "dock event = " + event);
-            switch (event) {
-                case DockManager.STATE_DOCKING:
-                    mDocking = true;
-                    requestPulse();
+            final DozeMachine.State dozeState = mMachine.getState();
+            mDockState = event;
+            switch (mDockState) {
+                case DockManager.STATE_DOCKED:
+                    requestPulse(dozeState);
                     break;
-                case DockManager.STATE_UNDOCKING:
-                    mDocking = false;
-                    requestPulseOutNow();
+                case DockManager.STATE_NONE:
+                    if (dozeState == State.DOZE
+                            && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+                        mMachine.requestState(State.DOZE_AOD);
+                        break;
+                    }
+                    // continue below
+                case DockManager.STATE_DOCKED_HIDE:
+                    requestPulseOutNow(dozeState);
                     break;
                 default:
                     // no-op
@@ -124,7 +137,6 @@
             if (mRegistered) {
                 return;
             }
-
             if (mDockManager != null) {
                 mDockManager.addListener(this);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 35b64ed..04362c1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -359,7 +359,9 @@
         }
 
         protected boolean enabledBySetting() {
-            if (TextUtils.isEmpty(mSetting)) {
+            if (!mConfig.enabled(UserHandle.USER_CURRENT)) {
+                return false;
+            } else if (TextUtils.isEmpty(mSetting)) {
                 return true;
             }
             return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index d7d3981..7c937a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -17,6 +17,7 @@
 
 import android.app.ActivityManager;
 import android.app.AlertDialog;
+import android.app.admin.DevicePolicyEventLogger;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -30,6 +31,7 @@
 import android.text.method.LinkMovementMethod;
 import android.text.style.ClickableSpan;
 import android.util.Log;
+import android.util.StatsLog;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -119,6 +121,9 @@
 
     private void handleClick() {
         showDeviceMonitoringDialog();
+        DevicePolicyEventLogger
+                .createEvent(StatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED)
+                .write();
     }
 
     public void showDeviceMonitoringDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index bec027f..7224599 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -63,6 +63,8 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.privacy.OngoingPrivacyChip;
 import com.android.systemui.privacy.OngoingPrivacyDialog;
 import com.android.systemui.privacy.PrivacyItem;
@@ -75,8 +77,6 @@
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java
deleted file mode 100644
index 78172f1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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.statusbar;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.View;
-import android.view.WindowManagerGlobal;
-
-import com.android.systemui.statusbar.phone.NavigationBarFragment;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-/**
- * A controller to handle external navigation bars
- */
-@Singleton
-public class DisplayNavigationBarController implements DisplayListener {
-
-    private static final String TAG = DisplayNavigationBarController.class.getName();
-
-    private final Context mContext;
-    private final Handler mHandler;
-    private final DisplayManager mDisplayManager;
-
-    /** A displayId - nav bar mapping */
-    private SparseArray<NavigationBarFragment> mExternalNavigationBarMap = new SparseArray<>();
-
-    @Inject
-    public DisplayNavigationBarController(Context context,
-            @Named(MAIN_HANDLER_NAME) Handler handler) {
-        mContext = context;
-        mHandler = handler;
-        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-
-        registerListener();
-    }
-
-    @Override
-    public void onDisplayAdded(int displayId) {
-        final Display display = mDisplayManager.getDisplay(displayId);
-        addExternalNavigationBar(display);
-    }
-
-    @Override
-    public void onDisplayRemoved(int displayId) {
-        final NavigationBarFragment navBar = mExternalNavigationBarMap.get(displayId);
-        if (navBar != null) {
-            final View navigationView = navBar.getView().getRootView();
-            WindowManagerGlobal.getInstance().removeView(navigationView, true);
-            mExternalNavigationBarMap.remove(displayId);
-        }
-    }
-
-    @Override
-    public void onDisplayChanged(int displayId) {
-    }
-
-    /** Create external navigation bars when car/status bar initializes */
-    public void createNavigationBars() {
-        // Add external navigation bars if more than one displays exist.
-        final Display[] displays = mDisplayManager.getDisplays();
-        for (Display display : displays) {
-            addExternalNavigationBar(display);
-        }
-    }
-
-    /** remove external navigation bars and unset everything related to external navigation bars */
-    public void destroy() {
-        unregisterListener();
-        if (mExternalNavigationBarMap.size() > 0) {
-            for (int i = 0; i < mExternalNavigationBarMap.size(); i++) {
-                final View navigationWindow = mExternalNavigationBarMap.valueAt(i)
-                        .getView().getRootView();
-                WindowManagerGlobal.getInstance()
-                        .removeView(navigationWindow, true /* immediate */);
-            }
-            mExternalNavigationBarMap.clear();
-        }
-    }
-
-    private void registerListener() {
-        mDisplayManager.registerDisplayListener(this, mHandler);
-    }
-
-    private void unregisterListener() {
-        mDisplayManager.unregisterDisplayListener(this);
-    }
-
-    /**
-     * Add a phone navigation bar on an external display if the display supports system decorations.
-     *
-     * @param display the display to add navigation bar on
-     */
-    private void addExternalNavigationBar(Display display) {
-        if (display == null || display.getDisplayId() == DEFAULT_DISPLAY
-                || !display.supportsSystemDecorations()) {
-            return;
-        }
-
-        final int displayId = display.getDisplayId();
-        final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
-
-        try {
-            if (!wms.hasNavigationBar(displayId)) {
-                return;
-            }
-        } catch (RemoteException e) {
-            // Cannot get wms, just return with warning message.
-            Log.w(TAG, "Cannot get WindowManager.");
-            return;
-        }
-        final Context externalDisplayContext = mContext.createDisplayContext(display);
-        NavigationBarFragment.create(externalDisplayContext, (tag, fragment) -> {
-            final NavigationBarFragment navBar = (NavigationBarFragment) fragment;
-            // TODO(b/115978725): handle external nav bars sysuiVisibility
-            navBar.setCurrentSysuiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
-            mExternalNavigationBarMap.append(displayId, navBar);
-        });
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index b39a96d..e217777 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -31,8 +31,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 
 import java.util.List;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
new file mode 100644
index 0000000..43eaff4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -0,0 +1,222 @@
+/*
+ * 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.statusbar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+
+/** A controller to handle navigation bars. */
+@Singleton
+public class NavigationBarController implements DisplayListener {
+
+    private static final String TAG = NavigationBarController.class.getName();
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final DisplayManager mDisplayManager;
+
+    /** A displayId - nav bar maps. */
+    private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+
+    @Inject
+    public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+        mContext = context;
+        mHandler = handler;
+        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(this, mHandler);
+    }
+
+    @Override
+    public void onDisplayAdded(int displayId) {
+        Display display = mDisplayManager.getDisplay(displayId);
+        createNavigationBar(display);
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        removeNavigationBar(displayId);
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+    }
+
+    // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
+    // CarStatusBar because they have their own nav bar. Think about a better way for it.
+    /**
+     * Creates navigation bars when car/status bar initializes.
+     *
+     * @param includeDefaultDisplay {@code true} to create navigation bar on default display.
+     */
+    public void createNavigationBars(final boolean includeDefaultDisplay) {
+        Display[] displays = mDisplayManager.getDisplays();
+        for (Display display : displays) {
+            if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
+                createNavigationBar(display);
+            }
+        }
+    }
+
+    /**
+     * Adds a navigation bar on default display or an external display if the display supports
+     * system decorations.
+     *
+     * @param display the display to add navigation bar on.
+     */
+    private void createNavigationBar(Display display) {
+        if (display == null
+                || (display.getDisplayId() != DEFAULT_DISPLAY
+                        && !display.supportsSystemDecorations())) {
+            return;
+        }
+
+        final int displayId = display.getDisplayId();
+        final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
+        final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+
+        try {
+            if (!wms.hasNavigationBar(displayId)) {
+                return;
+            }
+        } catch (RemoteException e) {
+            // Cannot get wms, just return with warning message.
+            Log.w(TAG, "Cannot get WindowManager.");
+            return;
+        }
+        final Context context = isOnDefaultDisplay
+                ? mContext
+                : mContext.createDisplayContext(display);
+        NavigationBarFragment.create(context, (tag, fragment) -> {
+            NavigationBarFragment navBar = (NavigationBarFragment) fragment;
+
+            // Unfortunately, we still need it because status bar needs LightBarController
+            // before notifications creation. We cannot directly use getLightBarController()
+            // from NavigationBarFragment directly.
+            LightBarController controller = isOnDefaultDisplay
+                    ? Dependency.get(LightBarController.class)
+                    : new LightBarController(context,
+                            Dependency.get(DarkIconDispatcher.class),
+                            Dependency.get(BatteryController.class));
+            navBar.setLightBarController(controller);
+            navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+            mNavigationBars.append(displayId, navBar);
+        });
+    }
+
+    /** Removes navigation bars. */
+    public void destroy() {
+        mDisplayManager.unregisterDisplayListener(this);
+        if (mNavigationBars.size() > 0) {
+            for (int i = 0; i < mNavigationBars.size(); i++) {
+                int displayId = mNavigationBars.keyAt(i);
+                removeNavigationBar(displayId);
+            }
+            mNavigationBars.clear();
+        }
+    }
+
+    private void removeNavigationBar(int displayId) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            View navigationWindow = navBar.getView().getRootView();
+            WindowManagerGlobal.getInstance()
+                    .removeView(navigationWindow, true /* immediate */);
+            mNavigationBars.remove(displayId);
+        }
+    }
+
+    /** @see NavigationBarFragment#checkNavBarModes() */
+    public void checkNavBarModes(int displayId) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            navBar.checkNavBarModes();
+        }
+    }
+
+    /** @see NavigationBarFragment#finishBarAnimations() */
+    public void finishBarAnimations(int displayId) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            navBar.finishBarAnimations();
+        }
+    }
+
+    /** @see NavigationBarFragment#touchAutoDim() */
+    public void touchAutoDim(int displayId) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            navBar.touchAutoDim();
+        }
+    }
+
+    /** @see NavigationBarFragment#transitionTo(int, boolean) */
+    public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            navBar.transitionTo(barMode, animate);
+        }
+    }
+
+    /** @see NavigationBarFragment#isSemiTransparent() */
+    public boolean isSemiTransparent(int displayId) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            return navBar.isSemiTransparent();
+        }
+        return false;
+    }
+
+    /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
+    public void disableAnimationsDuringHide(int displayId, long delay) {
+        NavigationBarFragment navBar = mNavigationBars.get(displayId);
+        if (navBar != null) {
+            navBar.disableAnimationsDuringHide(delay);
+        }
+    }
+
+    /** @return {@link NavigationBarView} on the default display. */
+    public NavigationBarView getDefaultNavigationBarView() {
+        NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
+        return (navBar == null) ? null : (NavigationBarView) navBar.getView();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 25837e1..1bf101c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -157,7 +157,7 @@
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    Entry entry,
+                    @Nullable Entry entry,
                     String key,
                     StatusBarNotification old,
                     NotificationVisibility visibility,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 674e262..886d99e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.KeyguardManager;
@@ -252,13 +253,13 @@
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    NotificationData.Entry entry,
+                    @Nullable NotificationData.Entry entry,
                     String key,
                     StatusBarNotification old,
                     NotificationVisibility visibility,
                     boolean lifetimeExtended,
                     boolean removedByUser) {
-                if (removedByUser) {
+                if (removedByUser && entry != null) {
                     onPerformRemoveNotification(entry, key);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index f1a891b..d1b3c3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -30,8 +30,8 @@
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index e7b768f..6d2c001 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -41,9 +41,9 @@
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 8b61a5b..3c13354 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index bc89889..4db981d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -37,8 +37,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
         StatusIconDisplayable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 045221f..c5751c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
 import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -37,8 +37,8 @@
 
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 /**
  * Start small: StatusBarWifiView will be able to layout from a WifiIconState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
index beb90b8..d541fae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar;
 
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 
 public interface StatusIconDisplayable extends DarkReceiver {
     String getSlot();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index dbc6f43..7b42dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
@@ -82,7 +83,7 @@
 
             @Override
             public void onEntryRemoved(
-                    NotificationData.Entry entry,
+                    @Nullable NotificationData.Entry entry,
                     String key,
                     StatusBarNotification old,
                     NotificationVisibility visibility,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 27c2837..a51896e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -90,7 +90,7 @@
         private static final long INITIALIZATION_DELAY = 400;
         private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
         private static final int COLOR_INVALID = 1;
-        public String key;
+        public final String key;
         public StatusBarNotification notification;
         public NotificationChannel channel;
         public long lastAudiblyAlertedMs;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 72f1d5b..1d06ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -80,7 +80,7 @@
      * @param removedByUser true if the notification was removed by a user action
      */
     default void onEntryRemoved(
-            NotificationData.Entry entry,
+            @Nullable NotificationData.Entry entry,
             String key,
             StatusBarNotification old,
             @Nullable NotificationVisibility visibility,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 060e755..32acb8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.statusbar.notification.logging;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -167,13 +168,13 @@
         entryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    NotificationData.Entry entry,
+                    @Nullable NotificationData.Entry entry,
                     String key,
                     StatusBarNotification old,
                     NotificationVisibility visibility,
                     boolean lifetimeExtended,
                     boolean removedByUser) {
-                if (removedByUser && visibility != null) {
+                if (removedByUser && visibility != null && entry.notification != null) {
                     logNotificationClear(key, entry.notification, visibility);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 5329541..b1eab80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -40,6 +40,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
@@ -150,6 +151,7 @@
         // Reset exit counter that we'll log and record an undo event separately (not an exit event)
         mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
         logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
+        mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
         swapContent(ACTION_UNDO, true /* animate */);
     };
 
@@ -381,6 +383,17 @@
         }
     }
 
+    /**
+     * Returns an initialized LogMaker for logging importance changes.
+     * The caller may override the type (to DISMISS) before passing it to mMetricsLogger.
+     * @return new LogMaker
+     */
+    private LogMaker importanceChangeLogMaker() {
+        return new LogMaker(MetricsEvent.ACTION_SAVE_IMPORTANCE)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setSubtype(mChosenImportance - mStartingChannelImportance);
+    }
+
     private boolean hasImportanceChanged() {
         return mSingleNotificationChannel != null
                 && mStartingChannelImportance != mChosenImportance;
@@ -397,8 +410,7 @@
      * Commits the updated importance values on the background thread.
      */
     private void updateImportance() {
-        MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
-                mChosenImportance - mStartingChannelImportance);
+        mMetricsLogger.write(importanceChangeLogMaker());
 
         Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
         bgHandler.post(new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 8c8bad2..a5411ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -87,8 +87,8 @@
 
             try {
                 drawable = mResolver.resolveImage(target);
-            } catch (IOException ex) {
-                Log.d(TAG, "PreloadImageTask: Resolve failed from " + target);
+            } catch (IOException | SecurityException ex) {
+                Log.d(TAG, "PreloadImageTask: Resolve failed from " + target, ex);
             }
 
             return drawable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 588246f..a3e1305 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -81,8 +81,8 @@
         Drawable result = null;
         try {
             result = hasCache() ? mImageCache.get(uri) : resolveImage(uri);
-        } catch (IOException ex) {
-            Log.d(TAG, "loadImage: Can't load image from " + uri);
+        } catch (IOException | SecurityException ex) {
+            Log.d(TAG, "loadImage: Can't load image from " + uri, ex);
         }
         return result;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 3d81473..7905617 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -36,6 +37,9 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 public class BarTransitions {
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_COLORS = false;
@@ -48,6 +52,18 @@
     public static final int MODE_WARNING = 5;
     public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
 
+    @IntDef(flag = true, prefix = { "MODE_" }, value = {
+            MODE_OPAQUE,
+            MODE_SEMI_TRANSPARENT,
+            MODE_TRANSLUCENT,
+            MODE_LIGHTS_OUT,
+            MODE_TRANSPARENT,
+            MODE_WARNING,
+            MODE_LIGHTS_OUT_TRANSPARENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TransitionMode {}
+
     public static final int LIGHTS_IN_DURATION = 250;
     public static final int LIGHTS_OUT_DURATION = 1500;
     public static final int BACKGROUND_DURATION = 200;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index 5b44a77..08a10dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -14,7 +14,8 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.DEFAULT_ICON_TINT;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
 
 import android.animation.ArgbEvaluator;
 import android.content.Context;
@@ -24,7 +25,7 @@
 import android.widget.ImageView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -35,7 +36,7 @@
 /**
  */
 @Singleton
-public class DarkIconDispatcherImpl implements DarkIconDispatcher {
+public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher {
 
     private final LightBarTransitionsController mTransitionsController;
     private final Rect mTintArea = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 3425dd2..236c72c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -29,14 +29,14 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 import java.util.ArrayList;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 3c8cad7..d1e488a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -25,12 +25,12 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.util.function.BiConsumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 5ba59b5..03375d20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -45,13 +45,13 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 6632d58..b590ca7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -27,8 +27,8 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -44,7 +44,7 @@
 
     private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
 
-    private final DarkIconDispatcher mStatusBarIconController;
+    private final SysuiDarkIconDispatcher mStatusBarIconController;
     private final BatteryController mBatteryController;
     private BiometricUnlockController mBiometricUnlockController;
 
@@ -79,16 +79,13 @@
     private final Rect mLastDockedBounds = new Rect();
     private boolean mQsCustomizing;
 
-    private final Context mContext;
-
     @Inject
     public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher,
             BatteryController batteryController) {
         mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
-        mStatusBarIconController = darkIconDispatcher;
+        mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
         mBatteryController = batteryController;
         mBatteryController.addCallback(this);
-        mContext = ctx;
     }
 
     public void setNavigationBar(LightBarTransitionsController navigationBar) {
@@ -225,9 +222,8 @@
 
     private void updateNavigation() {
         if (mNavigationBarController != null) {
-            if (!NavBarTintController.isEnabled(mContext)) {
-                mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
-            }
+            mNavigationBarController.setIconsDark(
+                    mNavigationLight, animateChange());
         }
     }
 
@@ -268,10 +264,6 @@
 
         pw.println();
 
-        if (mStatusBarIconController != null) {
-            mStatusBarIconController.dump(fd, pw, args);
-        }
-
         LightBarTransitionsController transitionsController =
                 mStatusBarIconController.getTransitionsController();
         if (transitionsController != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 2daff2c..270565b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -16,14 +16,19 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
 
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
 import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
 
@@ -55,6 +60,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
+import android.view.IWindowManager;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -63,6 +69,7 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -72,6 +79,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistManager;
@@ -83,6 +91,8 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -111,6 +121,7 @@
 
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
+    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
 
     private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     protected final AssistManager mAssistManager;
@@ -122,10 +133,11 @@
     private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
     private int mNavigationIconHints = 0;
-    private int mNavigationBarMode;
+    private @TransitionMode int mNavigationBarMode;
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
+    private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
@@ -144,9 +156,15 @@
 
     private OverviewProxyService mOverviewProxyService;
 
-    private boolean mIsOnDefaultDisplay = true;
+    private int mDisplayId;
+    private boolean mIsOnDefaultDisplay;
     public boolean mHomeBlockedThisTouch;
 
+    private Handler mHandler = Dependency.get(Dependency.MAIN_HANDLER);
+
+    // last value sent to window manager
+    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
+
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
@@ -183,14 +201,20 @@
         }
     };
 
-    private final ContextButtonListener mRotationButtonListener = new ContextButtonListener() {
-        @Override
-        public void onVisibilityChanged(ContextualButton button, boolean visible) {
-            if (visible) {
-                // If the button will actually become visible and the navbar is about to hide,
-                // tell the statusbar to keep it around for longer
-                mStatusBar.touchAutoHide();
-            }
+    private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
+        if (visible) {
+            // If the button will actually become visible and the navbar is about to hide,
+            // tell the statusbar to keep it around for longer
+            touchAutoHide();
+        }
+    };
+
+    private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
+
+    private final Runnable mAutoHide = () -> {
+        int requested = mSystemUiVisibility & ~View.NAVIGATION_BAR_TRANSIENT;
+        if (mSystemUiVisibility != requested) {
+            notifySystemUiVisibilityChanged(requested);
         }
     };
 
@@ -251,7 +275,8 @@
         final Display display = view.getDisplay();
         // It may not have display when running unit test.
         if (display != null) {
-            mIsOnDefaultDisplay = display.getDisplayId() == Display.DEFAULT_DISPLAY;
+            mDisplayId = display.getDisplayId();
+            mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         }
 
         mNavigationBarView.setComponents(mStatusBar.getPanel());
@@ -381,7 +406,7 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setNavigationIconHints(hints);
         }
-        mStatusBar.checkBarModes();
+        checkBarModes();
     }
 
     @Override
@@ -426,23 +451,22 @@
                 .onRotationProposal(rotation, winRotation, isValid);
     }
 
-    // Injected from StatusBar at creation.
-    public void setCurrentSysuiVisibility(int systemUiVisibility) {
+    /**
+     * Sets System UI flags to {@link NavigationBarFragment}.
+     *
+     * @see View#setSystemUiVisibility(int)
+     */
+    public void setSystemUiVisibility(int systemUiVisibility) {
         mSystemUiVisibility = systemUiVisibility;
-        final int barMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
-                View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
-                View.NAVIGATION_BAR_TRANSPARENT);
+        final int barMode = computeBarMode(0, mSystemUiVisibility);
         if (barMode != -1) {
             mNavigationBarMode = barMode;
         }
         checkNavBarModes();
-        mStatusBar.touchAutoHide();
+        touchAutoHide();
 
-        // TODO(115978725): Support light bar controller on external nav bars.
-        if (mLightBarController != null) {
-            mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
+        mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
                     true /* nbModeChanged */, mNavigationBarMode);
-        }
     }
 
     @Override
@@ -457,9 +481,7 @@
 
             // update navigation bar mode
             final int nbMode = getView() == null
-                    ? -1 : mStatusBar.computeBarMode(oldVal, newVal,
-                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
-                    View.NAVIGATION_BAR_TRANSPARENT);
+                    ? -1 : computeBarMode(oldVal, newVal);
             nbModeChanged = nbMode != -1;
             if (nbModeChanged) {
                 if (mNavigationBarMode != nbMode) {
@@ -470,14 +492,46 @@
                     mNavigationBarMode = nbMode;
                     checkNavBarModes();
                 }
-                mStatusBar.touchAutoHide();
+                touchAutoHide();
+            }
+            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+            }
+
+
+            // On the default display, just make StatusBar do this job.
+            if (!mIsOnDefaultDisplay) {
+                notifySystemUiVisibilityChanged(mSystemUiVisibility);
             }
         }
+        mLightBarController.onNavigationVisibilityChanged(
+                vis, mask, nbModeChanged, mNavigationBarMode);
+    }
 
-        // TODO(115978725): Support light bar controller on external nav bars.
-        if (mLightBarController != null) {
-            mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
-                    mNavigationBarMode);
+    private @TransitionMode int computeBarMode(int oldVis, int newVis) {
+        final int oldMode = barMode(oldVis);
+        final int newMode = barMode(newVis);
+        if (oldMode == newMode) {
+            return -1; // no mode change
+        }
+        return newMode;
+    }
+
+    private @TransitionMode int barMode(int vis) {
+        final int lightsOutTransparent =
+                View.SYSTEM_UI_FLAG_LOW_PROFILE | View.NAVIGATION_BAR_TRANSIENT;
+        if ((vis & View.NAVIGATION_BAR_TRANSIENT) != 0) {
+            return MODE_SEMI_TRANSPARENT;
+        } else if ((vis & View.NAVIGATION_BAR_TRANSLUCENT) != 0) {
+            return MODE_TRANSLUCENT;
+        } else if ((vis & lightsOutTransparent) == lightsOutTransparent) {
+            return MODE_LIGHTS_OUT_TRANSPARENT;
+        } else if ((vis & View.NAVIGATION_BAR_TRANSPARENT) != 0) {
+            return MODE_TRANSPARENT;
+        } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+            return MODE_LIGHTS_OUT;
+        } else {
+            return MODE_OPAQUE;
         }
     }
 
@@ -511,7 +565,7 @@
         }
     }
 
-    // ----- Internal stuffz -----
+    // ----- Internal stuff -----
 
     private void refreshLayout(int layoutDirection) {
         if (mNavigationBarView != null) {
@@ -610,7 +664,7 @@
     }
 
     private boolean onNavigationTouch(View v, MotionEvent event) {
-        mStatusBar.checkUserAutohide(event);
+        checkUserAutoHide(event);
         return false;
     }
 
@@ -800,7 +854,79 @@
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
     }
 
-    // ----- Methods that StatusBar talks to (should be minimized) -----
+    private void touchAutoHide() {
+        // There is status bar on default display. Thus the hide animations should apply on both
+        // status/navigation bar.
+        if (mIsOnDefaultDisplay) {
+            mStatusBar.touchAutoHide();
+        } else {
+            touchAutoHideInternal();
+        }
+    }
+
+    private void touchAutoHideInternal() {
+        // update transient bar autoHide.
+        if (isSemiTransparent()) {
+            scheduleAutoHide();
+        } else {
+            cancelAutoHide();
+        }
+    }
+
+    private void checkUserAutoHide(MotionEvent event) {
+        // There is status bar on default display. Thus the hide animations should apply on both
+        // status/navigation bar.
+        if (mIsOnDefaultDisplay) {
+            mStatusBar.checkUserAutoHide(event);
+        } else {
+            checkUserAutoHideInternal(event);
+        }
+    }
+
+    private void checkUserAutoHideInternal(MotionEvent event) {
+        if ((mSystemUiVisibility & View.NAVIGATION_BAR_TRANSIENT) != 0
+                // a transient bar is revealed
+                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
+                && event.getX() == 0 && event.getY() == 0) { // a touch outside both bars.
+            userAutoHide();
+        }
+    }
+
+    private void userAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear.
+    }
+
+    private void cancelAutoHide() {
+        mHandler.removeCallbacks(mAutoHide);
+    }
+
+    private void scheduleAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
+    }
+
+    private void notifySystemUiVisibilityChanged(int vis) {
+        try {
+            if (mLastDispatchedSystemUiVisibility != vis) {
+                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
+                mLastDispatchedSystemUiVisibility = vis;
+            }
+        } catch (RemoteException ex) {
+        }
+    }
+
+    // ----- Methods that DisplayNavigationBarController talks to -----
+
+    /** Applys auto dimming animation on navigation bar when touched. */
+    public void touchAutoDim() {
+        getBarTransitions().setAutoDim(false);
+        mHandler.removeCallbacks(mAutoDim);
+        int state = Dependency.get(StatusBarStateController.class).getState();
+        if (state != StatusBarState.KEYGUARD && state != StatusBarState.SHADE_LOCKED) {
+            mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
+        }
+    }
 
     public void setLightBarController(LightBarController lightBarController) {
         mLightBarController = lightBarController;
@@ -811,19 +937,42 @@
         return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
     }
 
+    private void checkBarModes() {
+        // We only have status bar on default display now.
+        if (mIsOnDefaultDisplay) {
+            mStatusBar.checkBarModes();
+        } else {
+            checkNavBarModes();
+        }
+    }
+
+    /**
+     * Checks current navigation bar mode and make transitions.
+     */
+    public void checkNavBarModes() {
+        final boolean anim = mStatusBar.isDeviceInteractive()
+                && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
+        mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
+    }
+
     public void disableAnimationsDuringHide(long delay) {
         mNavigationBarView.setLayoutTransitionsEnabled(false);
         mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
                 delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
     }
 
-    public BarTransitions getBarTransitions() {
-        return mNavigationBarView.getBarTransitions();
+    /**
+     * Performs transitions on navigation bar.
+     *
+     * @param barMode transition bar mode.
+     * @param animate shows animations if {@code true}.
+     */
+    public void transitionTo(@TransitionMode int barMode, boolean animate) {
+        getBarTransitions().transitionTo(barMode, animate);
     }
 
-    public void checkNavBarModes() {
-        mStatusBar.checkBarMode(mNavigationBarMode,
-                mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
+    private BarTransitions getBarTransitions() {
+        return mNavigationBarView.getBarTransitions();
     }
 
     public void finishBarAnimations() {
@@ -873,12 +1022,11 @@
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
                 updateAccessibilityServicesState(mAccessibilityManager);
-            };
+            }
         }
     };
 
     public static View create(Context context, FragmentListener listener) {
-        final int displayId = context.getDisplay().getDisplayId();
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
@@ -890,7 +1038,7 @@
                         | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         lp.token = new Binder();
-        lp.setTitle("NavigationBar" + displayId);
+        lp.setTitle("NavigationBar" + context.getDisplayId());
         lp.accessibilityTitle = context.getString(R.string.nav_bar);
         lp.windowAnimations = 0;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8c17922..2fc7b78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -282,6 +282,11 @@
         }
 
         @Override
+        public void onHomeButtonVisibilityChanged(boolean visible) {
+            getHomeButton().setVisibility(visible ? VISIBLE : GONE);
+        }
+
+        @Override
         public void onColorAdaptChanged(boolean enabled) {
             if (enabled) {
                 mColorAdaptionController.start();
@@ -672,6 +677,7 @@
         // TODO(b/113914868): investigation log for disappearing home button
         Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
                 + " mDisabledFlags=" + mDisabledFlags);
+        disableHome |= mPrototypeController.hideHomeButton();
 
         // Always disable recents when alternate car mode UI is active and for secondary displays.
         boolean disableRecent = isRecentsButtonDisabled();
@@ -945,6 +951,7 @@
 
             // TODO(b/112934365): remove after prototype finished, only needed to escape from pin
             getBackButton().setVisibility(VISIBLE);
+            getHomeButton().setVisibility(VISIBLE);
         } else {
             mScreenPinningNotify.showPinningExitToast();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index 40ac793..fb6254b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -34,6 +34,7 @@
  */
 public class NavigationPrototypeController extends ContentObserver {
     private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
+    private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
 
     static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
     private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
@@ -73,6 +74,7 @@
      */
     public void register() {
         registerObserver(HIDE_BACK_BUTTON_SETTING);
+        registerObserver(HIDE_HOME_BUTTON_SETTING);
         registerObserver(GESTURE_MATCH_SETTING);
         registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
     }
@@ -88,22 +90,20 @@
     public void onChange(boolean selfChange, Uri uri) {
         super.onChange(selfChange, uri);
         if (!selfChange && mListener != null) {
-            try {
-                final String path = uri.getPath();
-                if (path.endsWith(GESTURE_MATCH_SETTING)) {
-                    // Get the settings gesture map corresponding to each action
-                    // {@see updateSwipeLTRBackSetting}
-                    updateSwipeLTRBackSetting();
-                    mListener.onGestureRemap(mActionMap);
-                } else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
-                    mListener.onBackButtonVisibilityChanged(
-                            !getGlobalBool(HIDE_BACK_BUTTON_SETTING));
-                } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
-                    mListener.onColorAdaptChanged(
-                            NavBarTintController.isEnabled(mContext));
-                }
-            } catch (SettingNotFoundException e) {
-                e.printStackTrace();
+            final String path = uri.getPath();
+            if (path.endsWith(GESTURE_MATCH_SETTING)) {
+                // Get the settings gesture map corresponding to each action
+                // {@see updateSwipeLTRBackSetting}
+                updateSwipeLTRBackSetting();
+                mListener.onGestureRemap(mActionMap);
+            } else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
+                mListener.onBackButtonVisibilityChanged(
+                        !getGlobalBool(HIDE_BACK_BUTTON_SETTING, false));
+            } else if (path.endsWith(HIDE_HOME_BUTTON_SETTING)) {
+                mListener.onHomeButtonVisibilityChanged(!hideHomeButton());
+            } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
+                mListener.onColorAdaptChanged(
+                        NavBarTintController.isEnabled(mContext));
             }
         }
     }
@@ -117,6 +117,13 @@
     }
 
     /**
+     * @return if home button should be invisible
+     */
+    boolean hideHomeButton() {
+        return getGlobalBool(HIDE_HOME_BUTTON_SETTING, false /* default */);
+    }
+
+    /**
      * Since Settings.Global cannot pass arrays, use a string to represent each character as a
      * gesture map to actions corresponding to {@see GestureAction}. The number is represented as:
      * Number: [up] [down] [left] [right]
@@ -131,8 +138,8 @@
         }
     }
 
-    private boolean getGlobalBool(String name) throws SettingNotFoundException {
-        return Settings.Global.getInt(mContext.getContentResolver(), name) == 1;
+    private boolean getGlobalBool(String name, boolean defaultVal) {
+        return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
     }
 
     private void registerObserver(String name) {
@@ -143,6 +150,7 @@
     public interface OnPrototypeChangedListener {
         void onGestureRemap(@GestureAction int[] actions);
         void onBackButtonVisibilityChanged(boolean visible);
+        void onHomeButtonVisibilityChanged(boolean visible);
         void onColorAdaptChanged(boolean enabled);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 9fe30db..3839ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
@@ -218,7 +219,7 @@
 
         @Override
         public void onEntryRemoved(
-                Entry entry,
+                @Nullable Entry entry,
                 String key,
                 StatusBarNotification old,
                 NotificationVisibility visibility,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e40835f..056c8a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -19,14 +19,14 @@
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.tuner.TunerService;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 2129835..7a3d03f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -43,9 +43,9 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
 import java.util.Objects;
 
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 e1a6cd3..9f0eec4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -37,6 +37,7 @@
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -71,7 +72,6 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
 import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
@@ -155,6 +155,8 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.qs.QSFragment;
@@ -168,11 +170,11 @@
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.DisplayNavigationBarController;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -204,7 +206,6 @@
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
@@ -446,18 +447,18 @@
     protected final H mHandler = createHandler();
 
     private int mInteractingWindows;
-    private boolean mAutohideSuspended;
-    private int mStatusBarMode;
+    private boolean mAutoHideSuspended;
+    private @TransitionMode int mStatusBarMode;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
     protected ScrimController mScrimController;
     protected DozeScrimController mDozeScrimController;
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
-    private final Runnable mAutohide = () -> {
+    private final Runnable mAutoHide = () -> {
         int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
         if (mSystemUiVisibility != requested) {
-            notifyUiVisibilityChanged(requested);
+            notifySystemUiVisibilityChanged(requested);
         }
     };
 
@@ -584,11 +585,6 @@
                 }
             };
 
-    protected DisplayManager mDisplayManager;
-
-    private NavigationBarFragment mNavigationBar;
-    private View mNavigationBarView;
-
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private boolean mVibrateOnOpening;
     private VibratorHelper mVibratorHelper;
@@ -642,7 +638,7 @@
         mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
-        mNavigationBarController = Dependency.get(DisplayNavigationBarController.class);
+        mNavigationBarController = Dependency.get(NavigationBarController.class);
         mBubbleController = Dependency.get(BubbleController.class);
         mBubbleController.setExpandListener(mBubbleExpandListener);
         KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
@@ -808,6 +804,9 @@
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
 
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
+        // Allow plugins to reference DarkIconDispatcher
+        Dependency.get(PluginDependencyProvider.class)
+                .allowPluginDependency(DarkIconDispatcher.class);
         FragmentHostManager.get(mStatusBarWindow)
                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                     CollapsedStatusBarFragment statusBarFragment =
@@ -903,11 +902,7 @@
             }
         });
 
-        // TODO(115978725): Support light bar controller on external nav bars.
         mLightBarController = Dependency.get(LightBarController.class);
-        if (mNavigationBar != null) {
-            mNavigationBar.setLightBarController(mLightBarController);
-        }
 
         ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
         ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
@@ -1093,25 +1088,10 @@
         }
     }
 
+    // TODO(b/117478341): This was left such that CarStatusBar can override this method.
+    // Try to remove this.
     protected void createNavigationBar() {
-        try {
-            // TODO(117478341): Move this into DisplayNavigationBarController#createNavigationBars
-            // for-loop. We will also move the whole navigation bar logic together.
-            final boolean showNav = mWindowManagerService.hasNavigationBar(DEFAULT_DISPLAY);
-            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
-            if (!showNav) return;
-
-            mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
-                mNavigationBar = (NavigationBarFragment) fragment;
-                if (mLightBarController != null) {
-                    mNavigationBar.setLightBarController(mLightBarController);
-                }
-                mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
-            });
-        } catch (RemoteException ex) {
-            // no window manager? good luck with that
-        }
-        mNavigationBarController.createNavigationBars();
+        mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */);
     }
 
     /**
@@ -1120,7 +1100,7 @@
      */
     protected View.OnTouchListener getStatusBarWindowTouchListener() {
         return (v, event) -> {
-            checkUserAutohide(event);
+            checkUserAutoHide(event);
             mRemoteInputManager.checkRemoteInputOutside(event);
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                 if (mExpandedVisible) {
@@ -2101,7 +2081,7 @@
             }
 
             // send updated sysui visibility to window manager
-            notifyUiVisibilityChanged(mSystemUiVisibility);
+            notifySystemUiVisibilityChanged(mSystemUiVisibility);
         }
 
         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
@@ -2131,52 +2111,55 @@
         }
     }
 
-    // TODO(115978725): Support auto hide on external nav bars.
     void touchAutoHide() {
-        // update transient bar autohide
-        if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
-                && mNavigationBar.isSemiTransparent())) {
-            scheduleAutohide();
+        // update transient bar auto hide
+        if (mStatusBarMode == MODE_SEMI_TRANSPARENT
+                || mNavigationBarController.isSemiTransparent(DEFAULT_DISPLAY)) {
+            scheduleAutoHide();
         } else {
-            cancelAutohide();
+            cancelAutoHide();
         }
     }
 
-    protected int computeStatusBarMode(int oldVal, int newVal) {
-        return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
-                View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
+    protected @TransitionMode int computeStatusBarMode(int oldVal, int newVal) {
+        return computeBarMode(oldVal, newVal);
     }
 
     protected BarTransitions getStatusBarTransitions() {
         return mStatusBarView.getBarTransitions();
     }
 
-    protected int computeBarMode(int oldVis, int newVis,
-            int transientFlag, int translucentFlag, int transparentFlag) {
-        final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
-        final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
+    protected @TransitionMode int computeBarMode(int oldVis, int newVis) {
+        final int oldMode = barMode(oldVis);
+        final int newMode = barMode(newVis);
         if (oldMode == newMode) {
             return -1; // no mode change
         }
         return newMode;
     }
 
-    private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
-        int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
-        return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
-                : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
-                : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
-                : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
-                : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
-                : MODE_OPAQUE;
+    private @TransitionMode int barMode(int vis) {
+        int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.STATUS_BAR_TRANSPARENT;
+        if ((vis & View.STATUS_BAR_TRANSIENT) != 0) {
+            return MODE_SEMI_TRANSPARENT;
+        } else if ((vis & View.STATUS_BAR_TRANSLUCENT) != 0) {
+            return MODE_TRANSLUCENT;
+        } else if ((vis & lightsOutTransparent) == lightsOutTransparent) {
+            return MODE_LIGHTS_OUT_TRANSPARENT;
+        } else if ((vis & View.STATUS_BAR_TRANSPARENT) != 0) {
+            return MODE_TRANSPARENT;
+        } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+            return MODE_LIGHTS_OUT;
+        } else {
+            return MODE_OPAQUE;
+        }
     }
 
-    // TODO(115978725): Support animations on external nav bars.
     void checkBarModes() {
         if (mDemoMode) return;
         if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
                 getStatusBarTransitions());
-        if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
+        mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
         mNoAnimationOnNextBarModeChange = false;
     }
 
@@ -2185,20 +2168,17 @@
         mNotificationPanel.setQsScrimEnabled(scrimEnabled);
     }
 
-    void checkBarMode(int mode, int windowState, BarTransitions transitions) {
+    void checkBarMode(@TransitionMode int mode, int windowState, BarTransitions transitions) {
         final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
                 && windowState != WINDOW_STATE_HIDDEN;
         transitions.transitionTo(mode, anim);
     }
 
-    // TODO(115978725): Support animations on external nav bars.
     private void finishBarAnimations() {
         if (mStatusBarView != null) {
             mStatusBarView.getBarTransitions().finishAnimations();
         }
-        if (mNavigationBar != null) {
-            mNavigationBar.finishBarAnimations();
-        }
+        mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
     }
 
     private final Runnable mCheckBarModes = this::checkBarModes;
@@ -2209,13 +2189,13 @@
                 ? (mInteractingWindows | barWindow)
                 : (mInteractingWindows & ~barWindow);
         if (mInteractingWindows != 0) {
-            suspendAutohide();
+            suspendAutoHide();
         } else {
-            resumeSuspendedAutohide();
+            resumeSuspendedAutoHide();
         }
         // manually dismiss the volume panel when interacting with the nav bar
         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
-            touchAutoDim();
+            mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
             dismissVolumeDialog();
         }
         checkBarModes();
@@ -2227,57 +2207,42 @@
         }
     }
 
-    private void resumeSuspendedAutohide() {
-        if (mAutohideSuspended) {
-            scheduleAutohide();
+    private void resumeSuspendedAutoHide() {
+        if (mAutoHideSuspended) {
+            scheduleAutoHide();
             mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
         }
     }
 
-    private void suspendAutohide() {
-        mHandler.removeCallbacks(mAutohide);
+    private void suspendAutoHide() {
+        mHandler.removeCallbacks(mAutoHide);
         mHandler.removeCallbacks(mCheckBarModes);
-        mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
+        mAutoHideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
     }
 
-    private void cancelAutohide() {
-        mAutohideSuspended = false;
-        mHandler.removeCallbacks(mAutohide);
+    private void cancelAutoHide() {
+        mAutoHideSuspended = false;
+        mHandler.removeCallbacks(mAutoHide);
     }
 
-    private void scheduleAutohide() {
-        cancelAutohide();
-        mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
+    private void scheduleAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
     }
 
-    public void touchAutoDim() {
-        if (mNavigationBar != null) {
-            mNavigationBar.getBarTransitions().setAutoDim(false);
-        }
-        mHandler.removeCallbacks(mAutoDim);
-
-        // Do not dim the navigation buttons if the its tint is controlled by the bar's background
-        if (NavBarTintController.isEnabled(mContext)) {
-            return;
-        }
-        if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
-            mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
-        }
-    }
-
-    void checkUserAutohide(MotionEvent event) {
+    void checkUserAutoHide(MotionEvent event) {
         if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
                 && !mRemoteInputManager.getController()
                         .isRemoteInputActive()) { // not due to typing in IME
-            userAutohide();
+            userAutoHide();
         }
     }
 
-    private void userAutohide() {
-        cancelAutohide();
-        mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
+    private void userAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
     }
 
     private boolean areLightsOn() {
@@ -2296,11 +2261,10 @@
         }
     }
 
-    private void notifyUiVisibilityChanged(int vis) {
+    private void notifySystemUiVisibilityChanged(int vis) {
         try {
             if (mLastDispatchedSystemUiVisibility != vis) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                mWindowManagerService.statusBarVisibilityChanged(Display.DEFAULT_DISPLAY, vis);
+                mWindowManagerService.statusBarVisibilityChanged(DEFAULT_DISPLAY, vis);
                 mLastDispatchedSystemUiVisibility = vis;
             }
         } catch (RemoteException ex) {
@@ -2925,10 +2889,6 @@
             mWindowManager.removeViewImmediate(mStatusBarWindow);
             mStatusBarWindow = null;
         }
-        if (mNavigationBarView != null) {
-            mWindowManager.removeViewImmediate(mNavigationBarView);
-            mNavigationBarView = null;
-        }
         mNavigationBarController.destroy();
         mContext.unregisterReceiver(mBroadcastReceiver);
         mContext.unregisterReceiver(mDemoReceiver);
@@ -2998,15 +2958,12 @@
                     "transparent".equals(mode) ? MODE_TRANSPARENT :
                     "warning".equals(mode) ? MODE_WARNING :
                     -1;
-            // TODO(115978725): Support external nav bar transitions
             if (barMode != -1) {
                 boolean animate = true;
                 if (mStatusBarView != null) {
                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
                 }
-                if (mNavigationBar != null) {
-                    mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
-                }
+                mNavigationBarController.transitionTo(DEFAULT_DISPLAY, barMode, animate);
             }
         }
         if (modeChange || command.equals(COMMAND_OPERATOR)) {
@@ -3232,12 +3189,9 @@
                 mDraggedDownEntry = null;
             }
 
-            // TODO(115978725): Support animations on external nav bars.
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
-            if (mNavigationBar != null) {
-                mNavigationBar.disableAnimationsDuringHide(delay);
-            }
+            mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, delay);
         } else if (!mNotificationPanel.isCollapsing()) {
             instantCollapseNotificationPanel();
         }
@@ -3467,7 +3421,7 @@
         updateReportRejectedTouchVisibility();
         updateDozing();
         updateTheme();
-        touchAutoDim();
+        mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
         Trace.beginSection("StatusBar#updateKeyguardState");
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationController.setVisible(true);
@@ -3588,11 +3542,7 @@
 
     // TODO: Figure out way to remove these.
     public NavigationBarView getNavigationBarView() {
-        return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
-    }
-
-    public View getNavigationBarWindow() {
-        return mNavigationBarView;
+        return mNavigationBarController.getDefaultNavigationBarView();
     }
 
     /**
@@ -4174,7 +4124,7 @@
     private DeviceProvisionedController mDeviceProvisionedController
             = Dependency.get(DeviceProvisionedController.class);
 
-    protected DisplayNavigationBarController mNavigationBarController;
+    protected NavigationBarController mNavigationBarController;
 
     // UI-specific methods
 
@@ -4502,13 +4452,6 @@
     }
     // End Extra BaseStatusBarMethods.
 
-    // TODO(115978725): Handle dimming for external nav bars
-    private final Runnable mAutoDim = () -> {
-        if (mNavigationBar != null) {
-            mNavigationBar.getBarTransitions().setAutoDim(true);
-        }
-    };
-
     public NotificationGutsManager getGutsManager() {
         return mGutsManager;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 26c9d28..2e2ff1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -38,14 +38,14 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.util.Utils.DisableStateTracker;
 
 import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 7b6fef3..7b7bcb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
 import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
 
+import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -193,7 +194,7 @@
 
                 @Override
                 public void onEntryRemoved(
-                        Entry entry,
+                        @Nullable Entry entry,
                         String key,
                         StatusBarNotification old,
                         NotificationVisibility visibility,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
new file mode 100644
index 0000000..d537721
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
@@ -0,0 +1,32 @@
+/*
+ * 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.statusbar.phone;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.plugins.DarkIconDispatcher;
+
+/**
+ * Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area
+ * and dark intensity.
+ */
+public interface SysuiDarkIconDispatcher extends DarkIconDispatcher, Dumpable {
+
+    /**
+     * @return LightBarTransitionsController
+     */
+    LightBarTransitionsController getTransitionsController();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index aafdcd5..5eb3e89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -44,11 +44,12 @@
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
deleted file mode 100644
index 0823db9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area and dark
- * intensity
- */
-public interface DarkIconDispatcher extends Dumpable {
-
-    void setIconsDarkArea(Rect r);
-    LightBarTransitionsController getTransitionsController();
-
-    void addDarkReceiver(DarkReceiver receiver);
-    void addDarkReceiver(ImageView imageView);
-
-    // Must have been previously been added through one of the addDarkReceive methods above.
-    void removeDarkReceiver(DarkReceiver object);
-    void removeDarkReceiver(ImageView object);
-
-    // Used to reapply darkness on an object, must have previously been added through
-    // addDarkReceiver.
-    void applyDark(DarkReceiver object);
-
-    /**
-     * Dumpable interface
-     */
-    default void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
-
-    int DEFAULT_ICON_TINT = Color.WHITE;
-    Rect sTmpRect = new Rect();
-    int[] sTmpInt2 = new int[2];
-
-    /**
-     * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
-     *         the screen {@param tintArea} in which to apply that tint
-     */
-    static int getTint(Rect tintArea, View view, int color) {
-        if (isInArea(tintArea, view)) {
-            return color;
-        } else {
-            return DEFAULT_ICON_TINT;
-        }
-    }
-
-    /**
-     * @return the dark intensity to apply to {@param view} depending on the desired dark
-     *         {@param intensity} and the screen {@param tintArea} in which to apply that intensity
-     */
-    static float getDarkIntensity(Rect tintArea, View view, float intensity) {
-        if (isInArea(tintArea, view)) {
-            return intensity;
-        } else {
-            return 0f;
-        }
-    }
-
-    /**
-     * @return true if more than half of the {@param view} area are in {@param area}, false
-     *         otherwise
-     */
-    static boolean isInArea(Rect area, View view) {
-        if (area.isEmpty()) {
-            return true;
-        }
-        sTmpRect.set(area);
-        view.getLocationOnScreen(sTmpInt2);
-        int left = sTmpInt2[0];
-
-        int intersectStart = Math.max(left, area.left);
-        int intersectEnd = Math.min(left + view.getWidth(), area.right);
-        int intersectAmount = Math.max(0, intersectEnd - intersectStart);
-
-        boolean coversFullStatusBar = area.top <= 0;
-        boolean majorityOfWidth = 2 * intersectAmount > view.getWidth();
-        return majorityOfWidth && coversFullStatusBar;
-    }
-
-    interface DarkReceiver {
-        void onDarkChanged(Rect area, float darkIntensity, int tint);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 4a11754..54502e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -24,10 +24,10 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.phone.NavigationBarView;
-import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
  * The "dead zone" consumes unintentional taps along the top edge of the navigation bar.
@@ -44,7 +44,7 @@
     public static final int VERTICAL = 1;  // Consume taps along the left edge.
 
     private static final boolean CHATTY = true; // print to logcat when we eat a click
-    private final StatusBar mStatusBar;
+    private final NavigationBarController mNavBarController;
     private final NavigationBarView mNavigationBarView;
 
     private boolean mShouldFlash;
@@ -58,6 +58,7 @@
     private boolean mVertical;
     private long mLastPokeTime;
     private int mDisplayRotation;
+    private final int mDisplayId;
 
     private final Runnable mDebugFlash = new Runnable() {
         @Override
@@ -68,8 +69,8 @@
 
     public DeadZone(NavigationBarView view) {
         mNavigationBarView = view;
-        mStatusBar = SysUiServiceProvider.getComponent(mNavigationBarView.getContext(),
-                StatusBar.class);
+        mNavBarController = Dependency.get(NavigationBarController.class);
+        mDisplayId = view.getContext().getDisplayId();
         onConfigurationChanged(HORIZONTAL);
     }
 
@@ -133,7 +134,7 @@
             if (DEBUG) {
                 Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
             }
-            if (mStatusBar != null) mStatusBar.touchAutoDim();
+            mNavBarController.touchAutoDim(mDisplayId);
             int size = (int) getSize(event.getEventTime());
             // In the vertical orientation consume taps along the left edge.
             // In horizontal orientation consume taps along the top edge.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index b84f85b..122b094 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -16,13 +16,13 @@
 
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 
-import  static com.android.systemui.ScreenDecorations.rectsToRegion;
+import static com.android.systemui.ScreenDecorations.rectsToRegion;
 import static com.android.systemui.tuner.TunablePadding.FLAG_END;
 import static com.android.systemui.tuner.TunablePadding.FLAG_START;
 
 import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -87,7 +87,6 @@
         mWindowManager = mock(WindowManager.class);
         mView = spy(new StatusBarWindowView(mContext, null));
         when(mStatusBar.getStatusBarWindow()).thenReturn(mView);
-        when(mStatusBar.getNavigationBarWindow()).thenReturn(mView);
         mContext.putComponent(StatusBar.class, mStatusBar);
 
         Display display = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 9946317..926ff69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -17,7 +17,9 @@
 package com.android.systemui.doze;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -37,6 +39,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.doze.DozeMachine.State;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -66,6 +69,7 @@
         mMachine = mock(DozeMachine.class);
         mHost = spy(new DozeHostFake());
         mConfig = DozeConfigurationUtil.createMockConfig();
+        doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
 
         mDockManagerFake = spy(new DockManagerFake());
         mContext.putComponent(DockManager.class, mDockManagerFake);
@@ -75,7 +79,7 @@
     }
 
     @Test
-    public void testDockEventListener_registerAndUnregister() throws Exception {
+    public void testDockEventListener_registerAndUnregister() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
 
         verify(mDockManagerFake).addListener(any());
@@ -86,55 +90,115 @@
     }
 
     @Test
-    public void testOnEvent_dockingWhenDoze_requestPulse() throws Exception {
+    public void testOnEvent_dockedWhenDoze_requestPulse() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
 
         verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
     }
 
     @Test
-    public void testOnEvent_dockingWhenPausing_neverRequestPulse() throws Exception {
+    public void testOnEvent_dockedWhenDozeAoD_requestPulse() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD_PAUSING);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
 
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
 
-        verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
     }
 
     @Test
-    public void testOnEvent_undockedWhenPulsing_requestPulseOut() throws Exception {
+    public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
+        when(mMachine.getState()).thenReturn(State.DOZE_PULSING);
         when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
 
-        mDockManagerFake.setDockEvent(DockManager.STATE_UNDOCKING);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
 
         verify(mHost).stopPulsing();
     }
 
     @Test
-    public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() throws Exception {
+    public void testOnEvent_undockedWhenPulsing_requestPulseOut() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
+        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+
+        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
+
+        verify(mHost).stopPulsing();
+    }
+
+    @Test
+    public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
-        mDockManagerFake.setDockEvent(DockManager.STATE_UNDOCKING);
+        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
 
         verify(mHost, never()).stopPulsing();
     }
 
     @Test
-    public void testTransitionToDozeWhenDocking_RequestPulse() throws Exception {
+    public void testOnEvent_undockedWhenDozeAndEnabledAoD_requestDozeAoD() {
+        doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
-        mDockHandler.transitionTo(DozeMachine.State.DOZE_AOD_PAUSING, DozeMachine.State.DOZE);
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
+        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
+
+        verify(mMachine).requestState(eq(State.DOZE_AOD));
+    }
+
+    @Test
+    public void testTransitionToDoze_whenDocked_requestPulse() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+        mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE);
+
         TestableLooper.get(this).processAllMessages();
 
         verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
     }
+
+    @Test
+    public void testTransitionToDozeAoD_whenDocked_requestPulse() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
+        mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE_AOD);
+
+        TestableLooper.get(this).processAllMessages();
+
+        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+    }
+
+    @Test
+    public void testTransitionToDoze_whenDockedHide_neverRequestPulse() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+
+        verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+    }
+
+    @Test
+    public void testTransitionToDozeAoD_whenDockedHide_requestDoze() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
+
+        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_AOD);
+
+        verify(mMachine).requestState(eq(State.DOZE));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index d28f017..ecb0cf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -32,6 +32,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -44,6 +45,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.INotificationManager;
@@ -54,6 +56,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -69,6 +72,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -79,6 +83,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -177,6 +182,29 @@
                 () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
     }
 
+    class ImportanceChangeLogMaker implements ArgumentMatcher<LogMaker> {
+        private static final int CATEGORY = MetricsProto.MetricsEvent.ACTION_SAVE_IMPORTANCE;
+        private int mType, mSubtype;
+
+        ImportanceChangeLogMaker(int type, int subtype) {
+            mType = type;
+            mSubtype = subtype;
+        }
+        public boolean matches(LogMaker l) {
+            return (l.getCategory() == CATEGORY)
+                    && (l.getType() == mType)
+                    && (l.getSubtype() == mSubtype);
+        }
+
+        public String toString() {
+            return String.format("LogMaker(%d, %d, %d)", CATEGORY, mType, mSubtype);
+        }
+    }
+
+    private LogMaker importanceChangeLog(int type, int subtype) {
+        return argThat(new ImportanceChangeLogMaker(type, subtype));
+    }
+
     @Test
     public void testBindNotification_SetsTextApplicationName() throws Exception {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -475,7 +503,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
+        verifyZeroInteractions(mMetricsLogger);
     }
 
     @Test
@@ -484,7 +512,7 @@
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
                 true, true, IMPORTANCE_DEFAULT);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verify(mMetricsLogger, times(1)).count(anyString(), anyInt());
+        verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
     }
 
     @Test
@@ -827,6 +855,9 @@
         waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
+        verify(mMetricsLogger).write(importanceChangeLog(
+                MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW));
+
         mTestableLooper.processAllMessages();
         ArgumentCaptor<NotificationChannel> updated =
                 ArgumentCaptor.forClass(NotificationChannel.class);
@@ -860,6 +891,9 @@
         waitForUndoButton();
         mNotificationInfo.handleCloseControls(true, false);
 
+        verify(mMetricsLogger).write(importanceChangeLog(
+                MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW));
+
         mTestableLooper.processAllMessages();
         ArgumentCaptor<NotificationChannel> updated =
                 ArgumentCaptor.forClass(NotificationChannel.class);
@@ -936,15 +970,14 @@
         waitForUndoButton();
         mNotificationInfo.findViewById(R.id.undo).performClick();
         waitForStopButton();
-        mNotificationInfo.handleCloseControls(true, false);
+        // mNotificationInfo.handleCloseControls doesn't get called by this interaction.
+
+        verify(mMetricsLogger).write(importanceChangeLog(
+                MetricsProto.MetricsEvent.TYPE_DISMISS, IMPORTANCE_NONE - IMPORTANCE_LOW));
 
         mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+        verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), any());
     }
 
     @Test
@@ -958,15 +991,11 @@
         waitForUndoButton();
         mNotificationInfo.findViewById(R.id.undo).performClick();
         waitForStopButton();
-        mNotificationInfo.handleCloseControls(true, false);
+        // mNotificationInfo.handleCloseControls doesn't get called by this code path
 
         mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+        verify(mMockINotificationManager, times(0)).updateNotificationChannelForPackage(
+                anyString(), eq(TEST_UID), any());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 4f6329c..38d9ae7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -30,11 +30,11 @@
 import android.widget.TextView;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
index 76f57f0..40d5415 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
@@ -67,5 +67,4 @@
 
         assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT));
     }
-
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 72b0156..4f95bc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -14,17 +14,14 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 
-import android.graphics.Rect;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -32,15 +29,15 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
+import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e80694c..18ead90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -82,6 +82,7 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -196,6 +197,7 @@
                         mDreamManager);
         mDependency.injectTestDependency(NotificationInterruptionStateProvider.class,
                 mNotificationInterruptionStateProvider);
+        mDependency.injectMockDependency(NavigationBarController.class);
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -245,7 +247,7 @@
                 mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class),
                 mDozeScrimController, mock(NotificationShelf.class),
                 mLockscreenUserManager, mCommandQueue, mNotificationPresenter,
-                mock(BubbleController.class));
+                mock(BubbleController.class), mock(NavigationBarController.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         SystemUIFactory.getInstance().getRootComponent()
@@ -695,7 +697,8 @@
                 NotificationLockscreenUserManager notificationLockscreenUserManager,
                 CommandQueue commandQueue,
                 NotificationPresenter notificationPresenter,
-                BubbleController bubbleController) {
+                BubbleController bubbleController,
+                NavigationBarController navBarController) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -726,6 +729,7 @@
             mPresenter = notificationPresenter;
             mGestureWakeLock = mock(PowerManager.WakeLock.class);
             mBubbleController = bubbleController;
+            mNavigationBarController = navBarController;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml b/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
index f024615..138c283 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
-    <string name="config_icon_mask" translatable="false">"M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58, 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"</string>
+    <string name="config_icon_mask" translatable="false">"M50,0L88,0 C94.4,0 100,5.4 100 12 L100,88 C100,94.6 94.6 100 88 100 L12,100 C5.4,100 0,94.6 0,88 L0 12 C0 5.4 5.4 0 12 0 L50,0 Z"</string>
     <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
     <bool name="config_useRoundIcon">false</bool>
 
diff --git a/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml b/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
index 43ad04d..818e696 100644
--- a/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
-    <string name="config_icon_mask" translatable="false">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</string>
+    <string name="config_icon_mask" translatable="false">"M50,0 C77.6,0 100,22.4 100,50 L100,88 C100,94.6 94.6,100 88,100 L50,100 C22.4 100 0 77.6 0 50C0 22.4 22.4 0 50 0 Z"</string>
     <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
     <bool name="config_useRoundIcon">false</bool>
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0e9b407..0348f2b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -64,9 +64,11 @@
 import android.os.SystemClock;
 import android.service.autofill.AutofillFieldClassificationService.Scores;
 import android.service.autofill.AutofillService;
+import android.service.autofill.CompositeUserData;
 import android.service.autofill.Dataset;
 import android.service.autofill.FieldClassification;
 import android.service.autofill.FieldClassification.Match;
+import android.service.autofill.FieldClassificationUserData;
 import android.service.autofill.FillContext;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
@@ -1237,11 +1239,16 @@
             return;
         }
 
+        // Merge UserData if necessary.
+        // Fields in packageUserData will override corresponding fields in genericUserData.
+        final UserData genericUserData = mService.getUserData();
         final UserData packageUserData = lastResponse.getUserData();
-
-        final UserData userData;
-        if (packageUserData != null) {
-            // Replace default userData
+        final FieldClassificationUserData userData;
+        if (packageUserData == null && genericUserData == null) {
+            userData = null;
+        } else if (packageUserData != null && genericUserData != null) {
+            userData = new CompositeUserData(genericUserData, packageUserData);
+        } else if (packageUserData != null) {
             userData = packageUserData;
         } else {
             userData = mService.getUserData();
@@ -1396,7 +1403,8 @@
             @NonNull ArrayList<String> changedDatasetIds,
             @NonNull ArrayList<AutofillId> manuallyFilledFieldIds,
             @NonNull ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @NonNull UserData userData, @NonNull Collection<ViewState> viewStates) {
+            @NonNull FieldClassificationUserData userData,
+            @NonNull Collection<ViewState> viewStates) {
 
         final String[] userValues = userData.getValues();
         final String[] categoryIds = userData.getCategoryIds();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 7049744..8b07db7 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -36,7 +36,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.Environment;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -50,11 +49,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 
-import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.Set;
@@ -72,10 +67,6 @@
     public static final boolean MORE_DEBUG = false;
     public static final boolean DEBUG_SCHEDULING = true;
 
-    // File containing backup-enabled state. Contains a single byte to denote enabled status.
-    // Nonzero is enabled; file missing or a zero byte is disabled.
-    private static final String BACKUP_ENABLE_FILE = "backup_enabled";
-
     // The published binder is a singleton Trampoline object that calls through to the proper code.
     // This indirection lets us turn down the heavy implementation object on the fly without
     // disturbing binders that have been cached elsewhere in the system.
@@ -150,7 +141,8 @@
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
         try {
             // TODO(b/121198604): Make enable file per-user and clean up indirection.
-            mTrampoline.setBackupEnabledForUser(userId, readBackupEnableState(userId));
+            mTrampoline.setBackupEnabledForUser(
+                    userId, UserBackupManagerFilePersistedSettings.readBackupEnableState(userId));
         } catch (RemoteException e) {
             // Can't happen, it's a local object.
         }
@@ -773,44 +765,6 @@
         }
     }
 
-    private static boolean readBackupEnableState(int userId) {
-        File base = new File(Environment.getDataDirectory(), "backup");
-        File enableFile = new File(base, BACKUP_ENABLE_FILE);
-        if (enableFile.exists()) {
-            try (FileInputStream fin = new FileInputStream(enableFile)) {
-                int state = fin.read();
-                return state != 0;
-            } catch (IOException e) {
-                // can't read the file; fall through to assume disabled
-                Slog.e(TAG, "Cannot read enable state; assuming disabled");
-            }
-        } else {
-            if (DEBUG) {
-                Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
-            }
-        }
-        return false;
-    }
-
-    static void writeBackupEnableState(boolean enable, int userId) {
-        File base = new File(Environment.getDataDirectory(), "backup");
-        File enableFile = new File(base, BACKUP_ENABLE_FILE);
-        File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
-        try (FileOutputStream fout = new FileOutputStream(stage)) {
-            fout.write(enable ? 1 : 0);
-            fout.close();
-            stage.renameTo(enableFile);
-            // will be synced immediately by the try-with-resources call to close()
-        } catch (IOException | RuntimeException e) {
-            Slog.e(
-                    TAG,
-                    "Unable to record backup enable state; reverting to disabled: "
-                            + e.getMessage());
-            enableFile.delete();
-            stage.delete();
-        }
-    }
-
     /** Implementation to receive lifecycle event callbacks for system services. */
     public static final class Lifecycle extends SystemService {
         public Lifecycle(Context context) {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java
new file mode 100644
index 0000000..6a1de63
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import static com.android.server.backup.BackupManagerService.DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/** User settings which are persisted across reboots. */
+final class UserBackupManagerFilePersistedSettings {
+    // File containing backup-enabled state. Contains a single byte to denote enabled status.
+    // Nonzero is enabled; file missing or a zero byte is disabled.
+    private static final String BACKUP_ENABLE_FILE = "backup_enabled";
+
+    static boolean readBackupEnableState(int userId) {
+        return readBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId));
+    }
+
+    static void writeBackupEnableState(int userId, boolean enable) {
+        writeBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId), enable);
+    }
+
+    private static boolean readBackupEnableState(File baseDir) {
+        File enableFile = new File(baseDir, BACKUP_ENABLE_FILE);
+        if (enableFile.exists()) {
+            try (FileInputStream fin = new FileInputStream(enableFile)) {
+                int state = fin.read();
+                return state != 0;
+            } catch (IOException e) {
+                // can't read the file; fall through to assume disabled
+                Slog.e(TAG, "Cannot read enable state; assuming disabled");
+            }
+        } else {
+            if (DEBUG) {
+                Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
+            }
+        }
+        return false;
+    }
+
+    private static void writeBackupEnableState(File baseDir, boolean enable) {
+        File enableFile = new File(baseDir, BACKUP_ENABLE_FILE);
+        File stage = new File(baseDir, BACKUP_ENABLE_FILE + "-stage");
+        try (FileOutputStream fout = new FileOutputStream(stage)) {
+            fout.write(enable ? 1 : 0);
+            fout.close();
+            stage.renameTo(enableFile);
+            // will be synced immediately by the try-with-resources call to close()
+        } catch (IOException | RuntimeException e) {
+            Slog.e(
+                    TAG,
+                    "Unable to record backup enable state; reverting to disabled: "
+                            + e.getMessage());
+            enableFile.delete();
+            stage.delete();
+        }
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
new file mode 100644
index 0000000..a0feaf9
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import android.os.Environment;
+
+import java.io.File;
+
+/** Directories used for user specific backup/restore persistent state and book-keeping. */
+public final class UserBackupManagerFiles {
+    // Name of the directories the service stores bookkeeping data under.
+    private static final String BACKUP_PERSISTENT_DIR = "backup";
+    private static final String BACKUP_STAGING_DIR = "backup_stage";
+
+    static File getBaseStateDir(int userId) {
+        // TODO (b/120424138) this should be per user
+        return new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+    }
+
+    static File getDataDir(int userId) {
+        // TODO (b/120424138) this should be per user
+        // This dir on /cache is managed directly in init.rc
+        return new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
+    }
+
+    /** Directory used by full backup engine to store state. */
+    public static File getFullBackupEngineFilesDir(int userId) {
+        // TODO (b/120424138) this should be per user
+        return new File("/data/system");
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2e41443..6425508 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -70,7 +70,6 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -164,17 +163,9 @@
 
 /** System service that performs backup/restore operations. */
 public class UserBackupManagerService {
-    // File containing backup-enabled state.  Contains a single byte;
-    // nonzero == enabled.  File missing or contains a zero byte == disabled.
-    private static final String BACKUP_ENABLE_FILE = "backup_enabled";
-
     // Persistently track the need to do a full init.
     private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
 
-    // Name of the directories the service stores bookkeeping data under.
-    private static final String BACKUP_PERSISTENT_DIR = "backup";
-    private static final String BACKUP_STAGING_DIR = "backup_stage";
-
     // System-private key used for backing up an app's widget state.  Must
     // begin with U+FFxx by convention (we reserve all keys starting
     // with U+FF00 or higher for system use).
@@ -354,9 +345,9 @@
     final AtomicInteger mNextToken = new AtomicInteger();
 
     // Where we keep our journal files and other bookkeeping.
-    private File mBaseStateDir;
-    private File mDataDir;
-    private File mJournalDir;
+    private final File mBaseStateDir;
+    private final File mDataDir;
+    private final File mJournalDir;
     @Nullable
     private DataChangedJournal mJournal;
     private File mFullBackupScheduleFile;
@@ -395,10 +386,8 @@
         TransportManager transportManager =
                 new TransportManager(context, transportWhitelist, currentTransport);
 
-        File baseStateDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
-
-        // This dir on /cache is managed directly in init.rc
-        File dataDir = new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
+        File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId);
+        File dataDir = UserBackupManagerFiles.getDataDir(userId);
 
         return createAndInitializeService(
                 userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
@@ -726,18 +715,10 @@
         return mBaseStateDir;
     }
 
-    public void setBaseStateDir(File baseStateDir) {
-        mBaseStateDir = baseStateDir;
-    }
-
     public File getDataDir() {
         return mDataDir;
     }
 
-    public void setDataDir(File dataDir) {
-        mDataDir = dataDir;
-    }
-
     @Nullable
     public DataChangedJournal getJournal() {
         return mJournal;
@@ -2735,8 +2716,7 @@
         try {
             boolean wasEnabled = mEnabled;
             synchronized (this) {
-                // TODO(b/118520567): Clean up writing backup enabled logic.
-                BackupManagerService.writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
+                UserBackupManagerFilePersistedSettings.writeBackupEnableState(mUserId, enable);
                 mEnabled = enable;
             }
 
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 5e92339..45ca2af 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -24,6 +24,7 @@
 import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 
+import android.annotation.UserIdInt;
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
 import android.app.backup.BackupTransport;
@@ -40,6 +41,7 @@
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.UserBackupManagerFiles;
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.remote.RemoteCall;
 import com.android.server.backup.utils.FullBackupUtils;
@@ -66,6 +68,7 @@
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     class FullBackupRunner implements Runnable {
+        private final @UserIdInt int mUserId;
         private final PackageManager mPackageManager;
         private final PackageInfo mPackage;
         private final IBackupAgent mAgent;
@@ -81,13 +84,15 @@
                 int token,
                 boolean includeApks)
                 throws IOException {
+            // TODO: http://b/22388012
+            mUserId = UserHandle.USER_SYSTEM;
             mPackageManager = backupManagerService.getPackageManager();
             mPackage = packageInfo;
             mAgent = agent;
             mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
             mToken = token;
             mIncludeApks = includeApks;
-            mFilesDir = new File("/data/system");
+            mFilesDir = UserBackupManagerFiles.getFullBackupEngineFilesDir(mUserId);
         }
 
         @Override
@@ -114,10 +119,8 @@
                     manifestFile.delete();
 
                     // Write widget data.
-                    // TODO: http://b/22388012
                     byte[] widgetData =
-                            AppWidgetBackupBridge.getWidgetState(
-                                    packageName, UserHandle.USER_SYSTEM);
+                            AppWidgetBackupBridge.getWidgetState(packageName, mUserId);
                     if (widgetData != null && widgetData.length > 0) {
                         File metadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
                         appMetadataBackupWriter.backupWidget(
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
new file mode 100644
index 0000000..06dc918
--- /dev/null
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Monitors the health of packages on the system and notifies interested observers when packages
+ * fail. All registered observers will be notified until an observer takes a mitigation action.
+ */
+public class PackageWatchdog {
+    private static final String TAG = "PackageWatchdog";
+    // Duration to count package failures before it resets to 0
+    private static final int TRIGGER_DURATION_MS = 60000;
+    // Number of package failures within the duration above before we notify observers
+    private static final int TRIGGER_FAILURE_COUNT = 5;
+    private static final int DB_VERSION = 1;
+    private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
+    private static final String TAG_PACKAGE = "package";
+    private static final String TAG_OBSERVER = "observer";
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_DURATION = "duration";
+    private static final int MESSAGE_SAVE_FILE = 1;
+
+    private static PackageWatchdog sPackageWatchdog;
+
+    private final Object mLock = new Object();
+    // System server context
+    private final Context mContext;
+    // Handler to run package cleanup runnables
+    private final Handler mTimerHandler;
+    private final HandlerThread mIoThread = new HandlerThread("package_watchdog_io",
+            Process.THREAD_PRIORITY_BACKGROUND);
+    private final Handler mIoHandler;
+    // Maps observer names to package observers that have been registered since the last boot
+    @GuardedBy("mLock")
+    final Map<String, PackageHealthObserver> mRegisteredObservers = new ArrayMap<>();
+    // Maps observer names to internal observers (registered or not) loaded from file
+    @GuardedBy("mLock")
+    final Map<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+    // /data/system/ directory
+    private final File mSystemDir = new File(Environment.getDataDirectory(), "system");
+    // File containing the XML data of monitored packages
+    private final AtomicFile mPolicyFile =
+            new AtomicFile(new File(mSystemDir, "package-watchdog.xml"));
+    // Runnable to prune monitored packages that have expired
+    private final Runnable mPackageCleanup;
+    // Last SystemClock#uptimeMillis a package clean up was executed.
+    // 0 if mPackageCleanup not running.
+    private long mUptimeAtLastRescheduleMs;
+    // Duration a package cleanup was last scheduled for.
+    // 0 if mPackageCleanup not running.
+    private long mDurationAtLastReschedule;
+
+    private PackageWatchdog(Context context) {
+        mContext = context;
+        mTimerHandler = new Handler(Looper.myLooper());
+        mIoThread.start();
+        mIoHandler = new IoHandler(mIoThread.getLooper());
+        mPackageCleanup = this::rescheduleCleanup;
+        loadFromFile();
+    }
+
+    /** Creates or gets singleton instance of PackageWatchdog. */
+    public static synchronized PackageWatchdog getInstance(Context context) {
+        if (sPackageWatchdog == null) {
+            sPackageWatchdog = new PackageWatchdog(context);
+        }
+        return sPackageWatchdog;
+    }
+
+    /**
+     * Registers {@code observer} to listen for package failures
+     *
+     * <p>Observers are expected to call this on boot. It does not specify any packages but
+     * it will resume observing any packages requested from a previous boot.
+     */
+    public void registerHealthObserver(PackageHealthObserver observer) {
+        synchronized (mLock) {
+            mRegisteredObservers.put(observer.getName(), observer);
+            if (mDurationAtLastReschedule == 0) {
+                // Nothing running, schedule
+                rescheduleCleanup();
+            }
+        }
+    }
+
+    /**
+     * Starts observing the health of the {@code packages} for {@code observer} and notifies
+     * {@code observer} of any package failures within the monitoring duration.
+     *
+     * <p>If {@code observer} is already monitoring a package in {@code packageNames},
+     * the monitoring window of that package will be reset to {@code hours}.
+     *
+     * @throws IllegalArgumentException if {@code packageNames} is empty
+     * or {@code hours} is less than 1
+     */
+    public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
+            int hours) {
+        if (packageNames.isEmpty() || hours < 1) {
+            throw new IllegalArgumentException("Observation not started, no packages specified"
+                    + "or invalid hours");
+        }
+        long durationMs = TimeUnit.HOURS.toMillis(hours);
+        List<MonitoredPackage> packages = new ArrayList<>();
+        for (String packageName : packageNames) {
+            packages.add(new MonitoredPackage(packageName, durationMs));
+        }
+        synchronized (mLock) {
+            ObserverInternal oldObserver = mAllObservers.get(observer.getName());
+            if (oldObserver == null) {
+                Slog.d(TAG, observer.getName() + " started monitoring health of packages "
+                        + packageNames);
+                mAllObservers.put(observer.getName(),
+                        new ObserverInternal(observer.getName(), packages));
+            } else {
+                Slog.d(TAG, observer.getName() + " added the following packages to monitor "
+                        + packageNames);
+                oldObserver.updatePackages(packages);
+            }
+        }
+        registerHealthObserver(observer);
+        // Always reschedule because we may need to expire packages
+        // earlier than we are already scheduled for
+        rescheduleCleanup();
+        sendIoMessage(MESSAGE_SAVE_FILE);
+    }
+
+    /**
+     * Unregisters {@code observer} from listening to package failure.
+     * Additionally, this stops observing any packages that may have previously been observed
+     * even from a previous boot.
+     */
+    public void unregisterHealthObserver(PackageHealthObserver observer) {
+        synchronized (mLock) {
+            mAllObservers.remove(observer.getName());
+            mRegisteredObservers.remove(observer.getName());
+        }
+        sendIoMessage(MESSAGE_SAVE_FILE);
+    }
+
+    // TODO(zezeozue:) Accept current versionCodes of failing packages?
+    /**
+     * Called when a process fails either due to a crash or ANR.
+     *
+     * <p>All registered observers for the packages contained in the process will be notified in
+     * order of priority unitl an observer signifies that it has taken action and other observers
+     * should not notified.
+     *
+     * <p>This method could be called frequently if there is a severe problem on the device.
+     */
+    public void onPackageFailure(String[] packages) {
+        synchronized (mLock) {
+            if (mRegisteredObservers.isEmpty()) {
+                return;
+            }
+            for (String packageName : packages) {
+                for (ObserverInternal observer : mAllObservers.values()) {
+                    if (observer.onPackageFailure(packageName)) {
+                        PackageHealthObserver activeObserver =
+                                mRegisteredObservers.get(observer.mName);
+                        if (activeObserver != null
+                                && activeObserver.onHealthCheckFailed(packageName)) {
+                            // Observer has handled, do not notify other observers
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // TODO(zezeozue): Optimize write? Maybe only write a separate smaller file?
+    // This currently adds about 7ms extra to shutdown thread
+    /** Writes the package information to file during shutdown. */
+    public void writeNow() {
+        if (!mAllObservers.isEmpty()) {
+            mIoHandler.removeMessages(MESSAGE_SAVE_FILE);
+            pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastRescheduleMs);
+            saveToFile();
+            Slog.i(TAG, "Last write to update package durations");
+        }
+    }
+
+    /** Register instances of this interface to receive notifications on package failure. */
+    public interface PackageHealthObserver {
+        /**
+         * Called when health check fails for the {@code packages}.
+         * @return {@code true} if action was taken and other observers should not be notified of
+         * this failure, {@code false} otherwise.
+         */
+        boolean onHealthCheckFailed(String packageName);
+
+        // TODO(zezeozue): Ensure uniqueness?
+        /**
+         * Identifier for the observer, should not change across device updates otherwise the
+         * watchdog may drop observing packages with the old name.
+         */
+        String getName();
+    }
+
+    /** Reschedules handler to prune expired packages from observers. */
+    private void rescheduleCleanup() {
+        synchronized (mLock) {
+            long nextDurationToScheduleMs = getEarliestPackageExpiryLocked();
+            if (nextDurationToScheduleMs == Long.MAX_VALUE) {
+                Slog.i(TAG, "No monitored packages, ending package cleanup");
+                mDurationAtLastReschedule = 0;
+                mUptimeAtLastRescheduleMs = 0;
+                return;
+            }
+            long uptimeMs = SystemClock.uptimeMillis();
+            // O if mPackageCleanup not running
+            long elapsedDurationMs = mUptimeAtLastRescheduleMs == 0
+                    ? 0 : uptimeMs - mUptimeAtLastRescheduleMs;
+            // O if mPackageCleanup not running
+            long remainingDurationMs = mDurationAtLastReschedule - elapsedDurationMs;
+
+            if (mUptimeAtLastRescheduleMs == 0 || nextDurationToScheduleMs < remainingDurationMs) {
+                // First schedule or an earlier reschedule
+                pruneObservers(elapsedDurationMs);
+                mTimerHandler.removeCallbacks(mPackageCleanup);
+                mTimerHandler.postDelayed(mPackageCleanup, nextDurationToScheduleMs);
+                mDurationAtLastReschedule = nextDurationToScheduleMs;
+                mUptimeAtLastRescheduleMs = uptimeMs;
+            }
+        }
+    }
+
+    /**
+     * Returns the earliest time a package should expire.
+     * @returns Long#MAX_VALUE if there are no observed packages.
+     */
+    private long getEarliestPackageExpiryLocked() {
+        long shortestDurationMs = Long.MAX_VALUE;
+        for (ObserverInternal observer : mAllObservers.values()) {
+            for (MonitoredPackage p : observer.mPackages.values()) {
+                if (p.mDurationMs < shortestDurationMs) {
+                    shortestDurationMs = p.mDurationMs;
+                }
+            }
+        }
+        Slog.v(TAG, "Earliest package time is " + shortestDurationMs);
+        return shortestDurationMs;
+    }
+
+    /**
+     * Removes {@code elapsedMs} milliseconds from all durations on monitored packages.
+     * Discards expired packages and discards observers without any packages.
+     */
+    private void pruneObservers(long elapsedMs) {
+        if (elapsedMs == 0) {
+            return;
+        }
+        synchronized (mLock) {
+            Slog.d(TAG, "Removing expired packages after " + elapsedMs + "ms");
+            Iterator<ObserverInternal> it = mAllObservers.values().iterator();
+            while (it.hasNext()) {
+                ObserverInternal observer = it.next();
+                if (!observer.updateMonitoringDurations(elapsedMs)) {
+                    Slog.i(TAG, "Discarding observer " + observer.mName + ". All packages expired");
+                    it.remove();
+                }
+            }
+        }
+        sendIoMessage(MESSAGE_SAVE_FILE);
+    }
+
+    /**
+     * Loads mAllObservers from file.
+     *
+     * <p>Note that this is <b>not</b> thread safe and should only called be called
+     * from the constructor.
+     */
+    private void loadFromFile() {
+        InputStream infile = null;
+        mAllObservers.clear();
+        try {
+            infile = mPolicyFile.openRead();
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(infile, StandardCharsets.UTF_8.name());
+            XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                ObserverInternal observer = ObserverInternal.read(parser);
+                if (observer != null) {
+                    mAllObservers.put(observer.mName, observer);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // Nothing to monitor
+        } catch (IOException e) {
+            Log.wtf(TAG, "Unable to read monitored packages", e);
+        } catch (NumberFormatException e) {
+            Log.wtf(TAG, "Unable to parse monitored package windows", e);
+        } catch (XmlPullParserException e) {
+            Log.wtf(TAG, "Unable to parse monitored packages", e);
+        } finally {
+            IoUtils.closeQuietly(infile);
+        }
+    }
+
+    /**
+     * Persists mAllObservers to file and ignores threshold information.
+     *
+     * <p>Note that this is <b>not</b> thread safe and should only be called on the
+     * single threaded IoHandler.
+     */
+    private boolean saveToFile() {
+        FileOutputStream stream;
+        try {
+            stream = mPolicyFile.startWrite();
+        } catch (IOException e) {
+            Slog.w(TAG, "Cannot update monitored packages", e);
+            return false;
+        }
+
+        try {
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(stream, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+            out.startTag(null, TAG_PACKAGE_WATCHDOG);
+            out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+            for (ObserverInternal observer : mAllObservers.values()) {
+                observer.write(out);
+            }
+            out.endTag(null, TAG_PACKAGE_WATCHDOG);
+            out.endDocument();
+            mPolicyFile.finishWrite(stream);
+            return true;
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to save monitored packages, restoring backup", e);
+            mPolicyFile.failWrite(stream);
+            return false;
+        } finally {
+            IoUtils.closeQuietly(stream);
+        }
+    }
+
+    private void sendIoMessage(int what) {
+        if (!mIoHandler.hasMessages(what)) {
+            Message m = Message.obtain(mIoHandler, what);
+            mIoHandler.sendMessage(m);
+        }
+    }
+
+    /**
+     * Represents an observer monitoring a set of packages along with the failure thresholds for
+     * each package.
+     */
+    static class ObserverInternal {
+        public final String mName;
+        public final ArrayMap<String, MonitoredPackage> mPackages;
+
+        ObserverInternal(String name, List<MonitoredPackage> packages) {
+            mName = name;
+            mPackages = new ArrayMap<>();
+            updatePackages(packages);
+        }
+
+        /**
+         * Writes important details to file. Doesn't persist any package failure thresholds.
+         *
+         * <p>Note that this method is <b>not</b> thread safe. It should only be called from
+         * #saveToFile which runs on a single threaded handler.
+         */
+        public boolean write(XmlSerializer out) {
+            try {
+                out.startTag(null, TAG_OBSERVER);
+                out.attribute(null, ATTR_NAME, mName);
+                for (int i = 0; i < mPackages.size(); i++) {
+                    MonitoredPackage p = mPackages.valueAt(i);
+                    out.startTag(null, TAG_PACKAGE);
+                    out.attribute(null, ATTR_NAME, p.mName);
+                    out.attribute(null, ATTR_DURATION, String.valueOf(p.mDurationMs));
+                    out.endTag(null, TAG_PACKAGE);
+                }
+                out.endTag(null, TAG_OBSERVER);
+                return true;
+            } catch (IOException e) {
+                Slog.w(TAG, "Cannot save observer", e);
+                return false;
+            }
+        }
+
+        public void updatePackages(List<MonitoredPackage> packages) {
+            synchronized (mName) {
+                for (MonitoredPackage p : packages) {
+                    mPackages.put(p.mName, p);
+                }
+            }
+        }
+
+        /**
+         * Reduces the monitoring durations of all packages observed by this observer by
+         *  {@code elapsedMs}. If any duration is less than 0, the package is removed from
+         * observation.
+         *
+         * @returns {@code true} if there are still packages to be observed, {@code false} otherwise
+         */
+        public boolean updateMonitoringDurations(long elapsedMs) {
+            List<MonitoredPackage> packages = new ArrayList<>();
+            synchronized (mName) {
+                Iterator<MonitoredPackage> it = mPackages.values().iterator();
+                while (it.hasNext()) {
+                    MonitoredPackage p = it.next();
+                    long newDuration = p.mDurationMs - elapsedMs;
+                    if (newDuration > 0) {
+                        p.mDurationMs = newDuration;
+                    } else {
+                        it.remove();
+                    }
+                }
+                return !mPackages.isEmpty();
+            }
+        }
+
+        /**
+         * Increments failure counts of {@code packageName}.
+         * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
+         */
+        public boolean onPackageFailure(String packageName) {
+            synchronized (mName) {
+                MonitoredPackage p = mPackages.get(packageName);
+                if (p != null) {
+                    return p.onFailure();
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Returns one ObserverInternal from the {@code parser} and advances its state.
+         *
+         * <p>Note that this method is <b>not</b> thread safe. It should only be called from
+         * #loadFromFile which in turn is only called on construction of the
+         * singleton PackageWatchdog.
+         **/
+        public static ObserverInternal read(XmlPullParser parser) {
+            String observerName = null;
+            if (TAG_OBSERVER.equals(parser.getName())) {
+                observerName = parser.getAttributeValue(null, ATTR_NAME);
+                if (TextUtils.isEmpty(observerName)) {
+                    return null;
+                }
+            }
+            List<MonitoredPackage> packages = new ArrayList<>();
+            int innerDepth = parser.getDepth();
+            try {
+                while (XmlUtils.nextElementWithin(parser, innerDepth)) {
+                    if (TAG_PACKAGE.equals(parser.getName())) {
+                        String packageName = parser.getAttributeValue(null, ATTR_NAME);
+                        long duration = Long.parseLong(
+                                parser.getAttributeValue(null, ATTR_DURATION));
+                        if (!TextUtils.isEmpty(packageName)) {
+                            packages.add(new MonitoredPackage(packageName, duration));
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                return null;
+            } catch (XmlPullParserException e) {
+                return null;
+            }
+            if (packages.isEmpty()) {
+                return null;
+            }
+            return new ObserverInternal(observerName, packages);
+        }
+    }
+
+    /** Represents a package along with the time it should be monitored for. */
+    static class MonitoredPackage {
+        public final String mName;
+        // System uptime duration to monitor package
+        public long mDurationMs;
+        // System uptime of first package failure
+        private long mUptimeStartMs;
+        // Number of failures since mUptimeStartMs
+        private int mFailures;
+
+        MonitoredPackage(String name, long durationMs) {
+            mName = name;
+            mDurationMs = durationMs;
+        }
+
+        /**
+         * Increment package failures or resets failure count depending on the last package failure.
+         *
+         * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
+         */
+        public synchronized boolean onFailure() {
+            final long now = SystemClock.uptimeMillis();
+            final long duration = now - mUptimeStartMs;
+            if (duration > TRIGGER_DURATION_MS) {
+                // TODO(zezeozue): Reseting to 1 is not correct
+                // because there may be more than 1 failure in the last trigger window from now
+                // This is the RescueParty impl, will leave for now
+                mFailures = 1;
+                mUptimeStartMs = now;
+            } else {
+                mFailures++;
+            }
+            return mFailures >= TRIGGER_FAILURE_COUNT;
+        }
+    }
+
+    private class IoHandler extends Handler {
+        IoHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_SAVE_FILE:
+                    saveToFile();
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index e80e9e1..1aeb689 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -91,6 +91,7 @@
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
+        "/system/bin/vold",
         "media.extractor", // system/bin/mediaextractor
         "media.metrics", // system/bin/mediametrics
         "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1a5dd90..16c236e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -336,6 +336,7 @@
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.NetworkManagementInternal;
+import com.android.server.PackageWatchdog;
 import com.android.server.RescueParty;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
@@ -587,6 +588,7 @@
     public final PendingIntentController mPendingIntentController;
 
     final AppErrors mAppErrors;
+    final PackageWatchdog mPackageWatchdog;
 
     /**
      * Indicates the maximum time spent waiting for the network rules to get updated.
@@ -2209,6 +2211,7 @@
         mContext = mInjector.getContext();
         mUiContext = null;
         mAppErrors = null;
+        mPackageWatchdog = null;
         mActiveUids = new ActiveUids(this, false /* postChangesToAtm */);
         mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
         mBatteryStatsService = null;
@@ -2275,7 +2278,8 @@
 
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
-        mAppErrors = new AppErrors(mUiContext, this);
+        mPackageWatchdog = PackageWatchdog.getInstance(mUiContext);
+        mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog);
         mActiveUids = new ActiveUids(this, true /* postChangesToAtm */);
 
         final File systemDir = SystemServiceManager.ensureSystemDir();
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 1c1daff..a634b57 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -53,6 +53,7 @@
 import com.android.internal.app.ProcessMap;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.PackageWatchdog;
 import com.android.server.RescueParty;
 import com.android.server.wm.WindowProcessController;
 
@@ -69,6 +70,7 @@
 
     private final ActivityManagerService mService;
     private final Context mContext;
+    private final PackageWatchdog mPackageWatchdog;
 
     private ArraySet<String> mAppsNotReportingCrashes;
 
@@ -93,10 +95,11 @@
     private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
 
 
-    AppErrors(Context context, ActivityManagerService service) {
+    AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog) {
         context.assertRuntimeOverlayThemable();
         mService = service;
         mContext = context;
+        mPackageWatchdog = watchdog;
     }
 
     void writeToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
@@ -400,10 +403,16 @@
             longMsg = shortMsg;
         }
 
-        // If a persistent app is stuck in a crash loop, the device isn't very
-        // usable, so we want to consider sending out a rescue party.
-        if (r != null && r.isPersistent()) {
-            RescueParty.notePersistentAppCrash(mContext, r.uid);
+        if (r != null) {
+            if (r.isPersistent()) {
+                // If a persistent app is stuck in a crash loop, the device isn't very
+                // usable, so we want to consider sending out a rescue party.
+                RescueParty.notePersistentAppCrash(mContext, r.uid);
+            } else {
+                // If a non-persistent app is stuck in crash loop, we want to inform
+                // the package watchdog, maybe an update or experiment can be rolled back.
+                mPackageWatchdog.onPackageFailure(r.getPackageList());
+            }
         }
 
         final int relaunchReason = r != null
@@ -821,6 +830,7 @@
 
     void handleShowAnrUi(Message msg) {
         Dialog dialogToShow = null;
+        String[] packageList = null;
         synchronized (mService) {
             AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
             final ProcessRecord proc = data.proc;
@@ -828,6 +838,9 @@
                 Slog.e(TAG, "handleShowAnrUi: proc is null");
                 return;
             }
+            if (!proc.isPersistent()) {
+                packageList = proc.getPackageList();
+            }
             if (proc.anrDialog != null) {
                 Slog.e(TAG, "App already has anr dialog: " + proc);
                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
@@ -851,6 +864,10 @@
         if (dialogToShow != null) {
             dialogToShow.show();
         }
+        // Notify PackageWatchdog without the lock held
+        if (packageList != null) {
+            mPackageWatchdog.onPackageFailure(packageList);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 117984e..d133dea 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1362,8 +1362,9 @@
                 mService.mNativeDebuggingApp = null;
             }
 
-            if (app.info.isPrivilegedApp() &&
-                    DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
+            if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0
+                    || (app.info.isPrivilegedApp()
+                        && DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet()))) {
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
 
@@ -1613,6 +1614,13 @@
                 app.addPackage(info.packageName, info.versionCode, mService.mProcessStats);
                 checkSlow(startTime, "startProcess: done, added package to proc");
                 return app;
+            } else if (app.getActiveInstrumentation() != null) {
+                // We don't want to kill running instrumentation.
+                if (DEBUG_PROCESSES) {
+                    Slog.v(TAG_PROCESSES, "Instrumentation already running: " + app);
+                }
+                checkSlow(startTime, "startProcess: keep instrumentation proc");
+                return app;
             }
 
             // An application record is attached to a previous process,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6cde4ad..d704a3e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7822,6 +7822,36 @@
         return AudioManager.SUCCESS;
     }
 
+    /** see AudioPolicy.setUidDeviceAffinity() */
+    public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
+            @NonNull int[] deviceTypes,
+            @NonNull String[] deviceAddresses) {
+        synchronized (mAudioPolicies) {
+            final AudioPolicyProxy app =
+                    checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
+            if (app == null) {
+                return AudioManager.ERROR;
+            }
+            if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
+                return AudioManager.ERROR;
+            }
+        }
+        return AudioManager.SUCCESS;
+    }
+
+    /** see AudioPolicy.removeUidDeviceAffinity() */
+    public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
+        synchronized (mAudioPolicies) {
+            final AudioPolicyProxy app =
+                    checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
+            if (app == null) {
+                return AudioManager.ERROR;
+            }
+
+        }
+        return AudioManager.SUCCESS;
+    }
+
     public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
         if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
                 + " policy " +  pcb.asBinder());
@@ -7994,6 +8024,15 @@
     //======================
     // Audio policy proxy
     //======================
+    private static final class AudioDeviceArray {
+        final @NonNull int[] mDeviceTypes;
+        final @NonNull String[] mDeviceAddresses;
+        AudioDeviceArray(@NonNull int[] types,  @NonNull String[] addresses) {
+            mDeviceTypes = types;
+            mDeviceAddresses = addresses;
+        }
+    }
+
     /**
      * This internal class inherits from AudioPolicyConfig, each instance contains all the
      * mixes of an AudioPolicy and their configurations.
@@ -8003,6 +8042,8 @@
         final IAudioPolicyCallback mPolicyCallback;
         final boolean mHasFocusListener;
         final boolean mIsVolumeController;
+        final HashMap<Integer, AudioDeviceArray> mUidDeviceAffinities =
+                new HashMap<Integer, AudioDeviceArray>();
         /**
          * Audio focus ducking behavior for an audio policy.
          * This variable reflects the value that was successfully set in
@@ -8075,6 +8116,26 @@
             return false;
         }
 
+        // Verify all the devices in the array are served by mixes defined in this policy
+        boolean hasMixRoutedToDevices(@NonNull int[] deviceTypes,
+                @NonNull String[] deviceAddresses) {
+            for (int i = 0; i < deviceTypes.length; i++) {
+                boolean hasDevice = false;
+                for (AudioMix mix : mMixes) {
+                    // this will check both that the mix has ROUTE_FLAG_RENDER and the device
+                    // is reached by this mix
+                    if (mix.isRoutedToDevice(deviceTypes[i], deviceAddresses[i])) {
+                        hasDevice = true;
+                        break;
+                    }
+                }
+                if (!hasDevice) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         void addMixes(@NonNull ArrayList<AudioMix> mixes) {
             // TODO optimize to not have to unregister the mixes already in place
             synchronized (mMixes) {
@@ -8098,6 +8159,29 @@
             AudioSystem.registerPolicyMixes(mMixes, true);
             Binder.restoreCallingIdentity(identity);
         }
+
+        void setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+            final Integer Uid = new Integer(uid);
+            if (mUidDeviceAffinities.remove(Uid) != null) {
+                final long identity = Binder.clearCallingIdentity();
+                AudioSystem.removeUidDeviceAffinities(uid);
+                Binder.restoreCallingIdentity(identity);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            final int res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
+            Binder.restoreCallingIdentity(identity);
+            if (res == AudioSystem.SUCCESS) {
+                mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
+            }
+        }
+
+        void removeUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+            if (mUidDeviceAffinities.remove(new Integer(uid)) != null) {
+                final long identity = Binder.clearCallingIdentity();
+                AudioSystem.removeUidDeviceAffinities(uid);
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     };
 
     //======================
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b6c82d3..73d3d95 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
 
 import android.animation.Animator;
@@ -31,6 +32,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.IColorDisplayManager;
 import android.net.Uri;
 import android.opengl.Matrix;
@@ -86,23 +88,94 @@
      */
     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
 
+    private final TintController mNightDisplayTintController = new TintController() {
+
+        private float[] mMatrixNightDisplay = new float[16];
+        private final float[] mColorTempCoefficients = new float[9];
+
+        /**
+         * Set coefficients based on whether the color matrix is linear or not.
+         */
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+            final String[] coefficients = context.getResources().getStringArray(needsLinear
+                    ? R.array.config_nightDisplayColorTemperatureCoefficients
+                    : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
+            for (int i = 0; i < 9 && i < coefficients.length; i++) {
+                mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
+            }
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+            if (mMatrixNightDisplay.length != 16) {
+                Slog.d(TAG, "The display transformation matrix must be 4x4");
+                return;
+            }
+
+            Matrix.setIdentityM(mMatrixNightDisplay, 0);
+
+            final float squareTemperature = cct * cct;
+            final float red = squareTemperature * mColorTempCoefficients[0]
+                    + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
+            final float green = squareTemperature * mColorTempCoefficients[3]
+                    + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
+            final float blue = squareTemperature * mColorTempCoefficients[6]
+                    + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
+            mMatrixNightDisplay[0] = red;
+            mMatrixNightDisplay[5] = green;
+            mMatrixNightDisplay[10] = blue;
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return isActivated() ? mMatrixNightDisplay : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+        }
+    };
+
+    private final TintController mDisplayWhiteBalanceTintController = new TintController() {
+
+        private float[] mMatrixDisplayWhiteBalance = new float[16];
+
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+        }
+    };
+
     private final Handler mHandler;
 
-    private float[] mMatrixNight = new float[16];
-
-    private final float[] mColorTempCoefficients = new float[9];
-
     private int mCurrentUser = UserHandle.USER_NULL;
     private ContentObserver mUserSetupObserver;
     private boolean mBootCompleted;
 
     private ColorDisplayController mNightDisplayController;
     private ContentObserver mContentObserver;
-    private ValueAnimator mColorMatrixAnimator;
 
-    private Boolean mIsNightDisplayActivated;
+    private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
+
     private NightDisplayAutoMode mNightDisplayAutoMode;
 
+    private Integer mDisplayWhiteBalanceColorTemperature;
+
     public ColorDisplayService(Context context) {
         super(context);
         mHandler = new Handler(Looper.getMainLooper());
@@ -111,6 +184,7 @@
     @Override
     public void onStart() {
         publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
+        publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal());
     }
 
     @Override
@@ -232,6 +306,9 @@
                             case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
                                 onAccessibilityTransformChanged();
                                 break;
+                            case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
+                                onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+                                break;
                         }
                     }
                 }
@@ -256,25 +333,41 @@
         cr.registerContentObserver(
                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
+                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
 
         // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
         // existing activated state. This ensures consistency of tint across the color mode change.
         onDisplayColorModeChanged(mNightDisplayController.getColorMode());
 
-        // Reset the activated state.
-        mIsNightDisplayActivated = null;
+        if (ColorDisplayManager.isNightDisplayAvailable(getContext())) {
+            // Reset the activated state.
+            mNightDisplayTintController.setActivated(null);
 
-        setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            // Prepare the night display color transformation matrix.
+            mNightDisplayTintController
+                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
 
-        // Prepare color transformation matrix.
-        setMatrix(mNightDisplayController.getColorTemperature(), mMatrixNight);
+            // Initialize the current auto mode.
+            onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
 
-        // Initialize the current auto mode.
-        onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
+            // Force the initialization current activated state.
+            if (mNightDisplayTintController.isActivatedStateNotSet()) {
+                onNightDisplayActivated(mNightDisplayController.isActivated());
+            }
+        }
 
-        // Force the initialization current activated state.
-        if (mIsNightDisplayActivated == null) {
-            onNightDisplayActivated(mNightDisplayController.isActivated());
+        if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+            // Prepare the display white balance transform matrix.
+            mDisplayWhiteBalanceTintController
+                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            if (mDisplayWhiteBalanceColorTemperature != null) {
+                mDisplayWhiteBalanceTintController
+                        .setMatrix(mDisplayWhiteBalanceColorTemperature);
+            }
+
+            onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
         }
     }
 
@@ -287,28 +380,31 @@
             mNightDisplayController = null;
         }
 
-        if (mNightDisplayAutoMode != null) {
-            mNightDisplayAutoMode.onStop();
-            mNightDisplayAutoMode = null;
+        if (ColorDisplayManager.isNightDisplayAvailable(getContext())) {
+            if (mNightDisplayAutoMode != null) {
+                mNightDisplayAutoMode.onStop();
+                mNightDisplayAutoMode = null;
+            }
+            mNightDisplayTintController.endAnimator();
         }
 
-        if (mColorMatrixAnimator != null) {
-            mColorMatrixAnimator.end();
-            mColorMatrixAnimator = null;
+        if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+            mDisplayWhiteBalanceTintController.endAnimator();
         }
     }
 
     private void onNightDisplayActivated(boolean activated) {
-        if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activated) {
+        if (mNightDisplayTintController.isActivatedStateNotSet()
+                || mNightDisplayTintController.isActivated() != activated) {
             Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
 
-            mIsNightDisplayActivated = activated;
+            mNightDisplayTintController.setActivated(activated);
 
             if (mNightDisplayAutoMode != null) {
                 mNightDisplayAutoMode.onActivated(activated);
             }
 
-            applyTint(false);
+            applyTint(mNightDisplayTintController, false);
         }
     }
 
@@ -348,8 +444,8 @@
     }
 
     private void onNightDisplayColorTemperatureChanged(int colorTemperature) {
-        setMatrix(colorTemperature, mMatrixNight);
-        applyTint(true);
+        mNightDisplayTintController.setMatrix(colorTemperature);
+        applyTint(mNightDisplayTintController, true);
     }
 
     private void onDisplayColorModeChanged(int mode) {
@@ -357,66 +453,53 @@
             return;
         }
 
-        // Cancel the night display tint animator if it's running.
-        if (mColorMatrixAnimator != null) {
-            mColorMatrixAnimator.cancel();
+        mNightDisplayTintController.cancelAnimator();
+        mDisplayWhiteBalanceTintController.cancelAnimator();
+
+        mNightDisplayTintController
+                .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
+        mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
+
+        mDisplayWhiteBalanceTintController
+                .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
+        if (mDisplayWhiteBalanceColorTemperature != null) {
+            mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
         }
 
-        setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
-        setMatrix(mNightDisplayController.getColorTemperature(), mMatrixNight);
-
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
-        dtm.setColorMode(mode, (mIsNightDisplayActivated != null && mIsNightDisplayActivated)
-                ? mMatrixNight : MATRIX_IDENTITY);
+        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
     }
 
     private void onAccessibilityTransformChanged() {
         onDisplayColorModeChanged(mNightDisplayController.getColorMode());
     }
 
-    /**
-     * Set coefficients based on whether the color matrix is linear or not.
-     */
-    private void setCoefficientMatrix(Context context, boolean needsLinear) {
-        final String[] coefficients = context.getResources().getStringArray(needsLinear
-                ? R.array.config_nightDisplayColorTemperatureCoefficients
-                : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
-        for (int i = 0; i < 9 && i < coefficients.length; i++) {
-            mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
-        }
-    }
 
     /**
      * Applies current color temperature matrix, or removes it if deactivated.
      *
      * @param immediate {@code true} skips transition animation
      */
-    private void applyTint(boolean immediate) {
-        // Cancel the old animator if still running.
-        if (mColorMatrixAnimator != null) {
-            mColorMatrixAnimator.cancel();
-        }
+    private void applyTint(TintController tintController, boolean immediate) {
+        tintController.cancelAnimator();
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
-        final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
-        final float[] to = mIsNightDisplayActivated ? mMatrixNight : MATRIX_IDENTITY;
+        final float[] from = dtm.getColorMatrix(tintController.getLevel());
+        final float[] to = tintController.getMatrix();
 
         if (immediate) {
-            dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to);
+            dtm.setColorMatrix(tintController.getLevel(), to);
         } else {
-            mColorMatrixAnimator = ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
-                    from == null ? MATRIX_IDENTITY : from, to);
-            mColorMatrixAnimator.setDuration(TRANSITION_DURATION);
-            mColorMatrixAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+            tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
+                    from == null ? MATRIX_IDENTITY : from, to));
+            tintController.getAnimator().setDuration(TRANSITION_DURATION);
+            tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
                     getContext(), android.R.interpolator.fast_out_slow_in));
-            mColorMatrixAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    final float[] value = (float[]) animator.getAnimatedValue();
-                    dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, value);
-                }
+            tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
+                final float[] value = (float[]) animator.getAnimatedValue();
+                dtm.setColorMatrix(tintController.getLevel(), value);
             });
-            mColorMatrixAnimator.addListener(new AnimatorListenerAdapter() {
+            tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
 
                 private boolean mIsCancelled;
 
@@ -431,42 +514,16 @@
                         // Ensure final color matrix is set at the end of the animation. If the
                         // animation is cancelled then don't set the final color matrix so the new
                         // animator can pick up from where this one left off.
-                        dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to);
+                        dtm.setColorMatrix(tintController.getLevel(), to);
                     }
-                    mColorMatrixAnimator = null;
+                    tintController.setAnimator(null);
                 }
             });
-            mColorMatrixAnimator.start();
+            tintController.getAnimator().start();
         }
     }
 
     /**
-     * Set the color transformation {@code MATRIX_NIGHT} to the given color temperature.
-     *
-     * @param colorTemperature color temperature in Kelvin
-     * @param outTemp the 4x4 display transformation matrix for that color temperature
-     */
-    private void setMatrix(int colorTemperature, float[] outTemp) {
-        if (outTemp.length != 16) {
-            Slog.d(TAG, "The display transformation matrix must be 4x4");
-            return;
-        }
-
-        Matrix.setIdentityM(mMatrixNight, 0);
-
-        final float squareTemperature = colorTemperature * colorTemperature;
-        final float red = squareTemperature * mColorTempCoefficients[0]
-                + colorTemperature * mColorTempCoefficients[1] + mColorTempCoefficients[2];
-        final float green = squareTemperature * mColorTempCoefficients[3]
-                + colorTemperature * mColorTempCoefficients[4] + mColorTempCoefficients[5];
-        final float blue = squareTemperature * mColorTempCoefficients[6]
-                + colorTemperature * mColorTempCoefficients[7] + mColorTempCoefficients[8];
-        outTemp[0] = red;
-        outTemp[5] = green;
-        outTemp[10] = blue;
-    }
-
-    /**
      * Returns the first date time corresponding to the local time that occurs before the provided
      * date time.
      *
@@ -498,6 +555,18 @@
         return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
     }
 
+    private void onDisplayWhiteBalanceEnabled(boolean enabled) {
+        mDisplayWhiteBalanceTintController.setActivated(enabled);
+        if (mDisplayWhiteBalanceListener != null) {
+            mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+        }
+    }
+
+    private boolean isDisplayWhiteBalanceSettingEnabled() {
+        return Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.DISPLAY_WHITE_BALANCE_ENABLED, 0, mCurrentUser) == 1;
+    }
+
     private boolean isDeviceColorManagedInternal() {
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         return dtm.isDeviceColorManaged();
@@ -507,7 +576,7 @@
      * Returns the last time the night display transform activation state was changed, or {@link
      * LocalDateTime#MIN} if night display has never been activated.
      */
-    private @NonNull LocalDateTime getNightDisplayLastActivatedTimeSetting() {
+    private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
         final ContentResolver cr = getContext().getContentResolver();
         final String lastActivatedTime = Secure.getStringForUser(
                 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
@@ -577,11 +646,12 @@
                 }
             }
 
-            if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activate) {
+            if (mNightDisplayTintController.isActivatedStateNotSet() || (
+                    mNightDisplayTintController.isActivated() != activate)) {
                 mNightDisplayController.setActivated(activate);
             }
 
-            updateNextAlarm(mIsNightDisplayActivated, now);
+            updateNextAlarm(mNightDisplayTintController.isActivated(), now);
         }
 
         private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
@@ -672,7 +742,8 @@
                 }
             }
 
-            if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activate) {
+            if (mNightDisplayTintController.isActivatedStateNotSet() || (
+                    mNightDisplayTintController.isActivated() != activate)) {
                 mNightDisplayController.setActivated(activate);
             }
         }
@@ -724,6 +795,115 @@
         }
     }
 
+    private abstract static class TintController {
+
+        private ValueAnimator mAnimator;
+        private Boolean mIsActivated;
+
+        public ValueAnimator getAnimator() {
+            return mAnimator;
+        }
+
+        public void setAnimator(ValueAnimator animator) {
+            mAnimator = animator;
+        }
+
+        /**
+         * Cancel the animator if it's still running.
+         */
+        public void cancelAnimator() {
+            if (mAnimator != null) {
+                mAnimator.cancel();
+            }
+        }
+
+        /**
+         * End the animator if it's still running, jumping to the end state.
+         */
+        public void endAnimator() {
+            if (mAnimator != null) {
+                mAnimator.end();
+                mAnimator = null;
+            }
+        }
+
+        public void setActivated(Boolean isActivated) {
+            mIsActivated = isActivated;
+        }
+
+        public boolean isActivated() {
+            return mIsActivated != null && mIsActivated;
+        }
+
+        public boolean isActivatedStateNotSet() {
+            return mIsActivated == null;
+        }
+
+        /**
+         * Set up any constants needed for computing the matrix.
+         */
+        public abstract void setUp(Context context, boolean needsLinear);
+
+        /**
+         * Sets the 4x4 matrix to apply.
+         */
+        public abstract void setMatrix(int value);
+
+        /**
+         * Get the 4x4 matrix to apply.
+         */
+        public abstract float[] getMatrix();
+
+        /**
+         * Get the color transform level to apply the matrix.
+         */
+        public abstract int getLevel();
+    }
+
+    /**
+     * Local service that allows color transforms to be enabled from other system services.
+     */
+    public final class ColorDisplayServiceInternal {
+
+        /**
+         * Set the current CCT value for the display white balance transform, and if the transform
+         * is enabled, apply it.
+         *
+         * @param cct the color temperature in Kelvin.
+         */
+        public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
+            // Update the transform matrix even if it can't be applied.
+            mDisplayWhiteBalanceColorTemperature = cct;
+            mDisplayWhiteBalanceTintController.setMatrix(cct);
+
+            if (mDisplayWhiteBalanceTintController.isActivated()) {
+                applyTint(mDisplayWhiteBalanceTintController, true);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Sets the listener and returns whether display white balance is currently enabled.
+         */
+        public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
+            mDisplayWhiteBalanceListener = listener;
+            return mDisplayWhiteBalanceTintController.isActivated();
+        }
+    }
+
+    /**
+     * Listener for changes in display white balance status.
+     */
+    public interface DisplayWhiteBalanceListener {
+
+        /**
+         * Notify that the display white balance status has changed, either due to preemption by
+         * another transform or the feature being turned off.
+         */
+        void onDisplayWhiteBalanceStatusChanged(boolean enabled);
+    }
+
     private final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 4ad26da..a5e9728 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -45,6 +45,10 @@
      */
     public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
     /**
+     * Color transform level used by display white balance to adjust the display's white point.
+     */
+    public static final int LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE = 125;
+    /**
      * Color transform level used to adjust the color saturation of the display.
      */
     public static final int LEVEL_COLOR_MATRIX_SATURATION = 150;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d961bad..85a8d93 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -144,7 +144,6 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
-import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -3852,7 +3851,8 @@
         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
                 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
                 throws RemoteException {
-            new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
+            new NotificationShellCmd(NotificationManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
         }
     };
 
@@ -5258,22 +5258,25 @@
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
                     if (hasValidSound) {
-                        mSoundNotificationKey = key;
                         if (mInCall) {
                             playInCallNotification();
                             beep = true;
                         } else {
                             beep = playSound(record, soundUri);
                         }
+                        if(beep) {
+                            mSoundNotificationKey = key;
+                        }
                     }
 
                     final boolean ringerModeSilent =
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
-                        mVibrateNotificationKey = key;
-
                         buzz = playVibration(record, vibration, hasValidSound);
+                        if(buzz) {
+                            mVibrateNotificationKey = key;
+                        }
                     }
                 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                     hasValidSound = false;
@@ -5454,8 +5457,17 @@
                     try {
                         Thread.sleep(waitMs);
                     } catch (InterruptedException e) { }
-                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
-                            effect, "Notification (delayed)", record.getAudioAttributes());
+
+                    // Notifications might be canceled before it actually vibrates due to waitMs,
+                    // so need to check the notification still valide for vibrate.
+                    synchronized (mNotificationLock) {
+                        if (mNotificationsByKey.get(record.getKey()) != null) {
+                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                    effect, "Notification (delayed)", record.getAudioAttributes());
+                        } else {
+                            Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
+                        }
+                    }
                 }).start();
             } else {
                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
@@ -7715,110 +7727,6 @@
         }
     }
 
-    private class ShellCmd extends ShellCommand {
-        public static final String USAGE = "help\n"
-                + "allow_listener COMPONENT [user_id]\n"
-                + "disallow_listener COMPONENT [user_id]\n"
-                + "allow_assistant COMPONENT\n"
-                + "remove_assistant COMPONENT\n"
-                + "allow_dnd PACKAGE\n"
-                + "disallow_dnd PACKAGE\n"
-                + "suspend_package PACKAGE\n"
-                + "unsuspend_package PACKAGE";
-
-        @Override
-        public int onCommand(String cmd) {
-            if (cmd == null) {
-                return handleDefaultCommands(cmd);
-            }
-            final PrintWriter pw = getOutPrintWriter();
-            try {
-                switch (cmd) {
-                    case "allow_dnd": {
-                        getBinderService().setNotificationPolicyAccessGranted(
-                                getNextArgRequired(), true);
-                    }
-                    break;
-
-                    case "disallow_dnd": {
-                        getBinderService().setNotificationPolicyAccessGranted(
-                                getNextArgRequired(), false);
-                    }
-                    break;
-                    case "allow_listener": {
-                        ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
-                        if (cn == null) {
-                            pw.println("Invalid listener - must be a ComponentName");
-                            return -1;
-                        }
-                        String userId = getNextArg();
-                        if (userId == null) {
-                            getBinderService().setNotificationListenerAccessGranted(cn, true);
-                        } else {
-                            getBinderService().setNotificationListenerAccessGrantedForUser(
-                                    cn, Integer.parseInt(userId), true);
-                        }
-                    }
-                    break;
-                    case "disallow_listener": {
-                        ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
-                        if (cn == null) {
-                            pw.println("Invalid listener - must be a ComponentName");
-                            return -1;
-                        }
-                        String userId = getNextArg();
-                        if (userId == null) {
-                            getBinderService().setNotificationListenerAccessGranted(cn, false);
-                        } else {
-                            getBinderService().setNotificationListenerAccessGrantedForUser(
-                                    cn, Integer.parseInt(userId), false);
-                        }
-                    }
-                    break;
-                    case "allow_assistant": {
-                        ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
-                        if (cn == null) {
-                            pw.println("Invalid assistant - must be a ComponentName");
-                            return -1;
-                        }
-                        getBinderService().setNotificationAssistantAccessGranted(cn, true);
-                    }
-                    break;
-                    case "disallow_assistant": {
-                        ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
-                        if (cn == null) {
-                            pw.println("Invalid assistant - must be a ComponentName");
-                            return -1;
-                        }
-                        getBinderService().setNotificationAssistantAccessGranted(cn, false);
-                    }
-                    break;
-                    case "suspend_package": {
-                        // only use for testing
-                        simulatePackageSuspendBroadcast(true, getNextArgRequired());
-                    }
-                    break;
-                    case "unsuspend_package": {
-                        // only use for testing
-                        simulatePackageSuspendBroadcast(false, getNextArgRequired());
-                    }
-                    break;
-                    default:
-                        return handleDefaultCommands(cmd);
-                }
-            } catch (Exception e) {
-                pw.println("Error occurred. Check logcat for details. " + e.getMessage());
-                Slog.e(TAG, "Error running shell command", e);
-            }
-            return 0;
-        }
-
-        @Override
-        public void onHelp() {
-            getOutPrintWriter().println(USAGE);
-        }
-    }
-
     private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
         out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
         out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
new file mode 100644
index 0000000..3d88f20
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -0,0 +1,483 @@
+/*
+ * 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.notification;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.util.Collections;
+
+/**
+ * Implementation of `cmd notification` in NotificationManagerService.
+ */
+public class NotificationShellCmd extends ShellCommand {
+    private static final String USAGE =
+              "usage: cmd notification SUBCMD [args]\n\n"
+            + "SUBCMDs:\n"
+            + "  allow_listener COMPONENT [user_id]\n"
+            + "  disallow_listener COMPONENT [user_id]\n"
+            + "  allow_assistant COMPONENT\n"
+            + "  remove_assistant COMPONENT\n"
+            + "  allow_dnd PACKAGE\n"
+            + "  disallow_dnd PACKAGE\n"
+            + "  suspend_package PACKAGE\n"
+            + "  unsuspend_package PACKAGE\n"
+            + "  post [--help | flags] TAG TEXT";
+
+    private static final String NOTIFY_USAGE =
+              "usage: cmd notification post [flags] <tag> <text>\n\n"
+            + "flags:\n"
+            + "  -h|--help\n"
+            + "  -v|--verbose\n"
+            + "  -t|--title <text>\n"
+            + "  -i|--icon <iconspec>\n"
+            + "  -I|--large-icon <iconspec>\n"
+            + "  -S|--style <style> [styleargs]\n"
+            + "  -c|--content-intent <intentspec>\n"
+            + "\n"
+            + "styles: (default none)\n"
+            + "  bigtext\n"
+            + "  bigpicture --picture <iconspec>\n"
+            + "  inbox --line <text> --line <text> ...\n"
+            + "  messaging --conversation <title> --message <who>:<text> ...\n"
+            + "  media\n"
+            + "\n"
+            + "an <iconspec> is one of\n"
+            + "  file:///data/local/tmp/<img.png>\n"
+            + "  content://<provider>/<path>\n"
+            + "  @[<package>:]drawable/<img>\n"
+            + "  data:base64,<B64DATA==>\n"
+            + "\n"
+            + "an <intentspec> is (broadcast|service|activity) <args>\n"
+            + "  <args> are as described in `am start`";
+
+    public static final int NOTIFICATION_ID = 1138;
+    public static final String NOTIFICATION_PACKAGE = "com.android.shell";
+    public static final String CHANNEL_ID = "shellcmd";
+    public static final String CHANNEL_NAME = "Shell command";
+    public static final int CHANNEL_IMP = NotificationManager.IMPORTANCE_DEFAULT;
+
+    private final NotificationManagerService mDirectService;
+    private final INotificationManager mBinderService;
+
+    public NotificationShellCmd(NotificationManagerService service) {
+        mDirectService = service;
+        mBinderService = service.getBinderService();
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch (cmd.replace('-', '_')) {
+                case "allow_dnd": {
+                    mBinderService.setNotificationPolicyAccessGranted(
+                            getNextArgRequired(), true);
+                }
+                break;
+
+                case "disallow_dnd": {
+                    mBinderService.setNotificationPolicyAccessGranted(
+                            getNextArgRequired(), false);
+                }
+                break;
+                case "allow_listener": {
+                    ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+                    if (cn == null) {
+                        pw.println("Invalid listener - must be a ComponentName");
+                        return -1;
+                    }
+                    String userId = getNextArg();
+                    if (userId == null) {
+                        mBinderService.setNotificationListenerAccessGranted(cn, true);
+                    } else {
+                        mBinderService.setNotificationListenerAccessGrantedForUser(
+                                cn, Integer.parseInt(userId), true);
+                    }
+                }
+                break;
+                case "disallow_listener": {
+                    ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+                    if (cn == null) {
+                        pw.println("Invalid listener - must be a ComponentName");
+                        return -1;
+                    }
+                    String userId = getNextArg();
+                    if (userId == null) {
+                        mBinderService.setNotificationListenerAccessGranted(cn, false);
+                    } else {
+                        mBinderService.setNotificationListenerAccessGrantedForUser(
+                                cn, Integer.parseInt(userId), false);
+                    }
+                }
+                break;
+                case "allow_assistant": {
+                    ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+                    if (cn == null) {
+                        pw.println("Invalid assistant - must be a ComponentName");
+                        return -1;
+                    }
+                    mBinderService.setNotificationAssistantAccessGranted(cn, true);
+                }
+                break;
+                case "disallow_assistant": {
+                    ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+                    if (cn == null) {
+                        pw.println("Invalid assistant - must be a ComponentName");
+                        return -1;
+                    }
+                    mBinderService.setNotificationAssistantAccessGranted(cn, false);
+                }
+                break;
+                case "suspend_package": {
+                    // only use for testing
+                    mDirectService.simulatePackageSuspendBroadcast(true, getNextArgRequired());
+                }
+                break;
+                case "unsuspend_package": {
+                    // only use for testing
+                    mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
+                }
+                break;
+                case "post":
+                case "notify":
+                    doNotify(pw);
+                    break;
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (Exception e) {
+            pw.println("Error occurred. Check logcat for details. " + e.getMessage());
+            Slog.e(NotificationManagerService.TAG, "Error running shell command", e);
+        }
+        return 0;
+    }
+
+    void ensureChannel() throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        final int userid = UserHandle.getCallingUserId();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (mBinderService.getNotificationChannelForPackage(NOTIFICATION_PACKAGE,
+                    uid, CHANNEL_ID, false) == null) {
+                final NotificationChannel chan = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
+                        CHANNEL_IMP);
+                Slog.v(NotificationManagerService.TAG,
+                        "creating shell channel for user " + userid + " uid " + uid + ": " + chan);
+                mBinderService.createNotificationChannelsForPackage(NOTIFICATION_PACKAGE, uid,
+                        new ParceledListSlice<NotificationChannel>(
+                                Collections.singletonList(chan)));
+                Slog.v(NotificationManagerService.TAG, "created channel: "
+                        + mBinderService.getNotificationChannelForPackage(NOTIFICATION_PACKAGE,
+                                uid, CHANNEL_ID, false));
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    Icon parseIcon(Resources res, String encoded) throws IllegalArgumentException {
+        if (TextUtils.isEmpty(encoded)) return null;
+        if (encoded.startsWith("/")) {
+            encoded = "file://" + encoded;
+        }
+        if (encoded.startsWith("http:")
+                || encoded.startsWith("https:")
+                || encoded.startsWith("content:")
+                || encoded.startsWith("file:")
+                || encoded.startsWith("android.resource:")) {
+            Uri asUri = Uri.parse(encoded);
+            return Icon.createWithContentUri(asUri);
+        } else if (encoded.startsWith("@")) {
+            final int resid = res.getIdentifier(encoded.substring(1),
+                    "drawable", "android");
+            if (resid != 0) {
+                return Icon.createWithResource(res, resid);
+            }
+        } else if (encoded.startsWith("data:")) {
+            encoded = encoded.substring(encoded.indexOf(',') + 1);
+            byte[] bits = android.util.Base64.decode(encoded, android.util.Base64.DEFAULT);
+            return Icon.createWithData(bits, 0, bits.length);
+        }
+        return null;
+    }
+
+    private int doNotify(PrintWriter pw) throws RemoteException, URISyntaxException {
+        final Context context = mDirectService.getContext();
+        final Resources res = context.getResources();
+        final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID);
+        String opt;
+
+        boolean verbose = false;
+        Notification.BigPictureStyle bigPictureStyle = null;
+        Notification.BigTextStyle bigTextStyle = null;
+        Notification.InboxStyle inboxStyle = null;
+        Notification.MediaStyle mediaStyle = null;
+        Notification.MessagingStyle messagingStyle = null;
+
+        Icon smallIcon = null;
+        while ((opt = getNextOption()) != null) {
+            boolean large = false;
+            switch (opt) {
+                case "-v":
+                case "--verbose":
+                    verbose = true;
+                    break;
+                case "-t":
+                case "--title":
+                case "title":
+                    builder.setContentTitle(getNextArgRequired());
+                    break;
+                case "-I":
+                case "--large-icon":
+                case "--largeicon":
+                case "largeicon":
+                case "large-icon":
+                    large = true;
+                    // fall through
+                case "-i":
+                case "--icon":
+                case "icon":
+                    final String iconSpec = getNextArgRequired();
+                    final Icon icon = parseIcon(res, iconSpec);
+                    if (icon == null) {
+                        pw.println("error: invalid icon: " + iconSpec);
+                        return -1;
+                    }
+                    if (large) {
+                        builder.setLargeIcon(icon);
+                        large = false;
+                    } else {
+                        smallIcon = icon;
+                    }
+                    break;
+                case "-c":
+                case "--content-intent":
+                case "content-intent":
+                case "--intent":
+                case "intent":
+                    String intentKind = null;
+                    switch (peekNextArg()) {
+                        case "broadcast":
+                        case "service":
+                        case "activity":
+                            intentKind = getNextArg();
+                    }
+                    final Intent intent = Intent.parseCommandArgs(this, null);
+                    if (intent.getData() == null) {
+                        // force unique intents unless you know what you're doing
+                        intent.setData(Uri.parse("xyz:" + System.currentTimeMillis()));
+                    }
+                    final PendingIntent pi;
+                    if ("broadcast".equals(intentKind)) {
+                        pi = PendingIntent.getBroadcastAsUser(
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
+                                UserHandle.CURRENT);
+                    } else if ("service".equals(intentKind)) {
+                        pi = PendingIntent.getService(
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+                    } else {
+                        pi = PendingIntent.getActivityAsUser(
+                                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, null,
+                                UserHandle.CURRENT);
+                    }
+                    builder.setContentIntent(pi);
+                    break;
+                case "-S":
+                case "--style":
+                    final String styleSpec = getNextArgRequired().toLowerCase();
+                    switch (styleSpec) {
+                        case "bigtext":
+                            bigTextStyle = new Notification.BigTextStyle();
+                            builder.setStyle(bigTextStyle);
+                            break;
+                        case "bigpicture":
+                            bigPictureStyle = new Notification.BigPictureStyle();
+                            builder.setStyle(bigPictureStyle);
+                            break;
+                        case "inbox":
+                            inboxStyle = new Notification.InboxStyle();
+                            builder.setStyle(inboxStyle);
+                            break;
+                        case "messaging":
+                            String name = "You";
+                            if ("--user".equals(peekNextArg())) {
+                                getNextArg();
+                                name = getNextArgRequired();
+                            }
+                            messagingStyle = new Notification.MessagingStyle(
+                                    new Person.Builder().setName(name).build());
+                            builder.setStyle(messagingStyle);
+                            break;
+                        case "media":
+                            mediaStyle = new Notification.MediaStyle();
+                            builder.setStyle(mediaStyle);
+                            break;
+                        default:
+                            throw new IllegalArgumentException(
+                                    "unrecognized notification style: " + styleSpec);
+                    }
+                    break;
+                case "--bigText": case "--bigtext": case "--big-text":
+                    if (bigTextStyle == null) {
+                        throw new IllegalArgumentException("--bigtext requires --style bigtext");
+                    }
+                    bigTextStyle.bigText(getNextArgRequired());
+                    break;
+                case "--picture":
+                    if (bigPictureStyle == null) {
+                        throw new IllegalArgumentException("--picture requires --style bigpicture");
+                    }
+                    final String pictureSpec = getNextArgRequired();
+                    final Icon pictureAsIcon = parseIcon(res, pictureSpec);
+                    if (pictureAsIcon == null) {
+                        throw new IllegalArgumentException("bad picture spec: " + pictureSpec);
+                    }
+                    final Drawable d = pictureAsIcon.loadDrawable(context);
+                    if (d instanceof BitmapDrawable) {
+                        bigPictureStyle.bigPicture(((BitmapDrawable) d).getBitmap());
+                    } else {
+                        throw new IllegalArgumentException("not a bitmap: " + pictureSpec);
+                    }
+                    break;
+                case "--line":
+                    if (inboxStyle == null) {
+                        throw new IllegalArgumentException("--line requires --style inbox");
+                    }
+                    inboxStyle.addLine(getNextArgRequired());
+                    break;
+                case "--message":
+                    if (messagingStyle == null) {
+                        throw new IllegalArgumentException(
+                                "--message requires --style messaging");
+                    }
+                    String arg = getNextArgRequired();
+                    String[] parts = arg.split(":", 2);
+                    if (parts.length > 1) {
+                        messagingStyle.addMessage(parts[1], System.currentTimeMillis(),
+                                parts[0]);
+                    } else {
+                        messagingStyle.addMessage(parts[0], System.currentTimeMillis(),
+                                new String[]{
+                                        messagingStyle.getUserDisplayName().toString(),
+                                        "Them"
+                                }[messagingStyle.getMessages().size() % 2]);
+                    }
+                    break;
+                case "--conversation":
+                    if (messagingStyle == null) {
+                        throw new IllegalArgumentException(
+                                "--conversation requires --style messaging");
+                    }
+                    messagingStyle.setConversationTitle(getNextArgRequired());
+                    break;
+                case "-h":
+                case "--help":
+                case "--wtf":
+                default:
+                    pw.println(NOTIFY_USAGE);
+                    return 0;
+            }
+        }
+
+        final String tag = getNextArg();
+        final String text = getNextArg();
+        if (tag == null || text == null) {
+            pw.println(NOTIFY_USAGE);
+            return -1;
+        }
+
+        builder.setContentText(text);
+
+        if (smallIcon == null) {
+            // uh oh, let's substitute something
+            builder.setSmallIcon(com.android.internal.R.drawable.stat_notify_chat);
+        } else {
+            builder.setSmallIcon(smallIcon);
+        }
+
+        ensureChannel();
+
+        final Notification n = builder.build();
+        pw.println("posting:\n  " + n);
+        Slog.v("NotificationManager", "posting: " + n);
+
+        final int userId = UserHandle.getCallingUserId();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mBinderService.enqueueNotificationWithTag(
+                    NOTIFICATION_PACKAGE, "android",
+                    tag, NOTIFICATION_ID,
+                    n, userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        if (verbose) {
+            NotificationRecord nr = mDirectService.findNotificationLocked(
+                    NOTIFICATION_PACKAGE, tag, NOTIFICATION_ID, userId);
+            for (int tries = 3; tries-- > 0; ) {
+                if (nr != null) break;
+                try {
+                    pw.println("waiting for notification to post...");
+                    Thread.sleep(500);
+                } catch (InterruptedException e) {
+                }
+                nr = mDirectService.findNotificationLocked(
+                        NOTIFICATION_PACKAGE, tag, NOTIFICATION_ID, userId);
+            }
+            if (nr == null) {
+                pw.println("warning: couldn't find notification after enqueueing");
+            } else {
+                pw.println("posted: ");
+                nr.dump(pw, "  ", context, false);
+            }
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        getOutPrintWriter().println(USAGE);
+    }
+}
+
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index ee06746..2b4ec03 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -179,13 +179,19 @@
 
     List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
             final int userId) {
+        // Static RROs targeting "android" are loaded from AssetManager, and so they should be
+        // ignored in OverlayManagerService.
         return selectWhereTarget(targetPackageName, userId)
+                .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
                 .map(SettingsItem::getOverlayInfo)
                 .collect(Collectors.toList());
     }
 
     ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
+        // Static RROs targeting "android" are loaded from AssetManager, and so they should be
+        // ignored in OverlayManagerService.
         return selectWhereUser(userId)
+                .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
                 .map(SettingsItem::getOverlayInfo)
                 .collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
                         Collectors.toList()));
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 886cfb2..642bfa2 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -24,8 +24,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
-import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
@@ -91,7 +91,7 @@
         final PackageInfo pi;
         try {
             pi = mPackageManager.getPackageInfo(packageName,
-                PackageManager.GET_META_DATA, Process.SYSTEM_UID);
+                PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
 
             Context packageContext = mContext.createPackageContext(packageName, 0);
             packageResources = packageContext.getResources();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d4ee61b..d290f3f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -105,6 +105,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
+import com.android.server.pm.dex.DexManager;
 
 import libcore.io.IoUtils;
 
@@ -1594,6 +1595,16 @@
                 }
             }
         }
+        if (baseApk.preferCodeIntegrity) {
+            for (File file : mResolvedStagedFiles) {
+                if (file.getName().endsWith(".apk")
+                        && !DexManager.auditUncompressedCodeInApk(file.getPath())) {
+                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                            "Some code are not uncompressed and aligned correctly for "
+                            + mPackageName);
+                }
+            }
+        }
         if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
             throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
                     "Missing split for " + mPackageName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index da59b3e..136c7c9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -296,6 +296,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+import com.android.server.PackageWatchdog;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.SystemServerInitThreadPool;
@@ -9492,6 +9493,7 @@
         mPackageUsage.writeNow(mPackages);
         mCompilerStats.writeNow();
         mDexManager.writePackageDexUsageNow();
+        PackageWatchdog.getInstance(mContext).writeNow();
 
         // This is the last chance to write out pending restriction settings
         synchronized (mPackages) {
@@ -13021,20 +13023,26 @@
     }
 
     @Override
-    public boolean canSuspendPackageForUser(String packageName, int userId) {
+    public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
-                "canSuspendPackageForUser");
+                "getUnsuspendablePackagesForUser");
         final int callingUid = Binder.getCallingUid();
         if (UserHandle.getUserId(callingUid) != userId) {
             throw new SecurityException("Calling uid " + callingUid
-                    + " cannot query canSuspendPackageForUser for user " + userId);
+                    + " cannot query getUnsuspendablePackagesForUser for user " + userId);
         }
+        final ArraySet<String> unactionablePackages = new ArraySet<>();
         final long identity = Binder.clearCallingIdentity();
         try {
-            return canSuspendPackageForUserInternal(packageName, userId);
+            for (String packageName : packageNames) {
+                if (!canSuspendPackageForUserInternal(packageName, userId)) {
+                    unactionablePackages.add(packageName);
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
+        return unactionablePackages.toArray(new String[unactionablePackages.size()]);
     }
 
     private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 25ef767..e57d9d7 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -785,10 +785,10 @@
      * files that can be direclty mapped.
      */
     private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
-        logIfApkHasUncompressedCode(pkg.baseCodePath);
+        auditUncompressedCodeInApk(pkg.baseCodePath);
         if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
             for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                logIfApkHasUncompressedCode(pkg.splitCodePaths[i]);
+                auditUncompressedCodeInApk(pkg.splitCodePaths[i]);
             }
         }
     }
@@ -797,34 +797,41 @@
      * Generates log if the archive located at {@code fileName} has uncompressed dex file and so
      * files that can be direclty mapped.
      */
-    private static void logIfApkHasUncompressedCode(String fileName) {
+    public static boolean auditUncompressedCodeInApk(String fileName) {
         StrictJarFile jarFile = null;
         try {
             jarFile = new StrictJarFile(fileName,
                     false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
             Iterator<ZipEntry> it = jarFile.iterator();
+            boolean allCorrect = true;
             while (it.hasNext()) {
                 ZipEntry entry = it.next();
                 if (entry.getName().endsWith(".dex")) {
                     if (entry.getMethod() != ZipEntry.STORED) {
+                        allCorrect = false;
                         Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
                                 entry.getName());
                     } else if ((entry.getDataOffset() & 0x3) != 0) {
+                        allCorrect = false;
                         Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
                                 entry.getName());
                     }
                 } else if (entry.getName().endsWith(".so")) {
                     if (entry.getMethod() != ZipEntry.STORED) {
+                        allCorrect = false;
                         Slog.w(TAG, "APK " + fileName + " has compressed native code " +
                                 entry.getName());
                     } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+                        allCorrect = false;
                         Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
                                 entry.getName());
                     }
                 }
             }
+            return allCorrect;
         } catch (IOException ignore) {
             Slog.wtf(TAG, "Error when parsing APK " + fileName);
+            return false;
         } finally {
             try {
                 if (jarFile != null) {
diff --git a/services/core/java/com/android/server/slice/SliceClientPermissions.java b/services/core/java/com/android/server/slice/SliceClientPermissions.java
index e461e0d..ab94a59 100644
--- a/services/core/java/com/android/server/slice/SliceClientPermissions.java
+++ b/services/core/java/com/android/server/slice/SliceClientPermissions.java
@@ -282,9 +282,12 @@
         public synchronized void writeTo(XmlSerializer out) throws IOException {
             final int N = mPaths.size();
             for (int i = 0; i < N; i++) {
-                out.startTag(NAMESPACE, TAG_PATH);
-                out.text(encodeSegments(mPaths.valueAt(i)));
-                out.endTag(NAMESPACE, TAG_PATH);
+                final String[] segments = mPaths.valueAt(i);
+                if (segments != null) {
+                    out.startTag(NAMESPACE, TAG_PATH);
+                    out.text(encodeSegments(segments));
+                    out.endTag(NAMESPACE, TAG_PATH);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 780bc96..315d5e3 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -315,7 +315,8 @@
         return new AtomicFile(new File(mSliceDir, fileName));
     }
 
-    private void handlePersist() {
+    @VisibleForTesting
+    void handlePersist() {
         synchronized (this) {
             for (Persistable persistable : mDirty) {
                 AtomicFile file = getFile(persistable.getFileName());
@@ -335,7 +336,7 @@
 
                     out.flush();
                     file.finishWrite(stream);
-                } catch (IOException | XmlPullParserException e) {
+                } catch (IOException | XmlPullParserException | RuntimeException e) {
                     Slog.w(TAG, "Failed to save access file, restoring backup", e);
                     file.failWrite(stream);
                 }
@@ -344,6 +345,12 @@
         }
     }
 
+    // use addPersistableDirty(); this is just for tests
+    @VisibleForTesting
+    void addDirtyImmediate(Persistable obj) {
+        mDirty.add(obj);
+    }
+
     private void handleRemove(PkgUser pkgUser) {
         getFile(SliceClientPermissions.getFileName(pkgUser)).delete();
         getFile(SliceProviderPermissions.getFileName(pkgUser)).delete();
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 973499f..1f638c7 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -37,6 +37,7 @@
 import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
 import static com.android.server.am.ActivityDisplayProto.ID;
 import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
@@ -120,6 +121,9 @@
      */
     private boolean mRemoved;
 
+    /** The display can only contain one task. */
+    private boolean mSingleTaskInstance;
+
     /**
      * A focusable stack that is purposely to be positioned at the top. Although the stack may not
      * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
@@ -244,6 +248,10 @@
         final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
                 ? getFocusedStack() : null;
         final boolean wasContained = mStacks.remove(stack);
+        if (mSingleTaskInstance && getChildCount() > 0) {
+            throw new IllegalStateException(
+                    "positionChildAt: Can only have one child on display=" + this);
+        }
         final int insertPosition = getTopInsertPosition(stack, position);
         mStacks.add(insertPosition, stack);
 
@@ -403,6 +411,14 @@
      */
     <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
 
+        if (mSingleTaskInstance && getChildCount() > 0) {
+            // Create stack on default display instead since this display can only contain 1 stack.
+            // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
+            // this goes away once ActivityView is no longer using virtual displays.
+            return mRootActivityContainer.getDefaultDisplay().createStack(
+                    windowingMode, activityType, onTop);
+        }
+
         if (activityType == ACTIVITY_TYPE_UNDEFINED) {
             // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
             // anything else should be passing it in anyways...
@@ -1337,8 +1353,31 @@
         }
     }
 
+    void setDisplayToSingleTaskInstance() {
+        final int childCount = getChildCount();
+        if (childCount > 1) {
+            throw new IllegalArgumentException("Display already has multiple stacks. display="
+                    + this);
+        }
+        if (childCount > 0) {
+            final ActivityStack stack = getChildAt(0);
+            if (stack.getChildCount() > 1) {
+                throw new IllegalArgumentException("Display stack already has multiple tasks."
+                        + " display=" + this + " stack=" + stack);
+            }
+        }
+
+        mSingleTaskInstance = true;
+    }
+
+    /** Returns true if the display can only contain one task */
+    boolean isSingleTaskInstance() {
+        return mSingleTaskInstance;
+    }
+
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
+        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
+                + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
         final String myPrefix = prefix + " ";
         if (mHomeStack != null) {
             pw.println(myPrefix + "mHomeStack=" + mHomeStack);
@@ -1373,6 +1412,7 @@
         final long token = proto.start(fieldId);
         super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
         proto.write(ID, mDisplayId);
+        proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
         final ActivityStack focusedStack = getFocusedStack();
         if (focusedStack != null) {
             proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6755c73..4581a0f 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -66,6 +66,8 @@
 import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
+import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
@@ -309,7 +311,7 @@
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
      */
-    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
+    private final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -1142,6 +1144,12 @@
         }
     }
 
+    /** @return true if the stack can only contain one task */
+    boolean isSingleTaskInstance() {
+        final ActivityDisplay display = getDisplay();
+        return display != null && display.isSingleTaskInstance();
+    }
+
     final void removeActivitiesFromLRUListLocked(TaskRecord task) {
         for (ActivityRecord r : task.mActivities) {
             mLRUActivities.remove(r);
@@ -5153,6 +5161,47 @@
         }
     }
 
+    boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
+            String dumpPackage, boolean needSep) {
+        pw.println("  Stack #" + mStackId
+                + ": type=" + activityTypeToString(getActivityType())
+                + " mode=" + windowingModeToString(getWindowingMode()));
+        pw.println("  isSleeping=" + shouldSleepActivities());
+        pw.println("  mBounds=" + getRequestedOverrideBounds());
+
+        boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
+                needSep);
+
+        printed |= dumpHistoryList(fd, pw, mLRUActivities, "    ", "Run", false,
+                !dumpAll, false, dumpPackage, true,
+                "    Running activities (most recent first):", null);
+
+        needSep = printed;
+        boolean pr = printThisActivity(pw, mPausingActivity, dumpPackage, needSep,
+                "    mPausingActivity: ");
+        if (pr) {
+            printed = true;
+            needSep = false;
+        }
+        pr = printThisActivity(pw, getResumedActivity(), dumpPackage, needSep,
+                "    mResumedActivity: ");
+        if (pr) {
+            printed = true;
+            needSep = false;
+        }
+        if (dumpAll) {
+            pr = printThisActivity(pw, mLastPausedActivity, dumpPackage, needSep,
+                    "    mLastPausedActivity: ");
+            if (pr) {
+                printed = true;
+                needSep = true;
+            }
+            printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage,
+                    needSep, "    mLastNoHistoryActivity: ");
+        }
+        return printed;
+    }
+
     boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
             boolean dumpClient, String dumpPackage, boolean needSep) {
 
@@ -5172,7 +5221,7 @@
             pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
             pw.println(prefix + "* " + task);
             task.dump(pw, prefix + "  ");
-            ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
+            dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
                     prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
         }
         return true;
@@ -5241,11 +5290,6 @@
      *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
      */
     void removeTask(TaskRecord task, String reason, int mode) {
-        // TODO(b/119259346): Move some logic below to TaskRecord. See bug for more context.
-        for (ActivityRecord record : task.mActivities) {
-            onActivityRemovedFromStack(record);
-        }
-
         final boolean removed = mTaskHistory.remove(task);
 
         if (removed) {
@@ -5255,25 +5299,8 @@
         removeActivitiesFromLRUListLocked(task);
         updateTaskMovement(task, true);
 
-        if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
-            // This task is going away, so save the last state if necessary.
-            task.saveLaunchingStateIfNeeded();
-
-            // TODO: VI what about activity?
-            final boolean isVoiceSession = task.voiceSession != null;
-            if (isVoiceSession) {
-                try {
-                    task.voiceSession.taskFinished(task.intent, task.taskId);
-                } catch (RemoteException e) {
-                }
-            }
-            if (task.autoRemoveFromRecents() || isVoiceSession) {
-                // Task creator asked to remove this when done, or this task was a voice
-                // interaction, so it should not remain on the recent tasks list.
-                mStackSupervisor.mRecentTasks.remove(task);
-            }
-
-            task.removeWindowContainer();
+        if (mode == REMOVE_TASK_MODE_DESTROYING) {
+            task.cleanUpResourcesForDestroy();
         }
 
         if (mTaskHistory.isEmpty()) {
@@ -5348,6 +5375,10 @@
             String reason) {
         // TODO: Is this remove really needed? Need to look into the call path for the other addTask
         mTaskHistory.remove(task);
+        if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) {
+            throw new IllegalStateException("Can only have one child on stack=" + this);
+        }
+
         position = getAdjustedPositionForTask(task, position, null /* starting */);
         final boolean toTop = position >= mTaskHistory.size();
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c4be1ba537..86c5d4d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4569,6 +4569,26 @@
         }
     }
 
+    /**
+     * Makes the display with the given id a single task instance display. I.e the display can only
+     * contain one task.
+     */
+    @Override
+    public void setDisplayToSingleTaskInstance(int displayId) {
+        mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "setDisplayToSingleTaskInstance");
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            final ActivityDisplay display =
+                    mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+            if (display != null) {
+                display.setDisplayToSingleTaskInstance();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     void dumpLastANRLocked(PrintWriter pw) {
         pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
         if (mLastANRState == null) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 45d77de..5cfa7de 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -326,15 +326,11 @@
 
     void applySettingsToDisplayLocked(DisplayContent dc) {
         final DisplayInfo displayInfo = dc.getDisplayInfo();
-        final Entry entry = getEntry(displayInfo);
+        final Entry entry = getOrCreateEntry(displayInfo);
 
         // Setting windowing mode first, because it may override overscan values later.
         dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId()));
 
-        if (entry == null) {
-            return;
-        }
-
         displayInfo.overscanLeft = entry.mOverscanLeft;
         displayInfo.overscanTop = entry.mOverscanTop;
         displayInfo.overscanRight = entry.mOverscanRight;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 6f92e64..f55c7c9 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -29,8 +29,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.windowingModeToString;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -915,6 +913,13 @@
                     + " to its current displayId=" + displayId);
         }
 
+        if (activityDisplay.isSingleTaskInstance() && activityDisplay.getChildCount() > 0) {
+            // We don't allow moving stacks to single instance display that already has a child.
+            Slog.e(TAG, "Can not move stack=" + stack
+                    + " to single task instance display=" + activityDisplay);
+            return;
+        }
+
         stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
         // TODO(multi-display): resize stacks properly if moved from split-screen.
     }
@@ -2301,42 +2306,7 @@
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getChildAt(stackNdx);
                 pw.println();
-                pw.println("  Stack #" + stack.mStackId
-                        + ": type=" + activityTypeToString(stack.getActivityType())
-                        + " mode=" + windowingModeToString(stack.getWindowingMode()));
-                pw.println("  isSleeping=" + stack.shouldSleepActivities());
-                pw.println("  mBounds=" + stack.getRequestedOverrideBounds());
-
-                printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
-                        needSep);
-
-                printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false,
-                        !dumpAll, false, dumpPackage, true,
-                        "    Running activities (most recent first):", null);
-
-                needSep = printed;
-                boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
-                        "    mPausingActivity: ");
-                if (pr) {
-                    printed = true;
-                    needSep = false;
-                }
-                pr = printThisActivity(pw, stack.getResumedActivity(), dumpPackage, needSep,
-                        "    mResumedActivity: ");
-                if (pr) {
-                    printed = true;
-                    needSep = false;
-                }
-                if (dumpAll) {
-                    pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
-                            "    mLastPausedActivity: ");
-                    if (pr) {
-                        printed = true;
-                        needSep = true;
-                    }
-                    printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
-                            needSep, "    mLastNoHistoryActivity: ");
-                }
+                printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
                 needSep = printed;
             }
             printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep,
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 8c80009..f1b0c0696 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -481,6 +481,32 @@
         mTask = task;
     }
 
+    void cleanUpResourcesForDestroy() {
+        if (!mActivities.isEmpty()) {
+            return;
+        }
+
+        // This task is going away, so save the last state if necessary.
+        saveLaunchingStateIfNeeded();
+
+        // TODO: VI what about activity?
+        final boolean isVoiceSession = voiceSession != null;
+        if (isVoiceSession) {
+            try {
+                voiceSession.taskFinished(intent, taskId);
+            } catch (RemoteException e) {
+            }
+        }
+        if (autoRemoveFromRecents() || isVoiceSession) {
+            // Task creator asked to remove this when done, or this task was a voice
+            // interaction, so it should not remain on the recent tasks list.
+            mService.mStackSupervisor.mRecentTasks.remove(this);
+        }
+
+        removeWindowContainer();
+    }
+
+    @VisibleForTesting
     void removeWindowContainer() {
         mService.getLockTaskController().clearLockedTask(this);
         if (mTask == null) {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6d72191..b4fe837 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -111,6 +111,7 @@
         "android.hardware.light@2.0",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
+        "android.hardware.power.stats@1.0",
         "android.hardware.tetheroffload.config@1.0",
         "android.hardware.thermal@1.0",
         "android.hardware.tv.cec@1.0",
diff --git a/services/core/jni/BroadcastRadio/NativeCallbackThread.h b/services/core/jni/BroadcastRadio/NativeCallbackThread.h
index 53990be..0f62de9 100644
--- a/services/core/jni/BroadcastRadio/NativeCallbackThread.h
+++ b/services/core/jni/BroadcastRadio/NativeCallbackThread.h
@@ -41,7 +41,7 @@
     DISALLOW_COPY_AND_ASSIGN(NativeCallbackThread);
 
 public:
-    NativeCallbackThread(JavaVM *vm);
+    explicit NativeCallbackThread(JavaVM *vm);
     virtual ~NativeCallbackThread();
 
     void enqueue(const Task &task);
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 9c2e1e5..a2a7f7d 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -73,7 +73,8 @@
     wp<V1_1::ITunerCallback> mTunerCallback;
 
 public:
-    HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback):mTunerCallback(tunerCallback) {}
+    explicit HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback)
+        : mTunerCallback(tunerCallback) {}
 
     virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who);
 };
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 0ff60e4..024760d 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -27,9 +27,11 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <unordered_map>
 
 #include <android/hardware/power/1.0/IPower.h>
 #include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
 #include <android/system/suspend/1.0/ISystemSuspend.h>
 #include <android/system/suspend/1.0/ISystemSuspendCallback.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -74,6 +76,33 @@
 static jmethodID jputVoter = NULL;
 static jmethodID jputState = NULL;
 
+std::mutex gPowerHalMutex;
+std::unordered_map<uint32_t, std::string> gPowerStatsHalEntityNames = {};
+std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>>
+    gPowerStatsHalStateNames = {};
+std::vector<uint32_t> gPowerStatsHalPlatformIds = {};
+std::vector<uint32_t> gPowerStatsHalSubsystemIds = {};
+sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
+std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
+std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
+std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
+
+// The caller must be holding gPowerHalMutex.
+static void deinitPowerStatsLocked() {
+    gPowerStatsHalV1_0 = nullptr;
+}
+
+struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient {
+    virtual void serviceDied(uint64_t cookie,
+            const wp<android::hidl::base::V1_0::IBase>& who) override {
+        // The HAL just died. Reset all handles to HAL services.
+        std::lock_guard<std::mutex> lock(gPowerHalMutex);
+        deinitPowerStatsLocked();
+    }
+};
+
+sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
+
 class WakeupCallback : public ISystemSuspendCallback {
 public:
     Return<void> notifyWakeup(bool success) override {
@@ -202,18 +231,291 @@
     return mergedreasonpos - mergedreason;
 }
 
-static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats) {
-    if (jrpmStats == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException",
-                "The rpmstats jni input jobject jrpmStats is null.");
-        return;
+// The caller must be holding gPowerHalMutex.
+static bool checkResultLocked(const Return<void> &ret, const char* function) {
+    if (!ret.isOk()) {
+        ALOGE("%s failed: requested HAL service not available. Description: %s",
+            function, ret.description().c_str());
+        if (ret.isDeadObject()) {
+            deinitPowerStatsLocked();
+        }
+        return false;
     }
-    if (jgetAndUpdatePlatformState == NULL || jgetSubsystem == NULL
-            || jputVoter == NULL || jputState == NULL) {
-        ALOGE("A rpmstats jni jmethodID is null.");
+    return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+// gPowerStatsHalV1_0 must not be null
+static bool initializePowerStats() {
+    using android::hardware::power::stats::V1_0::Status;
+    using android::hardware::power::stats::V1_0::PowerEntityType;
+
+    // Clear out previous content if we are re-initializing
+    gPowerStatsHalEntityNames.clear();
+    gPowerStatsHalStateNames.clear();
+    gPowerStatsHalPlatformIds.clear();
+    gPowerStatsHalSubsystemIds.clear();
+
+    Return<void> ret;
+    ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
+        if (status != Status::SUCCESS) {
+            ALOGE("Error getting power entity info");
+            return;
+        }
+
+        // construct lookup table of powerEntityId to power entity name
+        // also construct vector of platform and subsystem IDs
+        for (auto info : infos) {
+            gPowerStatsHalEntityNames.emplace(info.powerEntityId, info.powerEntityName);
+            if (info.type == PowerEntityType::POWER_DOMAIN) {
+                gPowerStatsHalPlatformIds.emplace_back(info.powerEntityId);
+            } else {
+                gPowerStatsHalSubsystemIds.emplace_back(info.powerEntityId);
+            }
+        }
+    });
+    if (!checkResultLocked(ret, __func__)) {
+        return false;
+    }
+
+    ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
+        if (status != Status::SUCCESS) {
+            ALOGE("Error getting state info");
+            return;
+        }
+
+        // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
+        for (auto stateSpace : stateSpaces) {
+            std::unordered_map<uint32_t, std::string> stateNames = {};
+            for (auto state : stateSpace.states) {
+                stateNames.emplace(state.powerEntityStateId,
+                    state.powerEntityStateName);
+            }
+            gPowerStatsHalStateNames.emplace(stateSpace.powerEntityId, stateNames);
+        }
+    });
+    if (!checkResultLocked(ret, __func__)) {
+        return false;
+    }
+
+    return (!gPowerStatsHalEntityNames.empty()) && (!gPowerStatsHalStateNames.empty());
+}
+
+// The caller must be holding gPowerHalMutex.
+static bool getPowerStatsHalLocked() {
+    if (gPowerStatsHalV1_0 == nullptr) {
+        gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
+        if (gPowerStatsHalV1_0 == nullptr) {
+            ALOGE("Unable to get power.stats HAL service.");
+            return false;
+        }
+
+        // Link death recipient to power.stats service handle
+        hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
+        if (!linked.isOk()) {
+            ALOGE("Transaction error in linking to power.stats HAL death: %s",
+                    linked.description().c_str());
+            deinitPowerStatsLocked();
+            return false;
+        } else if (!linked) {
+            ALOGW("Unable to link to power.stats HAL death notifications");
+            // We should still continue even though linking failed
+        }
+        return initializePowerStats();
+    }
+    return true;
+}
+
+// The caller must be holding powerHalMutex.
+static void getPowerStatsHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
+    using android::hardware::power::stats::V1_0::Status;
+
+    if (!getPowerStatsHalLocked()) {
+        ALOGE("failed to get low power stats");
         return;
     }
 
+    // Get power entity state residency data
+    bool success = false;
+    Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
+        [&env, &jrpmStats, &success](auto results, auto status) {
+            if (status == Status::NOT_SUPPORTED) {
+                ALOGW("getPowerEntityStateResidencyData is not supported");
+                success = false;
+                return;
+            }
+
+            for (auto result : results) {
+                jobject jsubsystem = env->CallObjectMethod(jrpmStats, jgetSubsystem,
+                    env->NewStringUTF(gPowerStatsHalEntityNames.at(result.powerEntityId).c_str()));
+                if (jsubsystem == NULL) {
+                    ALOGE("The rpmstats jni jobject jsubsystem is null.");
+                    return;
+                }
+                for (auto stateResidency : result.stateResidencyData) {
+
+                    env->CallVoidMethod(jsubsystem, jputState,
+                        env->NewStringUTF(gPowerStatsHalStateNames.at(result.powerEntityId)
+                        .at(stateResidency.powerEntityStateId).c_str()),
+                        stateResidency.totalTimeInStateMs,
+                        stateResidency.totalStateEntryCount);
+                }
+            }
+            success = true;
+        });
+    checkResultLocked(ret, __func__);
+    if (!success) {
+        ALOGE("getPowerEntityStateResidencyData failed");
+    }
+}
+
+static jint getPowerStatsHalPlatformData(JNIEnv* env, jobject outBuf) {
+    using android::hardware::power::stats::V1_0::Status;
+    using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+    using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
+
+    if (!getPowerStatsHalLocked()) {
+        ALOGE("failed to get low power stats");
+        return -1;
+    }
+
+    char *output = (char*)env->GetDirectBufferAddress(outBuf);
+    char *offset = output;
+    int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+    int total_added = -1;
+
+    // Get power entity state residency data
+    Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
+        gPowerStatsHalPlatformIds,
+        [&offset, &remaining, &total_added](auto results, auto status) {
+            if (status == Status::NOT_SUPPORTED) {
+                ALOGW("getPowerEntityStateResidencyData is not supported");
+                return;
+            }
+
+            for (size_t i = 0; i < results.size(); i++) {
+                const PowerEntityStateResidencyResult& result = results[i];
+
+                for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
+                    const PowerEntityStateResidencyData& stateResidency =
+                        result.stateResidencyData[j];
+                    int added = snprintf(offset, remaining,
+                        "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
+                        j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
+                           .at(stateResidency.powerEntityStateId).c_str(),
+                        stateResidency.totalTimeInStateMs,
+                        stateResidency.totalStateEntryCount);
+                    if (added < 0) {
+                        break;
+                    }
+                    if (added > remaining) {
+                        added = remaining;
+                    }
+                    offset += added;
+                    remaining -= added;
+                    total_added += added;
+                }
+                if (remaining <= 0) {
+                    /* rewrite NULL character*/
+                    offset--;
+                    total_added--;
+                    ALOGE("power.stats Hal: buffer not enough");
+                    break;
+                }
+            }
+        });
+    if (!checkResultLocked(ret, __func__)) {
+        return -1;
+    }
+
+    total_added += 1;
+    return total_added;
+}
+
+static jint getPowerStatsHalSubsystemData(JNIEnv* env, jobject outBuf) {
+    using android::hardware::power::stats::V1_0::Status;
+    using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+    using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
+
+    if (!getPowerStatsHalLocked()) {
+        ALOGE("failed to get low power stats");
+        return -1;
+    }
+
+    char *output = (char*)env->GetDirectBufferAddress(outBuf);
+    char *offset = output;
+    int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+    int total_added = -1;
+
+    // Get power entity state residency data
+    Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
+        gPowerStatsHalSubsystemIds,
+        [&offset, &remaining, &total_added](auto results, auto status) {
+            if (status == Status::NOT_SUPPORTED) {
+                ALOGW("getPowerEntityStateResidencyData is not supported");
+                return;
+            }
+
+            int added = snprintf(offset, remaining, "SubsystemPowerState ");
+            offset += added;
+            remaining -= added;
+            total_added += added;
+
+            for (size_t i = 0; i < results.size(); i++) {
+                const PowerEntityStateResidencyResult& result = results[i];
+                added = snprintf(offset, remaining, "subsystem_%zu name=%s ",
+                        i + 1, gPowerStatsHalEntityNames.at(result.powerEntityId).c_str());
+                if (added < 0) {
+                    break;
+                }
+
+                if (added > remaining) {
+                    added = remaining;
+                }
+
+                offset += added;
+                remaining -= added;
+                total_added += added;
+
+                for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
+                    const PowerEntityStateResidencyData& stateResidency =
+                        result.stateResidencyData[j];
+                    added = snprintf(offset, remaining,
+                        "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry=%"
+                        PRIu64 " ", j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
+                           .at(stateResidency.powerEntityStateId).c_str(),
+                        stateResidency.totalTimeInStateMs,
+                        stateResidency.totalStateEntryCount,
+                        stateResidency.lastEntryTimestampMs);
+                    if (added < 0) {
+                        break;
+                    }
+                    if (added > remaining) {
+                        added = remaining;
+                    }
+                    offset += added;
+                    remaining -= added;
+                    total_added += added;
+                }
+                if (remaining <= 0) {
+                    /* rewrite NULL character*/
+                    offset--;
+                    total_added--;
+                    ALOGE("power.stats Hal: buffer not enough");
+                    break;
+                }
+            }
+        });
+    if (!checkResultLocked(ret, __func__)) {
+        return -1;
+    }
+
+    total_added += 1;
+    return total_added;
+}
+
+// The caller must be holding powerHalMutex.
+static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
     sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
     if (powerHalV1_0 == nullptr) {
         ALOGE("Power Hal not loaded");
@@ -286,17 +588,12 @@
     processPowerHalReturn(ret, "getSubsystemLowPowerStats");
 }
 
-static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
     char *output = (char*)env->GetDirectBufferAddress(outBuf);
     char *offset = output;
     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
     int total_added = -1;
 
-    if (outBuf == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "null argument");
-        return -1;
-    }
-
     {
         sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
         if (powerHalV1_0 == nullptr) {
@@ -365,7 +662,7 @@
     return total_added;
 }
 
-static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
     char *output = (char*)env->GetDirectBufferAddress(outBuf);
     char *offset = output;
     int remaining = (int)env->GetDirectBufferCapacity(outBuf);
@@ -374,11 +671,6 @@
     // This is a IPower 1.1 API
     sp<IPowerV1_1> powerHal_1_1 = nullptr;
 
-    if (outBuf == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "null argument");
-        return -1;
-    }
-
     {
         // Trying to get 1.1, this will succeed only for devices supporting 1.1
         powerHal_1_1 = getPowerHalV1_1();
@@ -458,6 +750,88 @@
     return total_added;
 }
 
+static void setUpPowerStatsLocked() {
+    // First see if power.stats HAL is available. Fall back to power HAL if
+    // power.stats HAL is unavailable.
+    if (android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
+        ALOGI("Using power.stats HAL");
+        gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
+        gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;
+        gGetSubsystemLowPowerStatsImpl = getPowerStatsHalSubsystemData;
+    } else if (android::hardware::power::V1_0::IPower::getService() != nullptr) {
+        ALOGI("Using power HAL");
+        gGetLowPowerStatsImpl = getPowerHalLowPowerData;
+        gGetPlatformLowPowerStatsImpl = getPowerHalPlatformData;
+        gGetSubsystemLowPowerStatsImpl = getPowerHalSubsystemData;
+    }
+}
+
+static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats) {
+    if (jrpmStats == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException",
+                "The rpmstats jni input jobject jrpmStats is null.");
+        return;
+    }
+    if (jgetAndUpdatePlatformState == NULL || jgetSubsystem == NULL
+            || jputVoter == NULL || jputState == NULL) {
+        ALOGE("A rpmstats jni jmethodID is null.");
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+    if (!gGetLowPowerStatsImpl) {
+        setUpPowerStatsLocked();
+    }
+
+    if (gGetLowPowerStatsImpl) {
+        return gGetLowPowerStatsImpl(env, jrpmStats);
+    }
+
+    ALOGE("Unable to load Power Hal or power.stats HAL");
+    return;
+}
+
+static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+    if (outBuf == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", "null argument");
+        return -1;
+    }
+
+    std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+    if (!gGetPlatformLowPowerStatsImpl) {
+        setUpPowerStatsLocked();
+    }
+
+    if (gGetPlatformLowPowerStatsImpl) {
+        return gGetPlatformLowPowerStatsImpl(env, outBuf);
+    }
+
+    ALOGE("Unable to load Power Hal or power.stats HAL");
+    return -1;
+}
+
+static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+    if (outBuf == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", "null argument");
+        return -1;
+    }
+
+    std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+    if (!gGetSubsystemLowPowerStatsImpl) {
+        setUpPowerStatsLocked();
+    }
+
+    if (gGetSubsystemLowPowerStatsImpl) {
+        return gGetSubsystemLowPowerStatsImpl(env, outBuf);
+    }
+
+    ALOGE("Unable to load Power Hal or power.stats HAL");
+    return -1;
+}
+
 static const JNINativeMethod method_table[] = {
     { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
     { "getLowPowerStats", "(Lcom/android/internal/os/RpmStats;)V", (void*)getLowPowerStats },
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index c22109c..b08d13f 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -89,7 +89,7 @@
 private:
     class HdmiCecCallback : public IHdmiCecCallback {
     public:
-        HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
+        explicit HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
         Return<void> onCecMessage(const CecMessage& event)  override;
         Return<void> onHotplugEvent(const HotplugEvent& event)  override;
     private:
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
index c8f842d..e519633 100644
--- a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -74,7 +74,7 @@
         }
     }
 
-    operator bool() {
+    explicit operator bool() {
         return mLocked;
     }
 
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 6c2a894..098b2ef 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -292,7 +292,7 @@
 
     class TvInputCallback : public ITvInputCallback {
     public:
-        TvInputCallback(JTvInputHal* hal);
+        explicit TvInputCallback(JTvInputHal* hal);
         Return<void> notify(const TvInputEvent& event) override;
     private:
         JTvInputHal* mHal;
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 7a5eaa8..f4443fe 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -20,6 +20,7 @@
         "android-support-test",
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
+        "hamcrest-library",
         "testables",
     ],
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index afbe6bc..9d84751 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -1015,6 +1015,22 @@
     }
 
     @Test
+    public void testCanceledNoisyNeverVibrate() throws Exception {
+        NotificationRecord r = getBuzzyBeepyNotification();
+
+        final int waitMs = mAudioManager.getFocusRampTimeMs(
+                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+                r.getAudioAttributes());
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.clearNotifications();
+
+        verifyNeverVibrate();
+        Thread.sleep(waitMs);
+        verifyNeverVibrate();
+    }
+    
+    @Test
     public void testEmptyUriSoundTreatedAsNoSound() throws Exception {
         NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
         channel.setSound(Uri.EMPTY, null);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
new file mode 100644
index 0000000..fa90b29
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// this is a lazy way to do in/out/err but we're not particularly interested in the output
+import static java.io.FileDescriptor.err;
+import static java.io.FileDescriptor.in;
+import static java.io.FileDescriptor.out;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.Icon;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class NotificationShellCmdTest extends UiServiceTestCase {
+    private final Binder mBinder = new Binder();
+    private final ShellCallback mCallback = new ShellCallback();
+    private final TestableContext mTestableContext = spy(getContext());
+    @Mock
+    NotificationManagerService mMockService;
+    @Mock
+    INotificationManager mMockBinderService;
+    private TestableLooper mTestableLooper;
+    private ResultReceiver mResultReceiver;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+        mResultReceiver = new ResultReceiver(new Handler(mTestableLooper.getLooper()));
+
+        when(mMockService.getContext()).thenReturn(mTestableContext);
+        when(mMockService.getBinderService()).thenReturn(mMockBinderService);
+    }
+
+    private Bitmap createTestBitmap() {
+        final Bitmap bits = Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bits);
+        final GradientDrawable grad = new GradientDrawable(GradientDrawable.Orientation.TL_BR,
+                new int[]{Color.RED, Color.YELLOW, Color.GREEN,
+                        Color.CYAN, Color.BLUE, Color.MAGENTA});
+        grad.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        grad.draw(canvas);
+        return bits;
+    }
+
+    private void doCmd(String... args) {
+        new NotificationShellCmd(mMockService)
+                .exec(mBinder, in, out, err, args, mCallback, mResultReceiver);
+    }
+
+    @Test
+    public void testNoArgs() throws Exception {
+        doCmd();
+    }
+
+    @Test
+    public void testHelp() throws Exception {
+        doCmd("--help");
+    }
+
+    Notification captureNotification(String aTag) throws Exception {
+        ArgumentCaptor<Notification> notificationCaptor =
+                ArgumentCaptor.forClass(Notification.class);
+        verify(mMockBinderService).enqueueNotificationWithTag(
+                eq(NotificationShellCmd.NOTIFICATION_PACKAGE),
+                eq("android"),
+                eq(aTag),
+                eq(NotificationShellCmd.NOTIFICATION_ID),
+                notificationCaptor.capture(),
+                eq(UserHandle.getCallingUserId()));
+        return notificationCaptor.getValue();
+    }
+
+    @Test
+    public void testBasic() throws Exception {
+        final String aTag = "aTag";
+        final String aText = "someText";
+        final String aTitle = "theTitle";
+        doCmd("notify",
+                "--title", aTitle,
+                aTag, aText);
+        final Notification captured = captureNotification(aTag);
+        assertEquals(aText, captured.extras.getString(Notification.EXTRA_TEXT));
+        assertEquals(aTitle, captured.extras.getString(Notification.EXTRA_TITLE));
+    }
+
+    @Test
+    public void testIcon() throws Exception {
+        final String aTag = "aTag";
+        final String aText = "someText";
+        doCmd("notify", "--icon", "@android:drawable/stat_sys_adb", aTag, aText);
+        final Notification captured = captureNotification(aTag);
+        final Icon icon = captured.getSmallIcon();
+        assertEquals("android", icon.getResPackage());
+        assertEquals(com.android.internal.R.drawable.stat_sys_adb, icon.getResId());
+    }
+
+    @Test
+    public void testBigText() throws Exception {
+        final String aTag = "aTag";
+        final String aText = "someText";
+        final String bigText = "someBigText";
+        doCmd("notify",
+                "--style", "bigtext",
+                "--big-text", bigText,
+                aTag, aText);
+        final Notification captured = captureNotification(aTag);
+        assertSame(captured.getNotificationStyle(), Notification.BigTextStyle.class);
+        assertEquals(aText, captured.extras.getString(Notification.EXTRA_TEXT));
+        assertEquals(bigText, captured.extras.getString(Notification.EXTRA_BIG_TEXT));
+    }
+
+    @Test
+    public void testBigPicture() throws Exception {
+        final String aTag = "aTag";
+        final String aText = "someText";
+        final String bigPicture = "@android:drawable/default_wallpaper";
+        doCmd("notify",
+                "--style", "bigpicture",
+                "--picture", bigPicture,
+                aTag, aText);
+        final Notification captured = captureNotification(aTag);
+        assertSame(captured.getNotificationStyle(), Notification.BigPictureStyle.class);
+        final Object pic = captured.extras.get(Notification.EXTRA_PICTURE);
+        assertThat(pic, instanceOf(Bitmap.class));
+    }
+
+    @Test
+    public void testInbox() throws Exception {
+        final int n = 25;
+        final String aTag = "inboxTag";
+        final String aText = "inboxText";
+        ArrayList<String> args = new ArrayList<>();
+        args.add("notify");
+        args.add("--style");
+        args.add("inbox");
+        final int startOfLineArgs = args.size();
+        for (int i = 0; i < n; i++) {
+            args.add("--line");
+            args.add(String.format("Line %02d", i));
+        }
+        args.add(aTag);
+        args.add(aText);
+
+        doCmd(args.toArray(new String[0]));
+        final Notification captured = captureNotification(aTag);
+        assertSame(captured.getNotificationStyle(), Notification.InboxStyle.class);
+        final Notification.Builder builder =
+                Notification.Builder.recoverBuilder(mContext, captured);
+        final ArrayList<CharSequence> lines =
+                ((Notification.InboxStyle) (builder.getStyle())).getLines();
+        for (int i = 0; i < n; i++) {
+            assertEquals(lines.get(i), args.get(1 + 2 * i + startOfLineArgs));
+        }
+    }
+
+    static final String[] PEOPLE = {
+            "Alice",
+            "Bob",
+            "Charlotte"
+    };
+    static final String[] MESSAGES = {
+            "Shall I compare thee to a summer's day?",
+            "Thou art more lovely and more temperate:",
+            "Rough winds do shake the darling buds of May,",
+            "And summer's lease hath all too short a date;",
+            "Sometime too hot the eye of heaven shines,",
+            "And often is his gold complexion dimm'd;",
+            "And every fair from fair sometime declines,",
+            "By chance or nature's changing course untrimm'd;",
+            "But thy eternal summer shall not fade,",
+            "Nor lose possession of that fair thou ow'st;",
+            "Nor shall death brag thou wander'st in his shade,",
+            "When in eternal lines to time thou grow'st:",
+            "   So long as men can breathe or eyes can see,",
+            "   So long lives this, and this gives life to thee.",
+    };
+
+    @Test
+    public void testMessaging() throws Exception {
+        final String aTag = "messagingTag";
+        final String aText = "messagingText";
+        ArrayList<String> args = new ArrayList<>();
+        args.add("notify");
+        args.add("--style");
+        args.add("messaging");
+        args.add("--conversation");
+        args.add("Sonnet 18");
+        final int startOfLineArgs = args.size();
+        for (int i = 0; i < MESSAGES.length; i++) {
+            args.add("--message");
+            args.add(String.format("%s:%s",
+                    PEOPLE[i % PEOPLE.length],
+                    MESSAGES[i % MESSAGES.length]));
+        }
+        args.add(aTag);
+        args.add(aText);
+
+        doCmd(args.toArray(new String[0]));
+        final Notification captured = captureNotification(aTag);
+        assertSame(Notification.MessagingStyle.class, captured.getNotificationStyle());
+        final Notification.Builder builder =
+                Notification.Builder.recoverBuilder(mContext, captured);
+        final Notification.MessagingStyle messagingStyle =
+                (Notification.MessagingStyle) (builder.getStyle());
+
+        assertEquals("Sonnet 18", messagingStyle.getConversationTitle());
+        final List<Notification.MessagingStyle.Message> messages = messagingStyle.getMessages();
+        for (int i = 0; i < messages.size(); i++) {
+            final Notification.MessagingStyle.Message m = messages.get(i);
+            assertEquals(MESSAGES[i], m.getText());
+            assertEquals(PEOPLE[i % PEOPLE.length], m.getSenderPerson().getName());
+        }
+
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index dc057d5..b315e51 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -101,4 +101,34 @@
         assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
     }
 
-}
\ No newline at end of file
+    @Test
+    public void testInvalid() throws Exception {
+        File sliceDir = new File(mContext.getCacheDir(), "slices-test");
+        if (!sliceDir.exists()) {
+            sliceDir.mkdir();
+        }
+        SlicePermissionManager permissions = new SlicePermissionManager(mContext,
+                TestableLooper.get(this).getLooper(), sliceDir);
+
+        DirtyTracker.Persistable junk = new DirtyTracker.Persistable() {
+            @Override
+            public String getFileName() {
+                return "invalidData";
+            }
+
+            @Override
+            public void writeTo(XmlSerializer out) throws IOException {
+                throw new RuntimeException("this doesn't work");
+            }
+        };
+
+        // let's put something bad in here
+        permissions.addDirtyImmediate(junk);
+        // force a persist. if this throws, it would take down system_server
+        permissions.handlePersist();
+
+        // Cleanup.
+        assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
+    }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 8e881b5..992d017 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -22,10 +22,10 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -43,11 +43,13 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.server.policy.WindowManagerPolicy;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.MockitoSession;
 
 import java.io.File;
 
@@ -94,6 +96,12 @@
     @After
     public void tearDown() {
         deleteRecursively(TEST_FOLDER);
+
+        // TODO(b/121296525): We may want to restore other display settings (not only overscans in
+        // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
+        // values after each test finishes, since we are going to reuse a singleton
+        // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
+        // (b/113239988).
     }
 
     @Test
@@ -245,21 +253,35 @@
     @Test
     public void testPersistOverscanInSameInstance() {
         final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
-        mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+        try {
+            mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */,
+                    4 /* bottom */);
 
-        mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
-        assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+            assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */,
+                    4 /* bottom */);
+        } finally {
+            mTarget.setOverscanLocked(info, 0, 0, 0, 0);
+            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        }
     }
 
     @Test
     public void testPersistOverscanAcrossInstances() {
         final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
-        mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+        try {
+            mTarget.setOverscanLocked(info, 10 /* left */, 20 /* top */, 30 /* right */,
+                    40 /* bottom */);
 
-        applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+            applySettingsToDisplayByNewInstance(mPrimaryDisplay);
 
-        assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+            assertOverscan(mPrimaryDisplay, 10 /* left */, 20 /* top */, 30 /* right */,
+                    40 /* bottom */);
+        } finally {
+            mTarget.setOverscanLocked(info, 0, 0, 0, 0);
+            mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+        }
     }
 
     @Test
@@ -389,26 +411,32 @@
         mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
                 Surface.ROTATION_0);
 
+        final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .startMocking();
         final DisplayRotation displayRotation = mock(DisplayRotation.class);
-        mPrimaryDisplay = spy(mPrimaryDisplay);
-        when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation);
+        spyOn(mPrimaryDisplay);
+        doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(false));
+        mockitoSession.finishMocking();
     }
 
     @Test
     public void testSetFixedToUserRotation() {
         mTarget.setFixedToUserRotation(mPrimaryDisplay, true);
 
+        final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+                .startMocking();
         final DisplayRotation displayRotation = mock(DisplayRotation.class);
-        mPrimaryDisplay = spy(mPrimaryDisplay);
-        when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation);
+        spyOn(mPrimaryDisplay);
+        doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
 
         applySettingsToDisplayByNewInstance(mPrimaryDisplay);
 
         verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(true));
+        mockitoSession.finishMocking();
     }
 
     private static void assertOverscan(DisplayContent display, int left, int top, int right,
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
index 5d675b7..7006075 100644
--- a/startop/view_compiler/TEST_MAPPING
+++ b/startop/view_compiler/TEST_MAPPING
@@ -2,6 +2,10 @@
   "presubmit": [
     {
       "name": "dex-builder-test"
+    },
+    {
+      "name": "view-compiler-tests",
+      "host": true
     }
   ]
 }
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 55bfdc7..609bcf3 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -32,6 +32,7 @@
 namespace {
 
 using namespace tinyxml2;
+using namespace startop::util;
 using std::string;
 
 constexpr char kStdoutFilename[]{"stdout"};
diff --git a/startop/view_compiler/util.cc b/startop/view_compiler/util.cc
index 69df41d..a0637e6 100644
--- a/startop/view_compiler/util.cc
+++ b/startop/view_compiler/util.cc
@@ -18,6 +18,9 @@
 
 using std::string;
 
+namespace startop {
+namespace util {
+
 // TODO: see if we can borrow this from somewhere else, like aapt2.
 string FindLayoutNameFromFilename(const string& filename) {
   size_t start = filename.rfind("/");
@@ -30,3 +33,6 @@
 
   return filename.substr(start, end - start);
 }
+
+}  // namespace util
+}  // namespace startop
diff --git a/startop/view_compiler/util.h b/startop/view_compiler/util.h
index 03e0939..0176175 100644
--- a/startop/view_compiler/util.h
+++ b/startop/view_compiler/util.h
@@ -13,11 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef UTIL_H_
-#define UTIL_H_
+#ifndef VIEW_COMPILER_UTIL_H_
+#define VIEW_COMPILER_UTIL_H_
 
 #include <string>
 
+namespace startop {
+namespace util {
+
 std::string FindLayoutNameFromFilename(const std::string& filename);
 
-#endif  // UTIL_H_
+}  // namespace util
+}  // namespace startop
+
+#endif  // VIEW_COMPILER_UTIL_H_
diff --git a/startop/view_compiler/util_test.cc b/startop/view_compiler/util_test.cc
index d1540d3..50682a0 100644
--- a/startop/view_compiler/util_test.cc
+++ b/startop/view_compiler/util_test.cc
@@ -20,9 +20,15 @@
 
 using std::string;
 
+namespace startop {
+namespace util {
+
 TEST(UtilTest, FindLayoutNameFromFilename) {
-  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("foo/bar.xml"));
-  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("bar.xml"));
-  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("./foo/bar.xml"));
-  EXPECT_EQ("bar", ::FindLayoutNameFromFilename("/foo/bar.xml"));
+  EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("foo/bar.xml"));
+  EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("bar.xml"));
+  EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("./foo/bar.xml"));
+  EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("/foo/bar.xml"));
 }
+
+}  // namespace util
+}  // namespace startop
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
index 1548d6e..f7c60fc 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
@@ -20,6 +20,7 @@
 import android.app.ActivityView;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.widget.Button;
 
 public class ActivityViewActivity extends Activity {
@@ -41,6 +42,10 @@
             final Intent intent = Intent.makeMainActivity(null);
             final Intent chooser = Intent.createChooser(intent,
                     "Pick an app to launch in ActivityView");
+            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] {
+                    new Intent(Intent.ACTION_MAIN)
+                            .addCategory("com.android.internal.category.PLATLOGO")
+            });
             if (intent.resolveActivity(getPackageManager()) != null) {
                 chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                         | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
new file mode 100644
index 0000000..fa2ab30
--- /dev/null
+++ b/wifi/java/android/net/wifi/DppStatusCallback.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
+ * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
+ * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
+ * Handler, DppStatusCallback)}
+ * @hide
+ */
+@SystemApi
+public abstract class DppStatusCallback {
+    /**
+     * DPP Success event: Configuration sent (Configurator mode).
+     */
+    public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+    /** @hide */
+    @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
+            DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppSuccessStatusCode {}
+
+    /**
+     * DPP Progress event: Initial authentication with peer succeeded.
+     */
+    public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+    /**
+     * DPP Progress event: Peer requires more time to process bootstrapping.
+     */
+    public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+    /** @hide */
+    @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
+            DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+            DPP_EVENT_PROGRESS_RESPONSE_PENDING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppProgressStatusCode {}
+
+    /**
+     * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
+     */
+    public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
+
+    /**
+     * DPP Failure event: Bootstrapping/Authentication initialization process failure.
+     */
+    public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
+
+    /**
+     * DPP Failure event: Both devices are implementing the same role and are incompatible.
+     */
+    public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+    /**
+     * DPP Failure event: Configuration process has failed due to malformed message.
+     */
+    public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
+
+    /**
+     * DPP Failure event: DPP request while in another DPP exchange.
+     */
+    public static final int DPP_EVENT_FAILURE_BUSY = -5;
+
+    /**
+     * DPP Failure event: No response from the peer.
+     */
+    public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
+
+    /**
+     * DPP Failure event: General protocol failure.
+     */
+    public static final int DPP_EVENT_FAILURE = -7;
+
+    /**
+     * DPP Failure event: Feature or option is not supported.
+     */
+    public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+    /**
+     * DPP Failure event: Invalid network provided to DPP configurator.
+     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+     */
+    public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+    /** @hide */
+    @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
+            DPP_EVENT_FAILURE_INVALID_URI,
+            DPP_EVENT_FAILURE_AUTHENTICATION,
+            DPP_EVENT_FAILURE_NOT_COMPATIBLE,
+            DPP_EVENT_FAILURE_CONFIGURATION,
+            DPP_EVENT_FAILURE_BUSY,
+            DPP_EVENT_FAILURE_TIMEOUT,
+            DPP_EVENT_FAILURE,
+            DPP_EVENT_FAILURE_NOT_SUPPORTED,
+            DPP_EVENT_FAILURE_INVALID_NETWORK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppFailureStatusCode {
+    }
+
+    /**
+     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
+     * peer DPP configurator. This callback marks the successful end of the DPP current DPP
+     * session, and no further callbacks will be called. This callback is the successful outcome
+     * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
+     * DppStatusCallback)}.
+     *
+     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+     */
+    public abstract void onEnrolleeSuccess(int newNetworkId);
+
+    /**
+     * Called when a DPP success event takes place, except for when configuration is received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     * This callback marks the successful end of the current DPP session, and no further
+     * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
+     * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
+     * DppStatusCallback)}.
+     *
+     * @param code DPP success status code.
+     */
+    public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
+
+    /**
+     * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
+     * current DPP session, and no further callbacks will be called.
+     *
+     * @param code DPP failure status code.
+     */
+    public abstract void onFailure(@DppFailureStatusCode int code);
+
+    /**
+     * Called when DPP events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     *
+     * @param code DPP progress status code.
+     */
+    public abstract void onProgress(@DppProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
new file mode 100644
index 0000000..c452c76
--- /dev/null
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for DPP callback.
+ *
+ * @hide
+ */
+oneway interface IDppCallback
+{
+    /**
+     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuratrion from the
+     * peer DPP configurator.
+     */
+    void onSuccessConfigReceived(int newNetworkId);
+
+    /**
+     * Called when DPP success events take place, except for when configuration is received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     */
+    void onSuccess(int status);
+
+    /**
+     * Called when DPP Failure events take place.
+     */
+    void onFailure(int status);
+
+    /**
+     * Called when DPP events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     */
+    void onProgress(int status);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0362a1b..1700006 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@
 
 import android.net.DhcpInfo;
 import android.net.Network;
+import android.net.wifi.IDppCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
@@ -199,5 +200,13 @@
     String[] getFactoryMacAddresses();
 
     void setDeviceMobilityState(int state);
+
+    void startDppAsConfiguratorInitiator(in IBinder binder, in String enrolleeUri,
+        int selectedNetworkId, int netRole, in IDppCallback callback);
+
+    void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
+        in IDppCallback callback);
+
+    void stopDppSession();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a7c2ff0..e67e8ea 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2017,6 +2017,8 @@
     public static final int WIFI_FEATURE_OWE              = 0x20000000; // Enhanced Open
     /** @hide */
     public static final int WIFI_FEATURE_LOW_LATENCY      = 0x40000000; // Low Latency modes
+    /** @hide */
+    public static final int WIFI_FEATURE_DPP              = 0x80000000; // DPP (Easy-Connect)
 
     private int getSupportedFeatures() {
         try {
@@ -4463,6 +4465,13 @@
     }
 
     /**
+     * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect)
+     */
+    public boolean isDppSupported() {
+        return isFeatureSupported(WIFI_FEATURE_DPP);
+    }
+
+    /**
      * Gets the factory Wi-Fi MAC addresses.
      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
      * if failed.
@@ -4541,4 +4550,146 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+
+    /**
+     * DPP Network role: Station.
+     * @hide
+     */
+    @SystemApi
+    public static final int DPP_NETWORK_ROLE_STA = 0;
+
+    /**
+     * DPP Network role: Access Point.
+     * @hide
+     */
+    @SystemApi
+    public static final int DPP_NETWORK_ROLE_AP = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
+            DPP_NETWORK_ROLE_STA,
+            DPP_NETWORK_ROLE_AP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DppNetworkRole {}
+
+    /**
+     * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
+     * with a peer, and configure the peer with the SSID and password of the specified network using
+     * the DPP protocol on an encrypted link.
+     *
+     * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
+     * @param selectedNetworkId Selected network ID to be sent to the peer
+     * @param enrolleeNetworkRole The network role of the enrollee
+     * @param callback Callback for status updates
+     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
+            int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
+            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
+                    enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
+     * with a peer, and receive the SSID and password from the peer configurator.
+     *
+     * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
+     * @param callback Callback for status updates
+     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
+            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
+                     new DppCallbackProxy(looper, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stop or abort a current DPP session.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void stopDppSession() {
+        try {
+            /* Request lower layers to stop/abort and clear resources */
+            mService.stopDppSession();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Helper class to support DPP callbacks
+     * @hide
+     */
+    @SystemApi
+    private static class DppCallbackProxy extends IDppCallback.Stub {
+        private final Handler mHandler;
+        private final DppStatusCallback mDppStatusCallback;
+
+        DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
+            mHandler = new Handler(looper);
+            mDppStatusCallback = dppStatusCallback;
+        }
+
+        @Override
+        public void onSuccessConfigReceived(int newNetworkId) {
+            Log.d(TAG, "DPP onSuccessConfigReceived callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+            });
+        }
+
+        @Override
+        public void onSuccess(int status) {
+            Log.d(TAG, "DPP onSuccess callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onConfiguratorSuccess(status);
+            });
+        }
+
+        @Override
+        public void onFailure(int status) {
+            Log.d(TAG, "DPP onFailure callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onFailure(status);
+            });
+        }
+
+        @Override
+        public void onProgress(int status) {
+            Log.d(TAG, "DPP onProgress callback");
+            mHandler.post(() -> {
+                mDppStatusCallback.onProgress(status);
+            });
+        }
+    }
 }