Merge "Wire "Action + Ctrl + D" to moveToNextDisplay" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 911e7de..a8b9e33 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -11240,6 +11240,7 @@
     method public void removeCategory(String);
     method public void removeExtra(String);
     method public void removeFlags(int);
+    method @FlaggedApi("android.security.prevent_intent_redirect") public void removeLaunchSecurityProtection();
     method @NonNull public android.content.Intent replaceExtras(@NonNull android.content.Intent);
     method @NonNull public android.content.Intent replaceExtras(@Nullable android.os.Bundle);
     method public android.content.ComponentName resolveActivity(@NonNull android.content.pm.PackageManager);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e7f4dbc..ed6b3d4a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -237,6 +237,7 @@
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.SafeZipPathValidatorCallback;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.DecorView;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -7675,6 +7676,16 @@
                 }
             }
         });
+
+        // Register callback to report native memory metrics post GC cleanup
+        if (Flags.reportPostgcMemoryMetrics() &&
+            com.android.libcore.readonly.Flags.postCleanupApis()) {
+            VMRuntime.addPostCleanupCallback(new Runnable() {
+                @Override public void run() {
+                    MetricsLoggerWrapper.logPostGcMemorySnapshot();
+                }
+            });
+        }
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index e882bb5..081ce31 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -345,6 +345,15 @@
      */
     public AppCompatTaskInfo appCompatTaskInfo = AppCompatTaskInfo.create();
 
+    /**
+     * The top activity's main window frame if it doesn't match the top activity bounds.
+     * {@code null}, otherwise.
+     *
+     * @hide
+     */
+    @Nullable
+    public Rect topActivityMainWindowFrame;
+
     TaskInfo() {
         // Do nothing
     }
@@ -477,7 +486,8 @@
                 && Objects.equals(capturedLink, that.capturedLink)
                 && capturedLinkTimestamp == that.capturedLinkTimestamp
                 && requestedVisibleTypes == that.requestedVisibleTypes
-                && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo);
+                && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo)
+                && Objects.equals(topActivityMainWindowFrame, that.topActivityMainWindowFrame);
     }
 
     /**
@@ -553,6 +563,7 @@
         capturedLinkTimestamp = source.readLong();
         requestedVisibleTypes = source.readInt();
         appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
+        topActivityMainWindowFrame = source.readTypedObject(Rect.CREATOR);
     }
 
     /**
@@ -606,6 +617,7 @@
         dest.writeLong(capturedLinkTimestamp);
         dest.writeInt(requestedVisibleTypes);
         dest.writeTypedObject(appCompatTaskInfo, flags);
+        dest.writeTypedObject(topActivityMainWindowFrame, flags);
     }
 
     @Override
@@ -649,6 +661,7 @@
                 + " capturedLinkTimestamp=" + capturedLinkTimestamp
                 + " requestedVisibleTypes=" + requestedVisibleTypes
                 + " appCompatTaskInfo=" + appCompatTaskInfo
+                + " topActivityMainWindowFrame=" + topActivityMainWindowFrame
                 + "}";
     }
 }
diff --git a/core/java/android/app/metrics.aconfig b/core/java/android/app/metrics.aconfig
new file mode 100644
index 0000000..488f1c7
--- /dev/null
+++ b/core/java/android/app/metrics.aconfig
@@ -0,0 +1,10 @@
+package: "android.app"
+container: "system"
+
+flag {
+     namespace: "system_performance"
+     name: "report_postgc_memory_metrics"
+     is_exported: false
+     description: "Controls whether to report memory metrics post GC cleanup"
+     bug: "331243037"
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f798523..e8cec70 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -20,6 +20,7 @@
 import static android.content.ContentProvider.maybeAddUserId;
 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
 import static android.security.Flags.FLAG_FRP_ENFORCEMENT;
+import static android.security.Flags.FLAG_PREVENT_INTENT_REDIRECT;
 import static android.security.Flags.preventIntentRedirect;
 
 import android.Manifest;
@@ -12297,6 +12298,20 @@
         mExtras.setIsIntentExtra();
     }
 
+    /**
+     * When an intent comes from another app or component as an embedded extra intent, the system
+     * creates a token to identify the creator of this foreign intent. If this token is missing or
+     * invalid, the system will block the launch of this intent. If it contains a valid token, the
+     * system will perform verification against the creator to block launching target it has no
+     * permission to launch or block it from granting URI access to the tagert it cannot access.
+     * This method provides a way to opt out this feature.
+     */
+    @FlaggedApi(FLAG_PREVENT_INTENT_REDIRECT)
+    public void removeLaunchSecurityProtection() {
+        mExtendedFlags &= ~EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN;
+        removeCreatorTokenInfo();
+    }
+
     public void writeToParcel(Parcel out, int flags) {
         out.writeString8(mAction);
         Uri.writeToParcel(out, mData);
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index ddcb5c6..6c3c285 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -24,6 +24,8 @@
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BatteryStatsHistory;
 import com.android.internal.os.BatteryStatsHistoryIterator;
 import com.android.internal.os.MonotonicClock;
@@ -43,7 +45,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Contains a snapshot of battery attribution data, on a per-subsystem and per-UID basis.
@@ -126,6 +130,12 @@
     // Max window size. CursorWindow uses only as much memory as needed.
     private static final long BATTERY_CONSUMER_CURSOR_WINDOW_SIZE = 20_000_000; // bytes
 
+    /**
+     * Used by tests to ensure all BatteryUsageStats instances are closed.
+     */
+    @VisibleForTesting
+    public static boolean DEBUG_INSTANCE_COUNT;
+
     private static final int STATSD_PULL_ATOM_MAX_BYTES = 45000;
 
     private static final int[] UID_USAGE_TIME_PROCESS_STATES = {
@@ -153,7 +163,7 @@
     private final List<UserBatteryConsumer> mUserBatteryConsumers;
     private final AggregateBatteryConsumer[] mAggregateBatteryConsumers;
     private final BatteryStatsHistory mBatteryStatsHistory;
-    private BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
+    private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
     private CursorWindow mBatteryConsumersCursorWindow;
 
     private BatteryUsageStats(@NonNull Builder builder) {
@@ -873,6 +883,7 @@
 
     @Override
     public void close() throws IOException {
+        onCursorWindowReleased(mBatteryConsumersCursorWindow);
         mBatteryConsumersCursorWindow.close();
         mBatteryConsumersCursorWindow = null;
     }
@@ -880,6 +891,7 @@
     @Override
     protected void finalize() throws Throwable {
         if (mBatteryConsumersCursorWindow != null) {
+            // Do not decrement sOpenCusorWindowCount. All instances should be closed explicitly
             mBatteryConsumersCursorWindow.close();
         }
         super.finalize();
@@ -934,6 +946,7 @@
                 boolean includesPowerStateData, double minConsumedPowerThreshold) {
             mBatteryConsumersCursorWindow =
                     new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE);
+            onCursorWindowAllocated(mBatteryConsumersCursorWindow);
             mBatteryConsumerDataLayout = BatteryConsumer.createBatteryConsumerDataLayout(
                     customPowerComponentNames, includePowerModels, includeProcessStateData,
                     includeScreenStateData, includesPowerStateData);
@@ -996,6 +1009,7 @@
          */
         public void discard() {
             mBatteryConsumersCursorWindow.close();
+            onCursorWindowReleased(mBatteryConsumersCursorWindow);
         }
 
         /**
@@ -1264,4 +1278,50 @@
             }
         }
     }
+
+    @GuardedBy("BatteryUsageStats.class")
+    private static Map<CursorWindow, Exception> sInstances;
+
+    private static void onCursorWindowAllocated(CursorWindow window) {
+        if (!DEBUG_INSTANCE_COUNT) {
+            return;
+        }
+
+        synchronized (BatteryUsageStats.class) {
+            if (sInstances == null) {
+                sInstances = new HashMap<>();
+            }
+            sInstances.put(window, new Exception());
+        }
+    }
+
+    private static void onCursorWindowReleased(CursorWindow window) {
+        if (!DEBUG_INSTANCE_COUNT) {
+            return;
+        }
+
+        synchronized (BatteryUsageStats.class) {
+            sInstances.remove(window);
+        }
+    }
+
+    /**
+     * Used by tests to ensure all BatteryUsageStats instances are closed.
+     */
+    @VisibleForTesting
+    public static void assertAllInstancesClosed() {
+        if (!DEBUG_INSTANCE_COUNT) {
+            throw new IllegalStateException("DEBUG_INSTANCE_COUNT is false");
+        }
+
+        synchronized (BatteryUsageStats.class) {
+            if (!sInstances.isEmpty()) {
+                Exception callSite = sInstances.entrySet().iterator().next().getValue();
+                int count = sInstances.size();
+                sInstances.clear();
+                throw new IllegalStateException(
+                        "Instances of BatteryUsageStats not closed: " + count, callSite);
+            }
+        }
+    }
 }
diff --git a/core/java/android/security/forensic/ForensicEvent.aidl b/core/java/android/security/forensic/ForensicEvent.aidl
new file mode 100644
index 0000000..a321fb0
--- /dev/null
+++ b/core/java/android/security/forensic/ForensicEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2024 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.security.forensic;
+
+/** {@hide} */
+parcelable ForensicEvent;
diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/forensic/ForensicEvent.java
new file mode 100644
index 0000000..9cbc5ec
--- /dev/null
+++ b/core/java/android/security/forensic/ForensicEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 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.security.forensic;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.security.Flags;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * A class that represents a forensic event.
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_AFL_API)
+public final class ForensicEvent implements Parcelable {
+    private static final String TAG = "ForensicEvent";
+
+    @NonNull
+    private final String mType;
+
+    @NonNull
+    private final Map<String, String> mKeyValuePairs;
+
+    public static final @NonNull Parcelable.Creator<ForensicEvent> CREATOR =
+            new Parcelable.Creator<>() {
+                public ForensicEvent createFromParcel(Parcel in) {
+                    return new ForensicEvent(in);
+                }
+
+                public ForensicEvent[] newArray(int size) {
+                    return new ForensicEvent[size];
+                }
+            };
+
+    public ForensicEvent(@NonNull String type, @NonNull Map<String, String> keyValuePairs) {
+        mType = type;
+        mKeyValuePairs = keyValuePairs;
+    }
+
+    private ForensicEvent(@NonNull Parcel in) {
+        mType = in.readString();
+        mKeyValuePairs = new ArrayMap<>(in.readInt());
+        in.readMap(mKeyValuePairs, getClass().getClassLoader(), String.class, String.class);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeString(mType);
+        out.writeInt(mKeyValuePairs.size());
+        out.writeMap(mKeyValuePairs);
+    }
+
+    @FlaggedApi(Flags.FLAG_AFL_API)
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "ForensicEvent{"
+                + "mType=" + mType
+                + ", mKeyValuePairs=" + mKeyValuePairs
+                + '}';
+    }
+}
diff --git a/core/java/android/security/forensic/IBackupTransport.aidl b/core/java/android/security/forensic/IBackupTransport.aidl
new file mode 100644
index 0000000..c2cbc83
--- /dev/null
+++ b/core/java/android/security/forensic/IBackupTransport.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2024 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.security.forensic;
+import android.security.forensic.ForensicEvent;
+
+import com.android.internal.infra.AndroidFuture;
+
+/** {@hide} */
+oneway interface IBackupTransport {
+    /**
+     * Initialize the server side.
+     */
+    void initialize(in AndroidFuture<int> resultFuture);
+
+    /**
+     * Send forensic logging data to the backup destination.
+     * The data is a list of ForensicEvent.
+     * The ForensicEvent is an abstract class that represents
+     * different type of events.
+     */
+    void addData(in List<ForensicEvent> events, in AndroidFuture<int> resultFuture);
+
+    /**
+     * Release the binder to the server.
+     */
+    void release(in AndroidFuture<int> resultFuture);
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 07aa720..b56aadd 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -1770,6 +1770,10 @@
 
     @GuardedBy("this")
     private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
+        if (cur.eventCode != HistoryItem.EVENT_NONE && cur.eventTag.string == null) {
+            Slog.wtfStack(TAG, "Event " + Integer.toHexString(cur.eventCode) + " without a name");
+        }
+
         if (mTracer != null && mTracer.tracingEnabled()) {
             recordTraceEvents(cur.eventCode, cur.eventTag);
             recordTraceCounters(mTraceLastState, cur.states, STATE1_TRACE_MASK,
@@ -2266,6 +2270,7 @@
     private int writeHistoryTag(HistoryTag tag) {
         if (tag.string == null) {
             Slog.wtfStack(TAG, "writeHistoryTag called with null name");
+            tag.string = "";
         }
 
         final int stringLength = tag.string.length();
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index dfb2884..489721f 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -105,7 +105,7 @@
         public void setValues(long[] array) {
             if (array.length != mLength) {
                 throw new IllegalArgumentException(
-                        "Invalid array length: " + mLength + ", expected: " + mLength);
+                        "Invalid array length: " + array.length + ", expected: " + mLength);
             }
             native_setValues(mNativeObject, array);
         }
@@ -116,7 +116,7 @@
         public void getValues(long[] array) {
             if (array.length != mLength) {
                 throw new IllegalArgumentException(
-                        "Invalid array length: " + mLength + ", expected: " + mLength);
+                        "Invalid array length: " + array.length + ", expected: " + mLength);
             }
             native_getValues(mNativeObject, array);
         }
@@ -347,6 +347,11 @@
             throw new IllegalArgumentException(
                     "State: " + state + ", outside the range: [0-" + mStateCount + "]");
         }
+        if (longArrayContainer.mLength != mLength) {
+            throw new IllegalArgumentException(
+                    "Invalid array length: " + longArrayContainer.mLength
+                            + ", expected: " + mLength);
+        }
         native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
     }
 
diff --git a/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java b/core/java/com/android/internal/os/ProcfsMemoryUtil.java
similarity index 60%
rename from services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java
rename to core/java/com/android/internal/os/ProcfsMemoryUtil.java
index 6cb6dc0..382f6c4 100644
--- a/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java
+++ b/core/java/com/android/internal/os/ProcfsMemoryUtil.java
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server.stats.pull;
+package com.android.internal.os;
 
-import static android.os.Process.PROC_OUT_STRING;
+import static android.os.Process.*;
 
 import android.annotation.Nullable;
 import android.os.Process;
@@ -23,6 +23,7 @@
 
 public final class ProcfsMemoryUtil {
     private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING };
+    private static final int[] OOM_SCORE_ADJ_OUT = new int[] { PROC_NEWLINE_TERM | PROC_OUT_LONG };
     private static final String[] STATUS_KEYS = new String[] {
             "Uid:",
             "VmHWM:",
@@ -38,17 +39,34 @@
     private ProcfsMemoryUtil() {}
 
     /**
-     * Reads memory stats of a process from procfs. Returns values of the VmHWM, VmRss, AnonRSS,
-     * VmSwap, RssShmem fields in /proc/pid/status in kilobytes or null if not available.
+     * Reads memory stats of a process from procfs.
+     *
+     * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in
+     * /proc/pid/status in kilobytes or null if not available.
      */
     @Nullable
     public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
+        return readMemorySnapshotFromProcfs("/proc/" + pid + "/status");
+    }
+
+    /**
+     * Reads memory stats of the current process from procfs.
+     *
+     * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in
+     * /proc/self/status in kilobytes or null if not available.
+     */
+    @Nullable
+    public static MemorySnapshot readMemorySnapshotFromProcfs() {
+        return readMemorySnapshotFromProcfs("/proc/self/status");
+    }
+
+    private static MemorySnapshot readMemorySnapshotFromProcfs(String path) {
         long[] output = new long[STATUS_KEYS.length];
         output[0] = -1;
         output[3] = -1;
         output[4] = -1;
         output[5] = -1;
-        Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output);
+        Process.readProcLines(path, STATUS_KEYS, output);
         if (output[0] == -1 || output[3] == -1 || output[4] == -1 || output[5] == -1) {
             // Could not open or parse file.
             return null;
@@ -70,14 +88,54 @@
      * if the file is not available.
      */
     public static String readCmdlineFromProcfs(int pid) {
+        return readCmdlineFromProcfs("/proc/" + pid + "/cmdline");
+    }
+
+    /**
+     * Reads cmdline of the current process from procfs.
+     *
+     * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
+     * if the file is not available.
+     */
+    public static String readCmdlineFromProcfs() {
+        return readCmdlineFromProcfs("/proc/self/cmdline");
+    }
+
+    private static String readCmdlineFromProcfs(String path) {
         String[] cmdline = new String[1];
-        if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) {
+        if (!Process.readProcFile(path, CMDLINE_OUT, cmdline, null, null)) {
             return "";
         }
         return cmdline[0];
     }
 
     /**
+     * Reads oom_score_adj of a process from procfs
+     *
+     * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails.
+     */
+    public static int readOomScoreAdjFromProcfs(int pid) {
+        return readOomScoreAdjFromProcfs("/proc/" + pid + "/oom_score_adj");
+    }
+
+    /**
+     * Reads oom_score_adj of the current process from procfs
+     *
+     * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails.
+     */
+    public static int readOomScoreAdjFromProcfs() {
+        return readOomScoreAdjFromProcfs("/proc/self/oom_score_adj");
+    }
+
+    private static int readOomScoreAdjFromProcfs(String path) {
+        long[] oom_score_adj = new long[1];
+        if (Process.readProcFile(path, OOM_SCORE_ADJ_OUT, null, oom_score_adj, null)) {
+            return (int)oom_score_adj[0];
+        }
+        return 0;
+    }
+
+    /**
      * Scans all /proc/pid/cmdline entries and returns a mapping between pid and cmdline.
      */
     public static SparseArray<String> getProcessCmdlines() {
@@ -109,7 +167,7 @@
 
     /** Reads and parses selected entries of /proc/vmstat. */
     @Nullable
-    static VmStat readVmStat() {
+    public static VmStat readVmStat() {
         long[] vmstat = new long[VMSTAT_KEYS.length];
         vmstat[0] = -1;
         Process.readProcLines("/proc/vmstat", VMSTAT_KEYS, vmstat);
@@ -121,7 +179,7 @@
         return result;
     }
 
-    static final class VmStat {
+    public static final class VmStat {
         public int oomKillCount;
     }
 }
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index b42ea7d..e2237f6 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -16,9 +16,15 @@
 
 package com.android.internal.os.logging;
 
+import android.app.Application;
+import android.os.Process;
+import android.util.Log;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.internal.os.ProcfsMemoryUtil;
 import com.android.internal.util.FrameworkStatsLog;
+import java.util.Collection;
+import libcore.util.NativeAllocationRegistry;
 
 /**
  * Used to wrap different logging calls in one, so that client side code base is clean and more
@@ -49,4 +55,46 @@
             }
         }
     }
+
+    public static void logPostGcMemorySnapshot() {
+        if (!com.android.libcore.Flags.nativeMetrics()) {
+            return;
+        }
+        int pid = Process.myPid();
+        String processName = Application.getProcessName();
+        Collection<NativeAllocationRegistry.Metrics> metrics =
+            NativeAllocationRegistry.getMetrics();
+        int nMetrics = metrics.size();
+
+        String[] classNames = new String[nMetrics];
+        long[] mallocedCount = new long[nMetrics];
+        long[] mallocedBytes = new long[nMetrics];
+        long[] nonmallocedCount = new long[nMetrics];
+        long[] nonmallocedBytes = new long[nMetrics];
+
+        int i = 0;
+        for (NativeAllocationRegistry.Metrics m : metrics) {
+            classNames[i] = m.getClassName();
+            mallocedCount[i] = m.getMallocedCount();
+            mallocedBytes[i] = m.getMallocedBytes();
+            nonmallocedCount[i] = m.getNonmallocedCount();
+            nonmallocedBytes[i] = m.getNonmallocedBytes();
+            i++;
+        }
+
+        ProcfsMemoryUtil.MemorySnapshot m = ProcfsMemoryUtil.readMemorySnapshotFromProcfs();
+        int oom_score_adj = ProcfsMemoryUtil.readOomScoreAdjFromProcfs();
+        FrameworkStatsLog.write(FrameworkStatsLog.POSTGC_MEMORY_SNAPSHOT,
+            m.uid, processName, pid,
+            oom_score_adj,
+            m.rssInKilobytes,
+            m.anonRssInKilobytes,
+            m.swapInKilobytes,
+            m.anonRssInKilobytes + m.swapInKilobytes,
+            classNames,
+            mallocedCount,
+            mallocedBytes,
+            nonmallocedCount,
+            nonmallocedBytes);
+    }
 }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4198171..42ac90dd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7175,4 +7175,7 @@
     <string name="identity_check_settings_action"></string>
     <!-- Package for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] -->
     <string name="identity_check_settings_package_name">com\u002eandroid\u002esettings</string>
+
+    <!-- The name of the service for forensic backup transport. -->
+    <string name="config_forensicBackupTransport" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0b2b345..dfee85a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5636,4 +5636,7 @@
   <!-- Identity check strings -->
   <java-symbol type="string" name="identity_check_settings_action" />
   <java-symbol type="string" name="identity_check_settings_package_name" />
+
+  <!-- Forensic backup transport -->
+  <java-symbol type="string" name="config_forensicBackupTransport" />
 </resources>
diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp
index 4edf52b..0964aab 100644
--- a/data/fonts/Android.bp
+++ b/data/fonts/Android.bp
@@ -53,22 +53,9 @@
     name: "use_var_font",
 }
 
-soong_config_module_type {
-    name: "prebuilt_fonts_xml",
-    module_type: "prebuilt_etc",
-    config_namespace: "noto_sans_cjk_config",
-    bool_variables: ["use_var_font"],
-    properties: ["src"],
-}
-
-prebuilt_fonts_xml {
+prebuilt_etc {
     name: "fonts.xml",
     src: "fonts.xml",
-    soong_config_variables: {
-        use_var_font: {
-            src: "fonts_cjkvf.xml",
-        },
-    },
 }
 
 prebuilt_etc {
diff --git a/data/fonts/font_fallback.xml b/data/fonts/font_fallback.xml
deleted file mode 100644
index ae50da1..0000000
--- a/data/fonts/font_fallback.xml
+++ /dev/null
@@ -1,950 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    In this file, all fonts without names are added to the default list.
-    Fonts are chosen based on a match: full BCP-47 language tag including
-    script, then just language, and finally order (the first font containing
-    the glyph).
-
-    Order of appearance is also the tiebreaker for weight matching. This is
-    the reason why the 900 weights of Roboto precede the 700 weights - we
-    prefer the former when an 800 weight is requested. Since bold spans
-    effectively add 300 to the weight, this ensures that 900 is the bold
-    paired with the 500 weight, ensuring adequate contrast.
-
-
-    The font_fallback.xml defines the list of font used by the system.
-
-    `familyset` node:
-      A `familyset` element must be a root node of the font_fallback.xml. No attributes are allowed
-      to `familyset` node.
-      The `familyset` node can contains `family` and `alias` nodes. Any other nodes will be ignored.
-
-    `family` node:
-      A `family` node defines a single font family definition.
-      A font family is a set of fonts for drawing text in various styles such as weight, slant.
-      There are three types of families, default family, named family and locale fallback family.
-
-      The default family is a special family node appeared the first node of the `familyset` node.
-      The default family is used as first priority fallback.
-      Only `name` attribute can be used for default family node. If the `name` attribute is
-      specified, This family will also works as named family.
-
-      The named family is a family that has name attribute. The named family defines a new fallback.
-      For example, if the name attribute is "serif", it creates serif fallback. Developers can
-      access the fallback by using Typeface#create API.
-      The named family can not have attribute other than `name` attribute. The `name` attribute
-      cannot be empty.
-
-      The locale fallback family is a font family that is used for fallback. The fallback family is
-      used when the named family or default family cannot be used. The locale fallback family can
-      have `lang` attribute and `variant` attribute. The `lang` attribute is an optional comma
-      separated BCP-47i language tag. The `variant` is an optional attribute that can be one one
-      `element`, `compact`. If a `variant` attribute is not specified, it is treated as default.
-
-    `alias` node:
-      An `alias` node defines a alias of named family with changing weight offset. An `alias` node
-      can have mandatory `name` and `to` attribute and optional `weight` attribute. This `alias`
-      defines new fallback that has the name of specified `name` attribute. The fallback list is
-      the same to the fallback that of the name specified with `to` attribute. If `weight` attribute
-      is specified, the base weight offset is shifted to the specified value. For example, if the
-      `weight` is 500, the output text is drawn with 500 of weight.
-
-    `font` node:
-      A `font` node defines a single font definition. There are two types of fonts, static font and
-      variable font.
-
-      A static font can have `weight`, `style`, `index` and `postScriptName` attributes. A `weight`
-      is a mandatory attribute that defines the weight of the font. Any number between 0 to 1000 is
-      valid. A `style` is a mandatory attribute that defines the style of the font. A 'style'
-      attribute can be `normal` or `italic`. An `index` is an optional attribute that defines the
-      index of the font collection. If this is not specified, it is treated as 0. If the font file
-      is not a font collection, this attribute is ignored. A `postScriptName` attribute is an
-      optional attribute. A PostScript name is used for identifying target of system font update.
-      If this is not specified, the system assumes the filename is same to PostScript name of the
-      font file. For example, if the font file is "Roboto-Regular.ttf", the system assume the
-      PostScript name of this font is "Roboto-Regular".
-
-      A variable font can be only defined for the variable font file. A variable font can have
-      `axis` child nodes for specifying axis values. A variable font can have all attribute of
-      static font and can have additional `supportedAxes` attribute. A `supportedAxes` attribute
-      is a comma separated supported axis tags. As of Android V, only `wght` and `ital` axes can
-      be specified.
-
-      If `supportedAxes` attribute is not specified, this `font` node works as static font of the
-      single instance of variable font specified with `axis` children.
-
-      If `supportedAxes` attribute is specified, the system dynamically create font instance for the
-      given weight and style value. If `wght` is specified in `supportedAxes` attribute the `weight`
-      attribute and `axis` child that has `wght` tag become optional and ignored because it is
-      determined by system at runtime. Similarly, if `ital` is specified in `supportedAxes`
-      attribute, the `style` attribute and `axis` child that has `ital` tag become optional and
-      ignored.
-
-    `axis` node:
-      An `axis` node defines a font variation value for a tag. An `axis` node can have two mandatory
-      attributes, `tag` and `value`. If the font is variable font and the same tag `axis` node is
-      specified in `supportedAxes` attribute, the style value works like a default instance.
--->
-<familyset>
-    <!-- first font is default -->
-    <family name="sans-serif">
-        <font supportedAxes="wght,ital">Roboto-Regular.ttf
-          <axis tag="wdth" stylevalue="100" />
-        </font>
-   </family>
-
-
-    <!-- Note that aliases must come after the fonts they reference. -->
-    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
-    <alias name="sans-serif-light" to="sans-serif" weight="300" />
-    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
-    <alias name="sans-serif-black" to="sans-serif" weight="900" />
-    <alias name="arial" to="sans-serif" />
-    <alias name="helvetica" to="sans-serif" />
-    <alias name="tahoma" to="sans-serif" />
-    <alias name="verdana" to="sans-serif" />
-
-    <family name="sans-serif-condensed">
-      <font supportedAxes="wght,ital">Roboto-Regular.ttf
-        <axis tag="wdth" stylevalue="75" />
-      </font>
-    </family>
-    <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
-    <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
-
-    <family name="serif">
-        <font weight="400" style="normal" postScriptName="NotoSerif">NotoSerif-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
-        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
-        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
-    </family>
-    <alias name="serif-bold" to="serif" weight="700" />
-    <alias name="times" to="serif" />
-    <alias name="times new roman" to="serif" />
-    <alias name="palatino" to="serif" />
-    <alias name="georgia" to="serif" />
-    <alias name="baskerville" to="serif" />
-    <alias name="goudy" to="serif" />
-    <alias name="fantasy" to="serif" />
-    <alias name="ITC Stone Serif" to="serif" />
-
-    <family name="monospace">
-        <font weight="400" style="normal">DroidSansMono.ttf</font>
-    </family>
-    <alias name="sans-serif-monospace" to="monospace" />
-    <alias name="monaco" to="monospace" />
-
-    <family name="serif-monospace">
-        <font weight="400" style="normal" postScriptName="CutiveMono-Regular">CutiveMono.ttf</font>
-    </family>
-    <alias name="courier" to="serif-monospace" />
-    <alias name="courier new" to="serif-monospace" />
-
-    <family name="casual">
-        <font weight="400" style="normal" postScriptName="ComingSoon-Regular">ComingSoon.ttf</font>
-    </family>
-
-    <family name="cursive">
-      <font supportedAxes="wght">DancingScript-Regular.ttf</font>
-    </family>
-
-    <family name="sans-serif-smallcaps">
-        <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
-    </family>
-
-    <family name="source-sans-pro">
-        <font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
-        <font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
-        <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font>
-        <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font>
-        <font weight="700" style="normal">SourceSansPro-Bold.ttf</font>
-        <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font>
-    </family>
-    <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/>
-
-    <family name="roboto-flex">
-        <font supportedAxes="wght">RobotoFlex-Regular.ttf
-          <axis tag="wdth" stylevalue="100" />
-        </font>
-    </family>
-
-    <!-- fallback fonts -->
-    <family lang="und-Arab" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabic">
-            NotoNaskhArabic-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
-    </family>
-    <family lang="und-Arab" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabicUI">
-            NotoNaskhArabicUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Ethi">
-        <font postScriptName="NotoSansEthiopic-Regular" supportedAxes="wght">
-            NotoSansEthiopic-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifEthiopic-Regular" supportedAxes="wght">
-            NotoSerifEthiopic-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Hebr">
-        <font weight="400" style="normal" postScriptName="NotoSansHebrew">
-            NotoSansHebrew-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansThai">NotoSansThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansThaiUI">
-            NotoSansThaiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Armn">
-        <font postScriptName="NotoSansArmenian-Regular" supportedAxes="wght">
-            NotoSansArmenian-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifArmenian-Regular" supportedAxes="wght">
-            NotoSerifArmenian-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Geor,und-Geok">
-        <font postScriptName="NotoSansGeorgian-Regular" supportedAxes="wght">
-            NotoSansGeorgian-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifGeorgian-Regular" supportedAxes="wght">
-            NotoSerifGeorgian-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Deva" variant="elegant">
-        <font postScriptName="NotoSansDevanagari-Regular" supportedAxes="wght">
-            NotoSansDevanagari-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifDevanagari-Regular" supportedAxes="wght">
-            NotoSerifDevanagari-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Deva" variant="compact">
-        <font postScriptName="NotoSansDevanagariUI-Regular" supportedAxes="wght">
-            NotoSansDevanagariUI-VF.ttf
-        </font>
-    </family>
-
-    <!-- All scripts of India should come after Devanagari, due to shared
-         danda characters.
-    -->
-    <family lang="und-Gujr" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansGujarati">
-            NotoSansGujarati-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
-        <font style="normal" fallbackFor="serif" postScriptName="NotoSerifGujarati-Regular"
-          supportedAxes="wght">
-          NotoSerifGujarati-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Gujr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansGujaratiUI">
-            NotoSansGujaratiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Guru" variant="elegant">
-        <font postScriptName="NotoSansGurmukhi-Regular" supportedAxes="wght">
-            NotoSansGurmukhi-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifGurmukhi-Regular" supportedAxes="wght">
-            NotoSerifGurmukhi-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Guru" variant="compact">
-        <font postScriptName="NotoSansGurmukhiUI-Regular" supportedAxes="wght">
-            NotoSansGurmukhiUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Taml" variant="elegant">
-        <font postScriptName="NotoSansTamil-Regular" supportedAxes="wght">
-            NotoSansTamil-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifTamil-Regular" supportedAxes="wght">
-            NotoSerifTamil-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Taml" variant="compact">
-        <font postScriptName="NotoSansTamilUI-Regular" supportedAxes="wght">
-            NotoSansTamilUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="elegant">
-        <font postScriptName="NotoSansMalayalam-Regular" supportedAxes="wght">
-            NotoSansMalayalam-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifMalayalam-Regular" supportedAxes="wght">
-            NotoSerifMalayalam-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="compact">
-        <font postScriptName="NotoSansMalayalamUI-Regular" supportedAxes="wght">
-            NotoSansMalayalamUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Beng" variant="elegant">
-        <font postScriptName="NotoSansBengali-Regular" supportedAxes="wght">
-            NotoSansBengali-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifBengali-Regular" supportedAxes="wght">
-            NotoSerifBengali-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Beng" variant="compact">
-        <font postScriptName="NotoSansBengaliUI-Regular" supportedAxes="wght">
-            NotoSansBengaliUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Telu" variant="elegant">
-        <font postScriptName="NotoSansTelugu-Regular" supportedAxes="wght">
-            NotoSansTelugu-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifTelugu-Regular" supportedAxes="wght">
-            NotoSerifTelugu-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Telu" variant="compact">
-        <font postScriptName="NotoSansTeluguUI-Regular" supportedAxes="wght">
-            NotoSansTeluguUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Knda" variant="elegant">
-        <font postScriptName="NotoSansKannada-Regular" supportedAxes="wght">
-            NotoSansKannada-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifKannada-Regular" supportedAxes="wght">
-            NotoSerifKannada-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Knda" variant="compact">
-        <font postScriptName="NotoSansKannadaUI-Regular" supportedAxes="wght">
-            NotoSansKannadaUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Orya" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansOriya">NotoSansOriya-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
-    </family>
-    <family lang="und-Orya" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansOriyaUI">
-            NotoSansOriyaUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Sinh" variant="elegant">
-        <font postScriptName="NotoSansSinhala-Regular" supportedAxes="wght">
-            NotoSansSinhala-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifSinhala-Regular" supportedAxes="wght">
-            NotoSerifSinhala-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Sinh" variant="compact">
-        <font postScriptName="NotoSansSinhalaUI-Regular" supportedAxes="wght">
-            NotoSansSinhalaUI-VF.ttf
-        </font>
-    </family>
-    <!-- TODO: NotoSansKhmer uses non-standard wght value, so cannot use auto-adjustment. -->
-    <family lang="und-Khmr" variant="elegant">
-        <font weight="100" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="26.0"/>
-        </font>
-        <font weight="200" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="39.0"/>
-        </font>
-        <font weight="300" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="58.0"/>
-        </font>
-        <font weight="400" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="90.0"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="108.0"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="128.0"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="151.0"/>
-        </font>
-        <font weight="800" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="169.0"/>
-        </font>
-        <font weight="900" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="190.0"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
-    </family>
-    <family lang="und-Khmr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansKhmerUI">
-            NotoSansKhmerUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="elegant">
-        <font weight="400" style="normal">NotoSansLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansLaoUI">NotoSansLaoUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Mymr" variant="elegant">
-        <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
-    </family>
-    <family lang="und-Mymr" variant="compact">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
-    </family>
-    <family lang="und-Thaa">
-        <font weight="400" style="normal" postScriptName="NotoSansThaana">
-            NotoSansThaana-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
-    </family>
-    <family lang="und-Cham">
-        <font weight="400" style="normal" postScriptName="NotoSansCham">NotoSansCham-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
-    </family>
-    <family lang="und-Ahom">
-        <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
-    </family>
-    <family lang="und-Adlm">
-        <font postScriptName="NotoSansAdlam-Regular" supportedAxes="wght">
-            NotoSansAdlam-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Avst">
-        <font weight="400" style="normal" postScriptName="NotoSansAvestan">
-            NotoSansAvestan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bali">
-        <font weight="400" style="normal" postScriptName="NotoSansBalinese">
-            NotoSansBalinese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bamu">
-        <font weight="400" style="normal" postScriptName="NotoSansBamum">NotoSansBamum-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Batk">
-        <font weight="400" style="normal" postScriptName="NotoSansBatak">NotoSansBatak-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Brah">
-        <font weight="400" style="normal" postScriptName="NotoSansBrahmi">
-            NotoSansBrahmi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bugi">
-        <font weight="400" style="normal" postScriptName="NotoSansBuginese">
-            NotoSansBuginese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Buhd">
-        <font weight="400" style="normal" postScriptName="NotoSansBuhid">NotoSansBuhid-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cans">
-        <font weight="400" style="normal">
-            NotoSansCanadianAboriginal-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cari">
-        <font weight="400" style="normal" postScriptName="NotoSansCarian">
-            NotoSansCarian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cakm">
-        <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
-    </family>
-    <family lang="und-Cher">
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
-    </family>
-    <family lang="und-Copt">
-        <font weight="400" style="normal" postScriptName="NotoSansCoptic">
-            NotoSansCoptic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xsux">
-        <font weight="400" style="normal" postScriptName="NotoSansCuneiform">
-            NotoSansCuneiform-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cprt">
-        <font weight="400" style="normal" postScriptName="NotoSansCypriot">
-            NotoSansCypriot-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Dsrt">
-        <font weight="400" style="normal" postScriptName="NotoSansDeseret">
-            NotoSansDeseret-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Egyp">
-        <font weight="400" style="normal" postScriptName="NotoSansEgyptianHieroglyphs">
-            NotoSansEgyptianHieroglyphs-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Elba">
-        <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
-    </family>
-    <family lang="und-Glag">
-        <font weight="400" style="normal" postScriptName="NotoSansGlagolitic">
-            NotoSansGlagolitic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Goth">
-        <font weight="400" style="normal" postScriptName="NotoSansGothic">
-            NotoSansGothic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hano">
-        <font weight="400" style="normal" postScriptName="NotoSansHanunoo">
-            NotoSansHanunoo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Armi">
-        <font weight="400" style="normal" postScriptName="NotoSansImperialAramaic">
-            NotoSansImperialAramaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phli">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalPahlavi">
-            NotoSansInscriptionalPahlavi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Prti">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalParthian">
-            NotoSansInscriptionalParthian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Java">
-        <font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
-    </family>
-    <family lang="und-Kthi">
-        <font weight="400" style="normal" postScriptName="NotoSansKaithi">
-            NotoSansKaithi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Kali">
-        <font weight="400" style="normal" postScriptName="NotoSansKayahLi">
-            NotoSansKayahLi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Khar">
-        <font weight="400" style="normal" postScriptName="NotoSansKharoshthi">
-            NotoSansKharoshthi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lepc">
-        <font weight="400" style="normal" postScriptName="NotoSansLepcha">
-            NotoSansLepcha-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Limb">
-        <font weight="400" style="normal" postScriptName="NotoSansLimbu">NotoSansLimbu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Linb">
-        <font weight="400" style="normal" postScriptName="NotoSansLinearB">
-            NotoSansLinearB-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lisu">
-        <font weight="400" style="normal" postScriptName="NotoSansLisu">NotoSansLisu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lyci">
-        <font weight="400" style="normal" postScriptName="NotoSansLycian">
-            NotoSansLycian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lydi">
-        <font weight="400" style="normal" postScriptName="NotoSansLydian">
-            NotoSansLydian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mand">
-        <font weight="400" style="normal" postScriptName="NotoSansMandaic">
-            NotoSansMandaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mtei">
-        <font weight="400" style="normal" postScriptName="NotoSansMeeteiMayek">
-            NotoSansMeeteiMayek-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Talu">
-        <font weight="400" style="normal" postScriptName="NotoSansNewTaiLue">
-            NotoSansNewTaiLue-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Nkoo">
-        <font weight="400" style="normal" postScriptName="NotoSansNKo">NotoSansNKo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ogam">
-        <font weight="400" style="normal" postScriptName="NotoSansOgham">NotoSansOgham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Olck">
-        <font weight="400" style="normal" postScriptName="NotoSansOlChiki">
-            NotoSansOlChiki-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ital">
-        <font weight="400" style="normal" postScriptName="NotoSansOldItalic">
-            NotoSansOldItalic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xpeo">
-        <font weight="400" style="normal" postScriptName="NotoSansOldPersian">
-            NotoSansOldPersian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sarb">
-        <font weight="400" style="normal" postScriptName="NotoSansOldSouthArabian">
-            NotoSansOldSouthArabian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Orkh">
-        <font weight="400" style="normal" postScriptName="NotoSansOldTurkic">
-            NotoSansOldTurkic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Osge">
-        <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
-    </family>
-    <family lang="und-Osma">
-        <font weight="400" style="normal" postScriptName="NotoSansOsmanya">
-            NotoSansOsmanya-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phnx">
-        <font weight="400" style="normal" postScriptName="NotoSansPhoenician">
-            NotoSansPhoenician-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Rjng">
-        <font weight="400" style="normal" postScriptName="NotoSansRejang">
-            NotoSansRejang-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Runr">
-        <font weight="400" style="normal" postScriptName="NotoSansRunic">NotoSansRunic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Samr">
-        <font weight="400" style="normal" postScriptName="NotoSansSamaritan">
-            NotoSansSamaritan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Saur">
-        <font weight="400" style="normal" postScriptName="NotoSansSaurashtra">
-            NotoSansSaurashtra-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Shaw">
-        <font weight="400" style="normal" postScriptName="NotoSansShavian">
-            NotoSansShavian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sund">
-        <font weight="400" style="normal" postScriptName="NotoSansSundanese">
-            NotoSansSundanese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sylo">
-        <font weight="400" style="normal" postScriptName="NotoSansSylotiNagri">
-            NotoSansSylotiNagri-Regular.ttf
-        </font>
-    </family>
-    <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
-    <family lang="und-Syre">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEstrangela">
-            NotoSansSyriacEstrangela-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrn">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEastern">
-            NotoSansSyriacEastern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrj">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacWestern">
-            NotoSansSyriacWestern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tglg">
-        <font weight="400" style="normal" postScriptName="NotoSansTagalog">
-            NotoSansTagalog-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tagb">
-        <font weight="400" style="normal" postScriptName="NotoSansTagbanwa">
-            NotoSansTagbanwa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lana">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiTham">
-            NotoSansTaiTham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tavt">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiViet">
-            NotoSansTaiViet-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tibt">
-        <font postScriptName="NotoSerifTibetan-Regular" supportedAxes="wght">
-            NotoSerifTibetan-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Tfng">
-        <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
-    </family>
-    <family lang="und-Ugar">
-        <font weight="400" style="normal" postScriptName="NotoSansUgaritic">
-            NotoSansUgaritic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Vaii">
-        <font weight="400" style="normal" postScriptName="NotoSansVai">NotoSansVai-Regular.ttf
-        </font>
-    </family>
-    <family>
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
-    </family>
-    <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKjp-Regular">
-            NotoSansCJK-Regular.ttc
-        </font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKjp-Regular">
-            NotoSansCJK-Regular.ttc
-        </font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKjp-Regular">
-            NotoSansCJK-Regular.ttc
-        </font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font postScriptName="NotoSerifHentaigana-ExtraLight" supportedAxes="wght">
-            NotoSerifHentaigana.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-    </family>
-    <family lang="ko">
-        <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
-            NotoSansCJK-Regular.ttc
-        </font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmoji.ttf</font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmojiFlags.ttf</font>
-    </family>
-    <family lang="und-Zsym">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
-    </family>
-    <!--
-        Tai Le, Yi, Mongolian, and Phags-pa are intentionally kept last, to make sure they don't
-        override the East Asian punctuation for Chinese.
-    -->
-    <family lang="und-Tale">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiLe">NotoSansTaiLe-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Yiii">
-        <font weight="400" style="normal" postScriptName="NotoSansYi">NotoSansYi-Regular.ttf</font>
-    </family>
-    <family lang="und-Mong">
-        <font weight="400" style="normal" postScriptName="NotoSansMongolian">
-            NotoSansMongolian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phag">
-        <font weight="400" style="normal" postScriptName="NotoSansPhagsPa">
-            NotoSansPhagsPa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hluw">
-        <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
-    </family>
-    <family lang="und-Bass">
-        <font weight="400" style="normal">NotoSansBassaVah-Regular.otf</font>
-    </family>
-    <family lang="und-Bhks">
-        <font weight="400" style="normal">NotoSansBhaiksuki-Regular.otf</font>
-    </family>
-    <family lang="und-Hatr">
-        <font weight="400" style="normal">NotoSansHatran-Regular.otf</font>
-    </family>
-    <family lang="und-Lina">
-        <font weight="400" style="normal">NotoSansLinearA-Regular.otf</font>
-    </family>
-    <family lang="und-Mani">
-        <font weight="400" style="normal">NotoSansManichaean-Regular.otf</font>
-    </family>
-    <family lang="und-Marc">
-        <font weight="400" style="normal">NotoSansMarchen-Regular.otf</font>
-    </family>
-    <family lang="und-Merc">
-        <font weight="400" style="normal">NotoSansMeroitic-Regular.otf</font>
-    </family>
-    <family lang="und-Plrd">
-        <font weight="400" style="normal">NotoSansMiao-Regular.otf</font>
-    </family>
-    <family lang="und-Mroo">
-        <font weight="400" style="normal">NotoSansMro-Regular.otf</font>
-    </family>
-    <family lang="und-Mult">
-        <font weight="400" style="normal">NotoSansMultani-Regular.otf</font>
-    </family>
-    <family lang="und-Nbat">
-        <font weight="400" style="normal">NotoSansNabataean-Regular.otf</font>
-    </family>
-    <family lang="und-Newa">
-        <font weight="400" style="normal">NotoSansNewa-Regular.otf</font>
-    </family>
-    <family lang="und-Narb">
-        <font weight="400" style="normal">NotoSansOldNorthArabian-Regular.otf</font>
-    </family>
-    <family lang="und-Perm">
-        <font weight="400" style="normal">NotoSansOldPermic-Regular.otf</font>
-    </family>
-    <family lang="und-Hmng">
-        <font weight="400" style="normal">NotoSansPahawhHmong-Regular.otf</font>
-    </family>
-    <family lang="und-Palm">
-        <font weight="400" style="normal">NotoSansPalmyrene-Regular.otf</font>
-    </family>
-    <family lang="und-Pauc">
-        <font weight="400" style="normal">NotoSansPauCinHau-Regular.otf</font>
-    </family>
-    <family lang="und-Shrd">
-        <font weight="400" style="normal">NotoSansSharada-Regular.otf</font>
-    </family>
-    <family lang="und-Sora">
-        <font weight="400" style="normal">NotoSansSoraSompeng-Regular.otf</font>
-    </family>
-    <family lang="und-Gong">
-        <font weight="400" style="normal">NotoSansGunjalaGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Rohg">
-        <font weight="400" style="normal">NotoSansHanifiRohingya-Regular.otf</font>
-    </family>
-    <family lang="und-Khoj">
-        <font weight="400" style="normal">NotoSansKhojki-Regular.otf</font>
-    </family>
-    <family lang="und-Gonm">
-        <font weight="400" style="normal">NotoSansMasaramGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Wcho">
-        <font weight="400" style="normal">NotoSansWancho-Regular.otf</font>
-    </family>
-    <family lang="und-Wara">
-        <font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font>
-    </family>
-    <family lang="und-Gran">
-        <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font>
-    </family>
-    <family lang="und-Modi">
-        <font weight="400" style="normal">NotoSansModi-Regular.ttf</font>
-    </family>
-    <family lang="und-Dogr">
-        <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
-    </family>
-    <family lang="und-Medf">
-        <font postScriptName="NotoSansMedefaidrin-Regular" supportedAxes="wght">
-            NotoSansMedefaidrin-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Soyo">
-        <font postScriptName="NotoSansSoyombo-Regular" supportedAxes="wght">
-            NotoSansSoyombo-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Takr">
-        <font postScriptName="NotoSansTakri-Regular" supportedAxes="wght">
-            NotoSansTakri-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Hmnp">
-        <font postScriptName="NotoSerifHmongNyiakeng-Regular" supportedAxes="wght">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Yezi">
-        <font postScriptName="NotoSerifYezidi-Regular" supportedAxes="wght">
-            NotoSerifYezidi-VF.ttf
-        </font>
-    </family>
-</familyset>
diff --git a/data/fonts/font_fallback_cjkvf.xml b/data/fonts/font_fallback_cjkvf.xml
deleted file mode 100644
index 407d704..0000000
--- a/data/fonts/font_fallback_cjkvf.xml
+++ /dev/null
@@ -1,966 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    In this file, all fonts without names are added to the default list.
-    Fonts are chosen based on a match: full BCP-47 language tag including
-    script, then just language, and finally order (the first font containing
-    the glyph).
-
-    Order of appearance is also the tiebreaker for weight matching. This is
-    the reason why the 900 weights of Roboto precede the 700 weights - we
-    prefer the former when an 800 weight is requested. Since bold spans
-    effectively add 300 to the weight, this ensures that 900 is the bold
-    paired with the 500 weight, ensuring adequate contrast.
-
-
-    The font_fallback.xml defines the list of font used by the system.
-
-    `familyset` node:
-      A `familyset` element must be a root node of the font_fallback.xml. No attributes are allowed
-      to `familyset` node.
-      The `familyset` node can contains `family` and `alias` nodes. Any other nodes will be ignored.
-
-    `family` node:
-      A `family` node defines a single font family definition.
-      A font family is a set of fonts for drawing text in various styles such as weight, slant.
-      There are three types of families, default family, named family and locale fallback family.
-
-      The default family is a special family node appeared the first node of the `familyset` node.
-      The default family is used as first priority fallback.
-      Only `name` attribute can be used for default family node. If the `name` attribute is
-      specified, This family will also works as named family.
-
-      The named family is a family that has name attribute. The named family defines a new fallback.
-      For example, if the name attribute is "serif", it creates serif fallback. Developers can
-      access the fallback by using Typeface#create API.
-      The named family can not have attribute other than `name` attribute. The `name` attribute
-      cannot be empty.
-
-      The locale fallback family is a font family that is used for fallback. The fallback family is
-      used when the named family or default family cannot be used. The locale fallback family can
-      have `lang` attribute and `variant` attribute. The `lang` attribute is an optional comma
-      separated BCP-47i language tag. The `variant` is an optional attribute that can be one one
-      `element`, `compact`. If a `variant` attribute is not specified, it is treated as default.
-
-    `alias` node:
-      An `alias` node defines a alias of named family with changing weight offset. An `alias` node
-      can have mandatory `name` and `to` attribute and optional `weight` attribute. This `alias`
-      defines new fallback that has the name of specified `name` attribute. The fallback list is
-      the same to the fallback that of the name specified with `to` attribute. If `weight` attribute
-      is specified, the base weight offset is shifted to the specified value. For example, if the
-      `weight` is 500, the output text is drawn with 500 of weight.
-
-    `font` node:
-      A `font` node defines a single font definition. There are two types of fonts, static font and
-      variable font.
-
-      A static font can have `weight`, `style`, `index` and `postScriptName` attributes. A `weight`
-      is a mandatory attribute that defines the weight of the font. Any number between 0 to 1000 is
-      valid. A `style` is a mandatory attribute that defines the style of the font. A 'style'
-      attribute can be `normal` or `italic`. An `index` is an optional attribute that defines the
-      index of the font collection. If this is not specified, it is treated as 0. If the font file
-      is not a font collection, this attribute is ignored. A `postScriptName` attribute is an
-      optional attribute. A PostScript name is used for identifying target of system font update.
-      If this is not specified, the system assumes the filename is same to PostScript name of the
-      font file. For example, if the font file is "Roboto-Regular.ttf", the system assume the
-      PostScript name of this font is "Roboto-Regular".
-
-      A variable font can be only defined for the variable font file. A variable font can have
-      `axis` child nodes for specifying axis values. A variable font can have all attribute of
-      static font and can have additional `supportedAxes` attribute. A `supportedAxes` attribute
-      is a comma separated supported axis tags. As of Android V, only `wght` and `ital` axes can
-      be specified.
-
-      If `supportedAxes` attribute is not specified, this `font` node works as static font of the
-      single instance of variable font specified with `axis` children.
-
-      If `supportedAxes` attribute is specified, the system dynamically create font instance for the
-      given weight and style value. If `wght` is specified in `supportedAxes` attribute the `weight`
-      attribute and `axis` child that has `wght` tag become optional and ignored because it is
-      determined by system at runtime. Similarly, if `ital` is specified in `supportedAxes`
-      attribute, the `style` attribute and `axis` child that has `ital` tag become optional and
-      ignored.
-
-    `axis` node:
-      An `axis` node defines a font variation value for a tag. An `axis` node can have two mandatory
-      attributes, `tag` and `value`. If the font is variable font and the same tag `axis` node is
-      specified in `supportedAxes` attribute, the style value works like a default instance.
--->
-<familyset>
-    <!-- first font is default -->
-    <family name="sans-serif">
-        <font supportedAxes="wght,ital">Roboto-Regular.ttf
-          <axis tag="wdth" stylevalue="100" />
-        </font>
-   </family>
-
-
-    <!-- Note that aliases must come after the fonts they reference. -->
-    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
-    <alias name="sans-serif-light" to="sans-serif" weight="300" />
-    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
-    <alias name="sans-serif-black" to="sans-serif" weight="900" />
-    <alias name="arial" to="sans-serif" />
-    <alias name="helvetica" to="sans-serif" />
-    <alias name="tahoma" to="sans-serif" />
-    <alias name="verdana" to="sans-serif" />
-
-    <family name="sans-serif-condensed">
-      <font supportedAxes="wght,ital">Roboto-Regular.ttf
-        <axis tag="wdth" stylevalue="75" />
-      </font>
-    </family>
-    <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
-    <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
-
-    <family name="serif">
-        <font weight="400" style="normal" postScriptName="NotoSerif">NotoSerif-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
-        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
-        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
-    </family>
-    <alias name="serif-bold" to="serif" weight="700" />
-    <alias name="times" to="serif" />
-    <alias name="times new roman" to="serif" />
-    <alias name="palatino" to="serif" />
-    <alias name="georgia" to="serif" />
-    <alias name="baskerville" to="serif" />
-    <alias name="goudy" to="serif" />
-    <alias name="fantasy" to="serif" />
-    <alias name="ITC Stone Serif" to="serif" />
-
-    <family name="monospace">
-        <font weight="400" style="normal">DroidSansMono.ttf</font>
-    </family>
-    <alias name="sans-serif-monospace" to="monospace" />
-    <alias name="monaco" to="monospace" />
-
-    <family name="serif-monospace">
-        <font weight="400" style="normal" postScriptName="CutiveMono-Regular">CutiveMono.ttf</font>
-    </family>
-    <alias name="courier" to="serif-monospace" />
-    <alias name="courier new" to="serif-monospace" />
-
-    <family name="casual">
-        <font weight="400" style="normal" postScriptName="ComingSoon-Regular">ComingSoon.ttf</font>
-    </family>
-
-    <family name="cursive">
-      <font supportedAxes="wght">DancingScript-Regular.ttf</font>
-    </family>
-
-    <family name="sans-serif-smallcaps">
-        <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
-    </family>
-
-    <family name="source-sans-pro">
-        <font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
-        <font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
-        <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font>
-        <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font>
-        <font weight="700" style="normal">SourceSansPro-Bold.ttf</font>
-        <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font>
-    </family>
-    <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/>
-
-    <family name="roboto-flex">
-        <font supportedAxes="wght">RobotoFlex-Regular.ttf
-          <axis tag="wdth" stylevalue="100" />
-        </font>
-    </family>
-
-    <!-- fallback fonts -->
-    <family lang="und-Arab" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabic">
-            NotoNaskhArabic-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
-    </family>
-    <family lang="und-Arab" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabicUI">
-            NotoNaskhArabicUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Ethi">
-        <font postScriptName="NotoSansEthiopic-Regular" supportedAxes="wght">
-            NotoSansEthiopic-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifEthiopic-Regular" supportedAxes="wght">
-            NotoSerifEthiopic-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Hebr">
-        <font weight="400" style="normal" postScriptName="NotoSansHebrew">
-            NotoSansHebrew-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansThai">NotoSansThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansThaiUI">
-            NotoSansThaiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Armn">
-        <font postScriptName="NotoSansArmenian-Regular" supportedAxes="wght">
-            NotoSansArmenian-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifArmenian-Regular" supportedAxes="wght">
-            NotoSerifArmenian-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Geor,und-Geok">
-        <font postScriptName="NotoSansGeorgian-Regular" supportedAxes="wght">
-            NotoSansGeorgian-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifGeorgian-Regular" supportedAxes="wght">
-            NotoSerifGeorgian-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Deva" variant="elegant">
-        <font postScriptName="NotoSansDevanagari-Regular" supportedAxes="wght">
-            NotoSansDevanagari-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifDevanagari-Regular" supportedAxes="wght">
-            NotoSerifDevanagari-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Deva" variant="compact">
-        <font postScriptName="NotoSansDevanagariUI-Regular" supportedAxes="wght">
-            NotoSansDevanagariUI-VF.ttf
-        </font>
-    </family>
-
-    <!-- All scripts of India should come after Devanagari, due to shared
-         danda characters.
-    -->
-    <family lang="und-Gujr" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansGujarati">
-            NotoSansGujarati-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
-        <font style="normal" fallbackFor="serif" postScriptName="NotoSerifGujarati-Regular"
-          supportedAxes="wght">
-          NotoSerifGujarati-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Gujr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansGujaratiUI">
-            NotoSansGujaratiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Guru" variant="elegant">
-        <font postScriptName="NotoSansGurmukhi-Regular" supportedAxes="wght">
-            NotoSansGurmukhi-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifGurmukhi-Regular" supportedAxes="wght">
-            NotoSerifGurmukhi-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Guru" variant="compact">
-        <font postScriptName="NotoSansGurmukhiUI-Regular" supportedAxes="wght">
-            NotoSansGurmukhiUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Taml" variant="elegant">
-        <font postScriptName="NotoSansTamil-Regular" supportedAxes="wght">
-            NotoSansTamil-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifTamil-Regular" supportedAxes="wght">
-            NotoSerifTamil-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Taml" variant="compact">
-        <font postScriptName="NotoSansTamilUI-Regular" supportedAxes="wght">
-            NotoSansTamilUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="elegant">
-        <font postScriptName="NotoSansMalayalam-Regular" supportedAxes="wght">
-            NotoSansMalayalam-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifMalayalam-Regular" supportedAxes="wght">
-            NotoSerifMalayalam-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="compact">
-        <font postScriptName="NotoSansMalayalamUI-Regular" supportedAxes="wght">
-            NotoSansMalayalamUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Beng" variant="elegant">
-        <font postScriptName="NotoSansBengali-Regular" supportedAxes="wght">
-            NotoSansBengali-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifBengali-Regular" supportedAxes="wght">
-            NotoSerifBengali-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Beng" variant="compact">
-        <font postScriptName="NotoSansBengaliUI-Regular" supportedAxes="wght">
-            NotoSansBengaliUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Telu" variant="elegant">
-        <font postScriptName="NotoSansTelugu-Regular" supportedAxes="wght">
-            NotoSansTelugu-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifTelugu-Regular" supportedAxes="wght">
-            NotoSerifTelugu-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Telu" variant="compact">
-        <font postScriptName="NotoSansTeluguUI-Regular" supportedAxes="wght">
-            NotoSansTeluguUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Knda" variant="elegant">
-        <font postScriptName="NotoSansKannada-Regular" supportedAxes="wght">
-            NotoSansKannada-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifKannada-Regular" supportedAxes="wght">
-            NotoSerifKannada-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Knda" variant="compact">
-        <font postScriptName="NotoSansKannadaUI-Regular" supportedAxes="wght">
-            NotoSansKannadaUI-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Orya" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansOriya">NotoSansOriya-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
-    </family>
-    <family lang="und-Orya" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansOriyaUI">
-            NotoSansOriyaUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Sinh" variant="elegant">
-        <font postScriptName="NotoSansSinhala-Regular" supportedAxes="wght">
-            NotoSansSinhala-VF.ttf
-        </font>
-        <font fallbackFor="serif" postScriptName="NotoSerifSinhala-Regular" supportedAxes="wght">
-            NotoSerifSinhala-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Sinh" variant="compact">
-        <font postScriptName="NotoSansSinhalaUI-Regular" supportedAxes="wght">
-            NotoSansSinhalaUI-VF.ttf
-        </font>
-    </family>
-    <!-- TODO: NotoSansKhmer uses non-standard wght value, so cannot use auto-adjustment. -->
-    <family lang="und-Khmr" variant="elegant">
-        <font weight="100" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="26.0"/>
-        </font>
-        <font weight="200" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="39.0"/>
-        </font>
-        <font weight="300" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="58.0"/>
-        </font>
-        <font weight="400" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="90.0"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="108.0"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="128.0"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="151.0"/>
-        </font>
-        <font weight="800" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="169.0"/>
-        </font>
-        <font weight="900" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="190.0"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
-    </family>
-    <family lang="und-Khmr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansKhmerUI">
-            NotoSansKhmerUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="elegant">
-        <font weight="400" style="normal">NotoSansLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansLaoUI">NotoSansLaoUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Mymr" variant="elegant">
-        <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
-    </family>
-    <family lang="und-Mymr" variant="compact">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
-    </family>
-    <family lang="und-Thaa">
-        <font weight="400" style="normal" postScriptName="NotoSansThaana">
-            NotoSansThaana-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
-    </family>
-    <family lang="und-Cham">
-        <font weight="400" style="normal" postScriptName="NotoSansCham">NotoSansCham-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
-    </family>
-    <family lang="und-Ahom">
-        <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
-    </family>
-    <family lang="und-Adlm">
-        <font postScriptName="NotoSansAdlam-Regular" supportedAxes="wght">
-            NotoSansAdlam-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Avst">
-        <font weight="400" style="normal" postScriptName="NotoSansAvestan">
-            NotoSansAvestan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bali">
-        <font weight="400" style="normal" postScriptName="NotoSansBalinese">
-            NotoSansBalinese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bamu">
-        <font weight="400" style="normal" postScriptName="NotoSansBamum">NotoSansBamum-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Batk">
-        <font weight="400" style="normal" postScriptName="NotoSansBatak">NotoSansBatak-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Brah">
-        <font weight="400" style="normal" postScriptName="NotoSansBrahmi">
-            NotoSansBrahmi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bugi">
-        <font weight="400" style="normal" postScriptName="NotoSansBuginese">
-            NotoSansBuginese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Buhd">
-        <font weight="400" style="normal" postScriptName="NotoSansBuhid">NotoSansBuhid-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cans">
-        <font weight="400" style="normal">
-            NotoSansCanadianAboriginal-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cari">
-        <font weight="400" style="normal" postScriptName="NotoSansCarian">
-            NotoSansCarian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cakm">
-        <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
-    </family>
-    <family lang="und-Cher">
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
-    </family>
-    <family lang="und-Copt">
-        <font weight="400" style="normal" postScriptName="NotoSansCoptic">
-            NotoSansCoptic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xsux">
-        <font weight="400" style="normal" postScriptName="NotoSansCuneiform">
-            NotoSansCuneiform-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cprt">
-        <font weight="400" style="normal" postScriptName="NotoSansCypriot">
-            NotoSansCypriot-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Dsrt">
-        <font weight="400" style="normal" postScriptName="NotoSansDeseret">
-            NotoSansDeseret-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Egyp">
-        <font weight="400" style="normal" postScriptName="NotoSansEgyptianHieroglyphs">
-            NotoSansEgyptianHieroglyphs-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Elba">
-        <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
-    </family>
-    <family lang="und-Glag">
-        <font weight="400" style="normal" postScriptName="NotoSansGlagolitic">
-            NotoSansGlagolitic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Goth">
-        <font weight="400" style="normal" postScriptName="NotoSansGothic">
-            NotoSansGothic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hano">
-        <font weight="400" style="normal" postScriptName="NotoSansHanunoo">
-            NotoSansHanunoo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Armi">
-        <font weight="400" style="normal" postScriptName="NotoSansImperialAramaic">
-            NotoSansImperialAramaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phli">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalPahlavi">
-            NotoSansInscriptionalPahlavi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Prti">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalParthian">
-            NotoSansInscriptionalParthian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Java">
-        <font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
-    </family>
-    <family lang="und-Kthi">
-        <font weight="400" style="normal" postScriptName="NotoSansKaithi">
-            NotoSansKaithi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Kali">
-        <font weight="400" style="normal" postScriptName="NotoSansKayahLi">
-            NotoSansKayahLi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Khar">
-        <font weight="400" style="normal" postScriptName="NotoSansKharoshthi">
-            NotoSansKharoshthi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lepc">
-        <font weight="400" style="normal" postScriptName="NotoSansLepcha">
-            NotoSansLepcha-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Limb">
-        <font weight="400" style="normal" postScriptName="NotoSansLimbu">NotoSansLimbu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Linb">
-        <font weight="400" style="normal" postScriptName="NotoSansLinearB">
-            NotoSansLinearB-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lisu">
-        <font weight="400" style="normal" postScriptName="NotoSansLisu">NotoSansLisu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lyci">
-        <font weight="400" style="normal" postScriptName="NotoSansLycian">
-            NotoSansLycian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lydi">
-        <font weight="400" style="normal" postScriptName="NotoSansLydian">
-            NotoSansLydian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mand">
-        <font weight="400" style="normal" postScriptName="NotoSansMandaic">
-            NotoSansMandaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mtei">
-        <font weight="400" style="normal" postScriptName="NotoSansMeeteiMayek">
-            NotoSansMeeteiMayek-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Talu">
-        <font weight="400" style="normal" postScriptName="NotoSansNewTaiLue">
-            NotoSansNewTaiLue-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Nkoo">
-        <font weight="400" style="normal" postScriptName="NotoSansNKo">NotoSansNKo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ogam">
-        <font weight="400" style="normal" postScriptName="NotoSansOgham">NotoSansOgham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Olck">
-        <font weight="400" style="normal" postScriptName="NotoSansOlChiki">
-            NotoSansOlChiki-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ital">
-        <font weight="400" style="normal" postScriptName="NotoSansOldItalic">
-            NotoSansOldItalic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xpeo">
-        <font weight="400" style="normal" postScriptName="NotoSansOldPersian">
-            NotoSansOldPersian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sarb">
-        <font weight="400" style="normal" postScriptName="NotoSansOldSouthArabian">
-            NotoSansOldSouthArabian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Orkh">
-        <font weight="400" style="normal" postScriptName="NotoSansOldTurkic">
-            NotoSansOldTurkic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Osge">
-        <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
-    </family>
-    <family lang="und-Osma">
-        <font weight="400" style="normal" postScriptName="NotoSansOsmanya">
-            NotoSansOsmanya-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phnx">
-        <font weight="400" style="normal" postScriptName="NotoSansPhoenician">
-            NotoSansPhoenician-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Rjng">
-        <font weight="400" style="normal" postScriptName="NotoSansRejang">
-            NotoSansRejang-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Runr">
-        <font weight="400" style="normal" postScriptName="NotoSansRunic">NotoSansRunic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Samr">
-        <font weight="400" style="normal" postScriptName="NotoSansSamaritan">
-            NotoSansSamaritan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Saur">
-        <font weight="400" style="normal" postScriptName="NotoSansSaurashtra">
-            NotoSansSaurashtra-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Shaw">
-        <font weight="400" style="normal" postScriptName="NotoSansShavian">
-            NotoSansShavian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sund">
-        <font weight="400" style="normal" postScriptName="NotoSansSundanese">
-            NotoSansSundanese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sylo">
-        <font weight="400" style="normal" postScriptName="NotoSansSylotiNagri">
-            NotoSansSylotiNagri-Regular.ttf
-        </font>
-    </family>
-    <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
-    <family lang="und-Syre">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEstrangela">
-            NotoSansSyriacEstrangela-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrn">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEastern">
-            NotoSansSyriacEastern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrj">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacWestern">
-            NotoSansSyriacWestern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tglg">
-        <font weight="400" style="normal" postScriptName="NotoSansTagalog">
-            NotoSansTagalog-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tagb">
-        <font weight="400" style="normal" postScriptName="NotoSansTagbanwa">
-            NotoSansTagbanwa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lana">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiTham">
-            NotoSansTaiTham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tavt">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiViet">
-            NotoSansTaiViet-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tibt">
-        <font postScriptName="NotoSerifTibetan-Regular" supportedAxes="wght">
-            NotoSerifTibetan-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Tfng">
-        <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
-    </family>
-    <family lang="und-Ugar">
-        <font weight="400" style="normal" postScriptName="NotoSansUgaritic">
-            NotoSansUgaritic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Vaii">
-        <font weight="400" style="normal" postScriptName="NotoSansVai">NotoSansVai-Regular.ttf
-        </font>
-    </family>
-    <family>
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
-    </family>
-    <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular"
-            supportedAxes="wght">
-            NotoSansCJK-Regular.ttc
-            <!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
-                 for making regular style as default. -->
-            <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular"
-            supportedAxes="wght">
-            NotoSansCJK-Regular.ttc
-            <!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
-                 for making regular style as default. -->
-            <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular"
-            supportedAxes="wght">
-            NotoSansCJK-Regular.ttc
-            <!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
-                 for making regular style as default. -->
-            <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font postScriptName="NotoSerifHentaigana-ExtraLight" supportedAxes="wght">
-            NotoSerifHentaigana.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-    </family>
-    <family lang="ko">
-        <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular"
-            supportedAxes="wght">
-            NotoSansCJK-Regular.ttc
-            <!-- The default instance of NotoSansCJK-Regular.ttc is wght=100, so specify wght=400
-                 for making regular style as default. -->
-            <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmoji.ttf</font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmojiFlags.ttf</font>
-    </family>
-    <family lang="und-Zsym">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
-    </family>
-    <!--
-        Tai Le, Yi, Mongolian, and Phags-pa are intentionally kept last, to make sure they don't
-        override the East Asian punctuation for Chinese.
-    -->
-    <family lang="und-Tale">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiLe">NotoSansTaiLe-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Yiii">
-        <font weight="400" style="normal" postScriptName="NotoSansYi">NotoSansYi-Regular.ttf</font>
-    </family>
-    <family lang="und-Mong">
-        <font weight="400" style="normal" postScriptName="NotoSansMongolian">
-            NotoSansMongolian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phag">
-        <font weight="400" style="normal" postScriptName="NotoSansPhagsPa">
-            NotoSansPhagsPa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hluw">
-        <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
-    </family>
-    <family lang="und-Bass">
-        <font weight="400" style="normal">NotoSansBassaVah-Regular.otf</font>
-    </family>
-    <family lang="und-Bhks">
-        <font weight="400" style="normal">NotoSansBhaiksuki-Regular.otf</font>
-    </family>
-    <family lang="und-Hatr">
-        <font weight="400" style="normal">NotoSansHatran-Regular.otf</font>
-    </family>
-    <family lang="und-Lina">
-        <font weight="400" style="normal">NotoSansLinearA-Regular.otf</font>
-    </family>
-    <family lang="und-Mani">
-        <font weight="400" style="normal">NotoSansManichaean-Regular.otf</font>
-    </family>
-    <family lang="und-Marc">
-        <font weight="400" style="normal">NotoSansMarchen-Regular.otf</font>
-    </family>
-    <family lang="und-Merc">
-        <font weight="400" style="normal">NotoSansMeroitic-Regular.otf</font>
-    </family>
-    <family lang="und-Plrd">
-        <font weight="400" style="normal">NotoSansMiao-Regular.otf</font>
-    </family>
-    <family lang="und-Mroo">
-        <font weight="400" style="normal">NotoSansMro-Regular.otf</font>
-    </family>
-    <family lang="und-Mult">
-        <font weight="400" style="normal">NotoSansMultani-Regular.otf</font>
-    </family>
-    <family lang="und-Nbat">
-        <font weight="400" style="normal">NotoSansNabataean-Regular.otf</font>
-    </family>
-    <family lang="und-Newa">
-        <font weight="400" style="normal">NotoSansNewa-Regular.otf</font>
-    </family>
-    <family lang="und-Narb">
-        <font weight="400" style="normal">NotoSansOldNorthArabian-Regular.otf</font>
-    </family>
-    <family lang="und-Perm">
-        <font weight="400" style="normal">NotoSansOldPermic-Regular.otf</font>
-    </family>
-    <family lang="und-Hmng">
-        <font weight="400" style="normal">NotoSansPahawhHmong-Regular.otf</font>
-    </family>
-    <family lang="und-Palm">
-        <font weight="400" style="normal">NotoSansPalmyrene-Regular.otf</font>
-    </family>
-    <family lang="und-Pauc">
-        <font weight="400" style="normal">NotoSansPauCinHau-Regular.otf</font>
-    </family>
-    <family lang="und-Shrd">
-        <font weight="400" style="normal">NotoSansSharada-Regular.otf</font>
-    </family>
-    <family lang="und-Sora">
-        <font weight="400" style="normal">NotoSansSoraSompeng-Regular.otf</font>
-    </family>
-    <family lang="und-Gong">
-        <font weight="400" style="normal">NotoSansGunjalaGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Rohg">
-        <font weight="400" style="normal">NotoSansHanifiRohingya-Regular.otf</font>
-    </family>
-    <family lang="und-Khoj">
-        <font weight="400" style="normal">NotoSansKhojki-Regular.otf</font>
-    </family>
-    <family lang="und-Gonm">
-        <font weight="400" style="normal">NotoSansMasaramGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Wcho">
-        <font weight="400" style="normal">NotoSansWancho-Regular.otf</font>
-    </family>
-    <family lang="und-Wara">
-        <font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font>
-    </family>
-    <family lang="und-Gran">
-        <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font>
-    </family>
-    <family lang="und-Modi">
-        <font weight="400" style="normal">NotoSansModi-Regular.ttf</font>
-    </family>
-    <family lang="und-Dogr">
-        <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
-    </family>
-    <family lang="und-Medf">
-        <font postScriptName="NotoSansMedefaidrin-Regular" supportedAxes="wght">
-            NotoSansMedefaidrin-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Soyo">
-        <font postScriptName="NotoSansSoyombo-Regular" supportedAxes="wght">
-            NotoSansSoyombo-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Takr">
-        <font postScriptName="NotoSansTakri-Regular" supportedAxes="wght">
-            NotoSansTakri-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Hmnp">
-        <font postScriptName="NotoSerifHmongNyiakeng-Regular" supportedAxes="wght">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-        </font>
-    </family>
-    <family lang="und-Yezi">
-        <font postScriptName="NotoSerifYezidi-Regular" supportedAxes="wght">
-            NotoSerifYezidi-VF.ttf
-        </font>
-    </family>
-</familyset>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index d1aa8e9..8cbc300 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1409,24 +1409,123 @@
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
     </family>
     <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKjp-Regular">
+        <font weight="100" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
             NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="100"/>
+        </font>
+        <font weight="200" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="200"/>
+        </font>
+        <font weight="300" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="300"/>
+        </font>
+        <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="500" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="500"/>
+        </font>
+        <font weight="600" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="600"/>
+        </font>
+        <font weight="700" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+        <font weight="800" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="800"/>
+        </font>
+        <font weight="900" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="900"/>
         </font>
         <font weight="400" style="normal" index="2" fallbackFor="serif"
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
     <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKjp-Regular">
+        <font weight="100" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
             NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="100"/>
+        </font>
+        <font weight="200" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="200"/>
+        </font>
+        <font weight="300" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="300"/>
+        </font>
+        <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="500" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="500"/>
+        </font>
+        <font weight="600" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="600"/>
+        </font>
+        <font weight="700" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+        <font weight="800" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="800"/>
+        </font>
+        <font weight="900" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="900"/>
         </font>
         <font weight="400" style="normal" index="3" fallbackFor="serif"
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
         </font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKjp-Regular">
+        <font weight="100" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
             NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="100"/>
+        </font>
+        <font weight="200" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="200"/>
+        </font>
+        <font weight="300" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="300"/>
+        </font>
+        <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="500" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="500"/>
+        </font>
+        <font weight="600" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="600"/>
+        </font>
+        <font weight="700" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+        <font weight="800" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="800"/>
+        </font>
+        <font weight="900" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="900"/>
         </font>
         <font weight="400" style="normal" index="0" fallbackFor="serif"
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
@@ -1443,8 +1542,41 @@
         </font>
     </family>
     <family lang="ko">
-        <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
+        <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
             NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="100"/>
+        </font>
+        <font weight="200" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="200"/>
+        </font>
+        <font weight="300" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="300"/>
+        </font>
+        <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="400"/>
+        </font>
+        <font weight="500" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="500"/>
+        </font>
+        <font weight="600" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="600"/>
+        </font>
+        <font weight="700" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="700"/>
+        </font>
+        <font weight="800" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="800"/>
+        </font>
+        <font weight="900" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
+            NotoSansCJK-Regular.ttc
+            <axis tag="wght" stylevalue="900"/>
         </font>
         <font weight="400" style="normal" index="1" fallbackFor="serif"
               postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
diff --git a/data/fonts/fonts_cjkvf.xml b/data/fonts/fonts_cjkvf.xml
deleted file mode 100644
index 8cbc300..0000000
--- a/data/fonts/fonts_cjkvf.xml
+++ /dev/null
@@ -1,1795 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    DEPRECATED: This XML file is no longer a source of the font files installed
-    in the system.
-
-    For the device vendors: please add your font configurations to the
-    platform/frameworks/base/data/font_fallback.xml and also add it to this XML
-    file as much as possible for apps that reads this XML file.
-
-    For the application developers: please stop reading this XML file and use
-    android.graphics.fonts.SystemFonts#getAvailableFonts Java API or
-    ASystemFontIterator_open NDK API for getting list of system installed
-    font files.
-
-    WARNING: Parsing of this file by third-party apps is not supported. The
-    file, and the font files it refers to, will be renamed and/or moved out
-    from their respective location in the next Android release, and/or the
-    format or syntax of the file may change significantly. If you parse this
-    file for information about system fonts, do it at your own risk. Your
-    application will almost certainly break with the next major Android
-    release.
-
-    In this file, all fonts without names are added to the default list.
-    Fonts are chosen based on a match: full BCP-47 language tag including
-    script, then just language, and finally order (the first font containing
-    the glyph).
-
-    Order of appearance is also the tiebreaker for weight matching. This is
-    the reason why the 900 weights of Roboto precede the 700 weights - we
-    prefer the former when an 800 weight is requested. Since bold spans
-    effectively add 300 to the weight, this ensures that 900 is the bold
-    paired with the 500 weight, ensuring adequate contrast.
-
-    TODO(rsheeter) update comment; ordering to match 800 to 900 is no longer required
--->
-<familyset version="23">
-    <!-- first font is default -->
-    <family name="sans-serif">
-        <font weight="100" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="100" />
-        </font>
-        <font weight="200" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="200" />
-        </font>
-        <font weight="300" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="300" />
-        </font>
-        <font weight="400" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="500" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="500" />
-        </font>
-        <font weight="600" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="600" />
-        </font>
-        <font weight="700" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="700" />
-        </font>
-        <font weight="800" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="800" />
-        </font>
-        <font weight="900" style="normal">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="900" />
-        </font>
-        <font weight="100" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="100" />
-        </font>
-        <font weight="200" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="200" />
-        </font>
-        <font weight="300" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="300" />
-        </font>
-        <font weight="400" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="500" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="500" />
-        </font>
-        <font weight="600" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="600" />
-        </font>
-        <font weight="700" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="700" />
-        </font>
-        <font weight="800" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="800" />
-        </font>
-        <font weight="900" style="italic">Roboto-Regular.ttf
-          <axis tag="ital" stylevalue="1" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="900" />
-        </font>
-   </family>
-
-
-    <!-- Note that aliases must come after the fonts they reference. -->
-    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
-    <alias name="sans-serif-light" to="sans-serif" weight="300" />
-    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
-    <alias name="sans-serif-black" to="sans-serif" weight="900" />
-    <alias name="arial" to="sans-serif" />
-    <alias name="helvetica" to="sans-serif" />
-    <alias name="tahoma" to="sans-serif" />
-    <alias name="verdana" to="sans-serif" />
-
-    <family name="sans-serif-condensed">
-      <font weight="100" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="100" />
-      </font>
-      <font weight="200" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="200" />
-      </font>
-      <font weight="300" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="300" />
-      </font>
-      <font weight="400" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="400" />
-      </font>
-      <font weight="500" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="500" />
-      </font>
-      <font weight="600" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="600" />
-      </font>
-      <font weight="700" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="700" />
-      </font>
-      <font weight="800" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="800" />
-      </font>
-      <font weight="900" style="normal">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="0" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="900" />
-      </font>
-      <font weight="100" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="100" />
-      </font>
-      <font weight="200" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="200" />
-      </font>
-      <font weight="300" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="300" />
-      </font>
-      <font weight="400" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="400" />
-      </font>
-      <font weight="500" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="500" />
-      </font>
-      <font weight="600" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="600" />
-      </font>
-      <font weight="700" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="700" />
-      </font>
-      <font weight="800" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="800" />
-      </font>
-      <font weight="900" style="italic">Roboto-Regular.ttf
-        <axis tag="ital" stylevalue="1" />
-        <axis tag="wdth" stylevalue="75" />
-        <axis tag="wght" stylevalue="900" />
-      </font>
-    </family>
-    <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
-    <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
-
-    <family name="serif">
-        <font weight="400" style="normal" postScriptName="NotoSerif">NotoSerif-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
-        <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
-        <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
-    </family>
-    <alias name="serif-bold" to="serif" weight="700" />
-    <alias name="times" to="serif" />
-    <alias name="times new roman" to="serif" />
-    <alias name="palatino" to="serif" />
-    <alias name="georgia" to="serif" />
-    <alias name="baskerville" to="serif" />
-    <alias name="goudy" to="serif" />
-    <alias name="fantasy" to="serif" />
-    <alias name="ITC Stone Serif" to="serif" />
-
-    <family name="monospace">
-        <font weight="400" style="normal">DroidSansMono.ttf</font>
-    </family>
-    <alias name="sans-serif-monospace" to="monospace" />
-    <alias name="monaco" to="monospace" />
-
-    <family name="serif-monospace">
-        <font weight="400" style="normal" postScriptName="CutiveMono-Regular">CutiveMono.ttf</font>
-    </family>
-    <alias name="courier" to="serif-monospace" />
-    <alias name="courier new" to="serif-monospace" />
-
-    <family name="casual">
-        <font weight="400" style="normal" postScriptName="ComingSoon-Regular">ComingSoon.ttf</font>
-    </family>
-
-    <family name="cursive">
-      <font weight="400" style="normal">DancingScript-Regular.ttf
-        <axis tag="wght" stylevalue="400" />
-      </font>
-      <font weight="700" style="normal">DancingScript-Regular.ttf
-        <axis tag="wght" stylevalue="700" />
-      </font>
-    </family>
-
-    <family name="sans-serif-smallcaps">
-        <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
-    </family>
-
-    <family name="source-sans-pro">
-        <font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
-        <font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
-        <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font>
-        <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font>
-        <font weight="700" style="normal">SourceSansPro-Bold.ttf</font>
-        <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font>
-    </family>
-    <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/>
-
-    <family name="roboto-flex">
-        <font weight="100" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="100" />
-        </font>
-        <font weight="200" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="200" />
-        </font>
-        <font weight="300" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="300" />
-        </font>
-        <font weight="400" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="500" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="500" />
-        </font>
-        <font weight="600" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="600" />
-        </font>
-        <font weight="700" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="700" />
-        </font>
-        <font weight="800" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="800" />
-        </font>
-        <font weight="900" style="normal">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="0" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="900" />
-        </font>
-        <font weight="100" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="100" />
-        </font>
-        <font weight="200" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="200" />
-        </font>
-        <font weight="300" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="300" />
-        </font>
-        <font weight="400" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="400" />
-        </font>
-        <font weight="500" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="500" />
-        </font>
-        <font weight="600" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="600" />
-        </font>
-        <font weight="700" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="700" />
-        </font>
-        <font weight="800" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="800" />
-        </font>
-        <font weight="900" style="italic">RobotoFlex-Regular.ttf
-          <axis tag="slnt" stylevalue="-10" />
-          <axis tag="wdth" stylevalue="100" />
-          <axis tag="wght" stylevalue="900" />
-        </font>
-    </family>
-
-    <!-- fallback fonts -->
-    <family lang="und-Arab" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabic">
-            NotoNaskhArabic-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
-    </family>
-    <family lang="und-Arab" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoNaskhArabicUI">
-            NotoNaskhArabicUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Ethi">
-        <font weight="400" style="normal" postScriptName="NotoSansEthiopic-Regular">
-            NotoSansEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansEthiopic-Regular">
-            NotoSansEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansEthiopic-Regular">
-            NotoSansEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansEthiopic-Regular">
-            NotoSansEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Hebr">
-        <font weight="400" style="normal" postScriptName="NotoSansHebrew">
-            NotoSansHebrew-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansThai">NotoSansThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifThai-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
-    </family>
-    <family lang="und-Thai" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansThaiUI">
-            NotoSansThaiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Armn">
-        <font weight="400" style="normal" postScriptName="NotoSansArmenian-Regular">
-            NotoSansArmenian-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansArmenian-Regular">
-            NotoSansArmenian-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansArmenian-Regular">
-            NotoSansArmenian-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansArmenian-Regular">
-            NotoSansArmenian-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Geor,und-Geok">
-        <font weight="400" style="normal" postScriptName="NotoSansGeorgian-Regular">
-            NotoSansGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansGeorgian-Regular">
-            NotoSansGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansGeorgian-Regular">
-            NotoSansGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansGeorgian-Regular">
-            NotoSansGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Deva" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansDevanagari-Regular">
-            NotoSansDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansDevanagari-Regular">
-            NotoSansDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansDevanagari-Regular">
-            NotoSansDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansDevanagari-Regular">
-            NotoSansDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Deva" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
-            NotoSansDevanagariUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
-            NotoSansDevanagariUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
-            NotoSansDevanagariUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
-            NotoSansDevanagariUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-
-    <!-- All scripts of India should come after Devanagari, due to shared
-         danda characters.
-    -->
-    <family lang="und-Gujr" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansGujarati">
-            NotoSansGujarati-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Gujr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansGujaratiUI">
-            NotoSansGujaratiUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Guru" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansGurmukhi-Regular">
-            NotoSansGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansGurmukhi-Regular">
-            NotoSansGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansGurmukhi-Regular">
-            NotoSansGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansGurmukhi-Regular">
-            NotoSansGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Guru" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
-            NotoSansGurmukhiUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
-            NotoSansGurmukhiUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
-            NotoSansGurmukhiUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
-            NotoSansGurmukhiUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Taml" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansTamil-Regular">
-            NotoSansTamil-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansTamil-Regular">
-            NotoSansTamil-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansTamil-Regular">
-            NotoSansTamil-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansTamil-Regular">
-            NotoSansTamil-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Taml" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansTamilUI-Regular">
-            NotoSansTamilUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansTamilUI-Regular">
-            NotoSansTamilUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansTamilUI-Regular">
-            NotoSansTamilUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansTamilUI-Regular">
-            NotoSansTamilUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansMalayalam-Regular">
-            NotoSansMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansMalayalam-Regular">
-            NotoSansMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansMalayalam-Regular">
-            NotoSansMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansMalayalam-Regular">
-            NotoSansMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Mlym" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
-            NotoSansMalayalamUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
-            NotoSansMalayalamUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
-            NotoSansMalayalamUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
-            NotoSansMalayalamUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Beng" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansBengali-Regular">
-            NotoSansBengali-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansBengali-Regular">
-            NotoSansBengali-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansBengali-Regular">
-            NotoSansBengali-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansBengali-Regular">
-            NotoSansBengali-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Beng" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansBengaliUI-Regular">
-            NotoSansBengaliUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansBengaliUI-Regular">
-            NotoSansBengaliUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansBengaliUI-Regular">
-            NotoSansBengaliUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansBengaliUI-Regular">
-            NotoSansBengaliUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Telu" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansTelugu-Regular">
-            NotoSansTelugu-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansTelugu-Regular">
-            NotoSansTelugu-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansTelugu-Regular">
-            NotoSansTelugu-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansTelugu-Regular">
-            NotoSansTelugu-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Telu" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansTeluguUI-Regular">
-            NotoSansTeluguUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansTeluguUI-Regular">
-            NotoSansTeluguUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansTeluguUI-Regular">
-            NotoSansTeluguUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansTeluguUI-Regular">
-            NotoSansTeluguUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Knda" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansKannada-Regular">
-            NotoSansKannada-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansKannada-Regular">
-            NotoSansKannada-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansKannada-Regular">
-            NotoSansKannada-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansKannada-Regular">
-            NotoSansKannada-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Knda" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansKannadaUI-Regular">
-            NotoSansKannadaUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansKannadaUI-Regular">
-            NotoSansKannadaUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansKannadaUI-Regular">
-            NotoSansKannadaUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansKannadaUI-Regular">
-            NotoSansKannadaUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Orya" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansOriya">NotoSansOriya-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
-    </family>
-    <family lang="und-Orya" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansOriyaUI">
-            NotoSansOriyaUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Sinh" variant="elegant">
-        <font weight="400" style="normal" postScriptName="NotoSansSinhala-Regular">
-            NotoSansSinhala-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansSinhala-Regular">
-            NotoSansSinhala-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansSinhala-Regular">
-            NotoSansSinhala-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansSinhala-Regular">
-            NotoSansSinhala-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif"
-              postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Sinh" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
-            NotoSansSinhalaUI-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
-            NotoSansSinhalaUI-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
-            NotoSansSinhalaUI-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
-            NotoSansSinhalaUI-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Khmr" variant="elegant">
-        <font weight="100" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="26.0"/>
-        </font>
-        <font weight="200" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="39.0"/>
-        </font>
-        <font weight="300" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="58.0"/>
-        </font>
-        <font weight="400" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="90.0"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="108.0"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="128.0"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="151.0"/>
-        </font>
-        <font weight="800" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="169.0"/>
-        </font>
-        <font weight="900" style="normal" postScriptName="NotoSansKhmer-Regular">
-            NotoSansKhmer-VF.ttf
-            <axis tag="wdth" stylevalue="100.0"/>
-            <axis tag="wght" stylevalue="190.0"/>
-        </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
-    </family>
-    <family lang="und-Khmr" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansKhmerUI">
-            NotoSansKhmerUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="elegant">
-        <font weight="400" style="normal">NotoSansLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">
-            NotoSerifLao-Regular.ttf
-        </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
-    </family>
-    <family lang="und-Laoo" variant="compact">
-        <font weight="400" style="normal" postScriptName="NotoSansLaoUI">NotoSansLaoUI-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
-    </family>
-    <family lang="und-Mymr" variant="elegant">
-        <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
-    </family>
-    <family lang="und-Mymr" variant="compact">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
-    </family>
-    <family lang="und-Thaa">
-        <font weight="400" style="normal" postScriptName="NotoSansThaana">
-            NotoSansThaana-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
-    </family>
-    <family lang="und-Cham">
-        <font weight="400" style="normal" postScriptName="NotoSansCham">NotoSansCham-Regular.ttf
-        </font>
-        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
-    </family>
-    <family lang="und-Ahom">
-        <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
-    </family>
-    <family lang="und-Adlm">
-        <font weight="400" style="normal" postScriptName="NotoSansAdlam-Regular">
-            NotoSansAdlam-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansAdlam-Regular">
-            NotoSansAdlam-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansAdlam-Regular">
-            NotoSansAdlam-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansAdlam-Regular">
-            NotoSansAdlam-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Avst">
-        <font weight="400" style="normal" postScriptName="NotoSansAvestan">
-            NotoSansAvestan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bali">
-        <font weight="400" style="normal" postScriptName="NotoSansBalinese">
-            NotoSansBalinese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bamu">
-        <font weight="400" style="normal" postScriptName="NotoSansBamum">NotoSansBamum-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Batk">
-        <font weight="400" style="normal" postScriptName="NotoSansBatak">NotoSansBatak-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Brah">
-        <font weight="400" style="normal" postScriptName="NotoSansBrahmi">
-            NotoSansBrahmi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Bugi">
-        <font weight="400" style="normal" postScriptName="NotoSansBuginese">
-            NotoSansBuginese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Buhd">
-        <font weight="400" style="normal" postScriptName="NotoSansBuhid">NotoSansBuhid-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cans">
-        <font weight="400" style="normal">
-            NotoSansCanadianAboriginal-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cari">
-        <font weight="400" style="normal" postScriptName="NotoSansCarian">
-            NotoSansCarian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cakm">
-        <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
-    </family>
-    <family lang="und-Cher">
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
-    </family>
-    <family lang="und-Copt">
-        <font weight="400" style="normal" postScriptName="NotoSansCoptic">
-            NotoSansCoptic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xsux">
-        <font weight="400" style="normal" postScriptName="NotoSansCuneiform">
-            NotoSansCuneiform-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Cprt">
-        <font weight="400" style="normal" postScriptName="NotoSansCypriot">
-            NotoSansCypriot-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Dsrt">
-        <font weight="400" style="normal" postScriptName="NotoSansDeseret">
-            NotoSansDeseret-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Egyp">
-        <font weight="400" style="normal" postScriptName="NotoSansEgyptianHieroglyphs">
-            NotoSansEgyptianHieroglyphs-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Elba">
-        <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
-    </family>
-    <family lang="und-Glag">
-        <font weight="400" style="normal" postScriptName="NotoSansGlagolitic">
-            NotoSansGlagolitic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Goth">
-        <font weight="400" style="normal" postScriptName="NotoSansGothic">
-            NotoSansGothic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hano">
-        <font weight="400" style="normal" postScriptName="NotoSansHanunoo">
-            NotoSansHanunoo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Armi">
-        <font weight="400" style="normal" postScriptName="NotoSansImperialAramaic">
-            NotoSansImperialAramaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phli">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalPahlavi">
-            NotoSansInscriptionalPahlavi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Prti">
-        <font weight="400" style="normal" postScriptName="NotoSansInscriptionalParthian">
-            NotoSansInscriptionalParthian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Java">
-        <font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
-    </family>
-    <family lang="und-Kthi">
-        <font weight="400" style="normal" postScriptName="NotoSansKaithi">
-            NotoSansKaithi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Kali">
-        <font weight="400" style="normal" postScriptName="NotoSansKayahLi">
-            NotoSansKayahLi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Khar">
-        <font weight="400" style="normal" postScriptName="NotoSansKharoshthi">
-            NotoSansKharoshthi-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lepc">
-        <font weight="400" style="normal" postScriptName="NotoSansLepcha">
-            NotoSansLepcha-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Limb">
-        <font weight="400" style="normal" postScriptName="NotoSansLimbu">NotoSansLimbu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Linb">
-        <font weight="400" style="normal" postScriptName="NotoSansLinearB">
-            NotoSansLinearB-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lisu">
-        <font weight="400" style="normal" postScriptName="NotoSansLisu">NotoSansLisu-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lyci">
-        <font weight="400" style="normal" postScriptName="NotoSansLycian">
-            NotoSansLycian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lydi">
-        <font weight="400" style="normal" postScriptName="NotoSansLydian">
-            NotoSansLydian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mand">
-        <font weight="400" style="normal" postScriptName="NotoSansMandaic">
-            NotoSansMandaic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Mtei">
-        <font weight="400" style="normal" postScriptName="NotoSansMeeteiMayek">
-            NotoSansMeeteiMayek-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Talu">
-        <font weight="400" style="normal" postScriptName="NotoSansNewTaiLue">
-            NotoSansNewTaiLue-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Nkoo">
-        <font weight="400" style="normal" postScriptName="NotoSansNKo">NotoSansNKo-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ogam">
-        <font weight="400" style="normal" postScriptName="NotoSansOgham">NotoSansOgham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Olck">
-        <font weight="400" style="normal" postScriptName="NotoSansOlChiki">
-            NotoSansOlChiki-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Ital">
-        <font weight="400" style="normal" postScriptName="NotoSansOldItalic">
-            NotoSansOldItalic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Xpeo">
-        <font weight="400" style="normal" postScriptName="NotoSansOldPersian">
-            NotoSansOldPersian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sarb">
-        <font weight="400" style="normal" postScriptName="NotoSansOldSouthArabian">
-            NotoSansOldSouthArabian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Orkh">
-        <font weight="400" style="normal" postScriptName="NotoSansOldTurkic">
-            NotoSansOldTurkic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Osge">
-        <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
-    </family>
-    <family lang="und-Osma">
-        <font weight="400" style="normal" postScriptName="NotoSansOsmanya">
-            NotoSansOsmanya-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phnx">
-        <font weight="400" style="normal" postScriptName="NotoSansPhoenician">
-            NotoSansPhoenician-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Rjng">
-        <font weight="400" style="normal" postScriptName="NotoSansRejang">
-            NotoSansRejang-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Runr">
-        <font weight="400" style="normal" postScriptName="NotoSansRunic">NotoSansRunic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Samr">
-        <font weight="400" style="normal" postScriptName="NotoSansSamaritan">
-            NotoSansSamaritan-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Saur">
-        <font weight="400" style="normal" postScriptName="NotoSansSaurashtra">
-            NotoSansSaurashtra-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Shaw">
-        <font weight="400" style="normal" postScriptName="NotoSansShavian">
-            NotoSansShavian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sund">
-        <font weight="400" style="normal" postScriptName="NotoSansSundanese">
-            NotoSansSundanese-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Sylo">
-        <font weight="400" style="normal" postScriptName="NotoSansSylotiNagri">
-            NotoSansSylotiNagri-Regular.ttf
-        </font>
-    </family>
-    <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
-    <family lang="und-Syre">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEstrangela">
-            NotoSansSyriacEstrangela-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrn">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacEastern">
-            NotoSansSyriacEastern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Syrj">
-        <font weight="400" style="normal" postScriptName="NotoSansSyriacWestern">
-            NotoSansSyriacWestern-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tglg">
-        <font weight="400" style="normal" postScriptName="NotoSansTagalog">
-            NotoSansTagalog-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tagb">
-        <font weight="400" style="normal" postScriptName="NotoSansTagbanwa">
-            NotoSansTagbanwa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Lana">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiTham">
-            NotoSansTaiTham-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tavt">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiViet">
-            NotoSansTaiViet-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Tibt">
-        <font weight="400" style="normal" postScriptName="NotoSerifTibetan-Regular">
-            NotoSerifTibetan-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSerifTibetan-Regular">
-            NotoSerifTibetan-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSerifTibetan-Regular">
-            NotoSerifTibetan-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSerifTibetan-Regular">
-            NotoSerifTibetan-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Tfng">
-        <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
-    </family>
-    <family lang="und-Ugar">
-        <font weight="400" style="normal" postScriptName="NotoSansUgaritic">
-            NotoSansUgaritic-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Vaii">
-        <font weight="400" style="normal" postScriptName="NotoSansVai">NotoSansVai-Regular.ttf
-        </font>
-    </family>
-    <family>
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
-    </family>
-    <family lang="zh-Hans">
-        <font weight="100" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="100"/>
-        </font>
-        <font weight="200" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="200"/>
-        </font>
-        <font weight="300" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="300"/>
-        </font>
-        <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="800" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="800"/>
-        </font>
-        <font weight="900" style="normal" index="2" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="900"/>
-        </font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="zh-Hant,zh-Bopo">
-        <font weight="100" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="100"/>
-        </font>
-        <font weight="200" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="200"/>
-        </font>
-        <font weight="300" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="300"/>
-        </font>
-        <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="800" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="800"/>
-        </font>
-        <font weight="900" style="normal" index="3" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="900"/>
-        </font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font weight="100" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="100"/>
-        </font>
-        <font weight="200" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="200"/>
-        </font>
-        <font weight="300" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="300"/>
-        </font>
-        <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="800" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="800"/>
-        </font>
-        <font weight="900" style="normal" index="0" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="900"/>
-        </font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="ja">
-        <font weight="400" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
-            NotoSerifHentaigana.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSerifHentaigana-ExtraLight">
-            NotoSerifHentaigana.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="ko">
-        <font weight="100" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="100"/>
-        </font>
-        <font weight="200" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="200"/>
-        </font>
-        <font weight="300" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="300"/>
-        </font>
-        <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-        <font weight="800" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="800"/>
-        </font>
-        <font weight="900" style="normal" index="1" postScriptName="NotoSansCJKJP-Regular">
-            NotoSansCJK-Regular.ttc
-            <axis tag="wght" stylevalue="900"/>
-        </font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif"
-              postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
-        </font>
-    </family>
-    <family lang="und-Zsye" ignore="true">
-        <font weight="400" style="normal">NotoColorEmojiLegacy.ttf</font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmoji.ttf</font>
-    </family>
-    <family lang="und-Zsye">
-        <font weight="400" style="normal">NotoColorEmojiFlags.ttf</font>
-    </family>
-    <family lang="und-Zsym">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
-    </family>
-    <!--
-        Tai Le, Yi, Mongolian, and Phags-pa are intentionally kept last, to make sure they don't
-        override the East Asian punctuation for Chinese.
-    -->
-    <family lang="und-Tale">
-        <font weight="400" style="normal" postScriptName="NotoSansTaiLe">NotoSansTaiLe-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Yiii">
-        <font weight="400" style="normal" postScriptName="NotoSansYi">NotoSansYi-Regular.ttf</font>
-    </family>
-    <family lang="und-Mong">
-        <font weight="400" style="normal" postScriptName="NotoSansMongolian">
-            NotoSansMongolian-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Phag">
-        <font weight="400" style="normal" postScriptName="NotoSansPhagsPa">
-            NotoSansPhagsPa-Regular.ttf
-        </font>
-    </family>
-    <family lang="und-Hluw">
-        <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
-    </family>
-    <family lang="und-Bass">
-        <font weight="400" style="normal">NotoSansBassaVah-Regular.otf</font>
-    </family>
-    <family lang="und-Bhks">
-        <font weight="400" style="normal">NotoSansBhaiksuki-Regular.otf</font>
-    </family>
-    <family lang="und-Hatr">
-        <font weight="400" style="normal">NotoSansHatran-Regular.otf</font>
-    </family>
-    <family lang="und-Lina">
-        <font weight="400" style="normal">NotoSansLinearA-Regular.otf</font>
-    </family>
-    <family lang="und-Mani">
-        <font weight="400" style="normal">NotoSansManichaean-Regular.otf</font>
-    </family>
-    <family lang="und-Marc">
-        <font weight="400" style="normal">NotoSansMarchen-Regular.otf</font>
-    </family>
-    <family lang="und-Merc">
-        <font weight="400" style="normal">NotoSansMeroitic-Regular.otf</font>
-    </family>
-    <family lang="und-Plrd">
-        <font weight="400" style="normal">NotoSansMiao-Regular.otf</font>
-    </family>
-    <family lang="und-Mroo">
-        <font weight="400" style="normal">NotoSansMro-Regular.otf</font>
-    </family>
-    <family lang="und-Mult">
-        <font weight="400" style="normal">NotoSansMultani-Regular.otf</font>
-    </family>
-    <family lang="und-Nbat">
-        <font weight="400" style="normal">NotoSansNabataean-Regular.otf</font>
-    </family>
-    <family lang="und-Newa">
-        <font weight="400" style="normal">NotoSansNewa-Regular.otf</font>
-    </family>
-    <family lang="und-Narb">
-        <font weight="400" style="normal">NotoSansOldNorthArabian-Regular.otf</font>
-    </family>
-    <family lang="und-Perm">
-        <font weight="400" style="normal">NotoSansOldPermic-Regular.otf</font>
-    </family>
-    <family lang="und-Hmng">
-        <font weight="400" style="normal">NotoSansPahawhHmong-Regular.otf</font>
-    </family>
-    <family lang="und-Palm">
-        <font weight="400" style="normal">NotoSansPalmyrene-Regular.otf</font>
-    </family>
-    <family lang="und-Pauc">
-        <font weight="400" style="normal">NotoSansPauCinHau-Regular.otf</font>
-    </family>
-    <family lang="und-Shrd">
-        <font weight="400" style="normal">NotoSansSharada-Regular.otf</font>
-    </family>
-    <family lang="und-Sora">
-        <font weight="400" style="normal">NotoSansSoraSompeng-Regular.otf</font>
-    </family>
-    <family lang="und-Gong">
-        <font weight="400" style="normal">NotoSansGunjalaGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Rohg">
-        <font weight="400" style="normal">NotoSansHanifiRohingya-Regular.otf</font>
-    </family>
-    <family lang="und-Khoj">
-        <font weight="400" style="normal">NotoSansKhojki-Regular.otf</font>
-    </family>
-    <family lang="und-Gonm">
-        <font weight="400" style="normal">NotoSansMasaramGondi-Regular.otf</font>
-    </family>
-    <family lang="und-Wcho">
-        <font weight="400" style="normal">NotoSansWancho-Regular.otf</font>
-    </family>
-    <family lang="und-Wara">
-        <font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font>
-    </family>
-    <family lang="und-Gran">
-        <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font>
-    </family>
-    <family lang="und-Modi">
-        <font weight="400" style="normal">NotoSansModi-Regular.ttf</font>
-    </family>
-    <family lang="und-Dogr">
-        <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
-    </family>
-    <family lang="und-Medf">
-        <font weight="400" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
-            NotoSansMedefaidrin-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
-            NotoSansMedefaidrin-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
-            NotoSansMedefaidrin-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
-            NotoSansMedefaidrin-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Soyo">
-        <font weight="400" style="normal" postScriptName="NotoSansSoyombo-Regular">
-            NotoSansSoyombo-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansSoyombo-Regular">
-            NotoSansSoyombo-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansSoyombo-Regular">
-            NotoSansSoyombo-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansSoyombo-Regular">
-            NotoSansSoyombo-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Takr">
-        <font weight="400" style="normal" postScriptName="NotoSansTakri-Regular">
-            NotoSansTakri-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSansTakri-Regular">
-            NotoSansTakri-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSansTakri-Regular">
-            NotoSansTakri-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSansTakri-Regular">
-            NotoSansTakri-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Hmnp">
-        <font weight="400" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
-            NotoSerifNyiakengPuachueHmong-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-    <family lang="und-Yezi">
-        <font weight="400" style="normal" postScriptName="NotoSerifYezidi-Regular">
-            NotoSerifYezidi-VF.ttf
-            <axis tag="wght" stylevalue="400"/>
-        </font>
-        <font weight="500" style="normal" postScriptName="NotoSerifYezidi-Regular">
-            NotoSerifYezidi-VF.ttf
-            <axis tag="wght" stylevalue="500"/>
-        </font>
-        <font weight="600" style="normal" postScriptName="NotoSerifYezidi-Regular">
-            NotoSerifYezidi-VF.ttf
-            <axis tag="wght" stylevalue="600"/>
-        </font>
-        <font weight="700" style="normal" postScriptName="NotoSerifYezidi-Regular">
-            NotoSerifYezidi-VF.ttf
-            <axis tag="wght" stylevalue="700"/>
-        </font>
-    </family>
-</familyset>
diff --git a/keystore/java/android/security/OWNERS b/keystore/java/android/security/OWNERS
index 32759b2..4305286 100644
--- a/keystore/java/android/security/OWNERS
+++ b/keystore/java/android/security/OWNERS
@@ -1,2 +1,2 @@
-per-file *.java,*.aidl = eranm@google.com,pgrafov@google.com,rubinxu@google.com
+per-file *.java,*.aidl = drysdale@google.com,jbires@google.com,pgrafov@google.com,rubinxu@google.com
 per-file KeyStoreManager.java = mpgroover@google.com
diff --git a/keystore/tests/OWNERS b/keystore/tests/OWNERS
index 86c31f4..0f94ddc 100644
--- a/keystore/tests/OWNERS
+++ b/keystore/tests/OWNERS
@@ -1,4 +1,7 @@
+# Android HW Trust team
+drysdale@google.com
+jbires@google.com
+
 # Android Enterprise security team
-eranm@google.com
 pgrafov@google.com
 rubinxu@google.com
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
index 6ad2f08..220fc6f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
@@ -54,6 +54,7 @@
     @NonNull
     private final BackupIdler mBackupIdler = new BackupIdler();
     private boolean mBackupIdlerScheduled;
+    private boolean mSaveEmbeddingState = false;
 
     private final List<ParcelableTaskContainerData> mParcelableTaskContainerDataList =
             new ArrayList<>();
@@ -71,11 +72,32 @@
         }
     }
 
+    void setAutoSaveEmbeddingState(boolean saveEmbeddingState) {
+        if (mSaveEmbeddingState == saveEmbeddingState) {
+            return;
+        }
+
+        Log.i(TAG, "Set save embedding state: " + saveEmbeddingState);
+        mSaveEmbeddingState = saveEmbeddingState;
+        if (!mSaveEmbeddingState) {
+            removeSavedState();
+            return;
+        }
+
+        if (!hasPendingStateToRestore() && !mController.getTaskContainers().isEmpty()) {
+            scheduleBackup();
+        }
+    }
     /**
      * Schedules a back-up request. It is no-op if there was a request scheduled and not yet
      * completed.
      */
     void scheduleBackup() {
+        if (!mSaveEmbeddingState) {
+            // TODO(b/289875940): enabled internally for broader testing.
+            return;
+        }
+
         if (!mBackupIdlerScheduled) {
             mBackupIdlerScheduled = true;
             Looper.getMainLooper().getQueue().addIdleHandler(mBackupIdler);
@@ -128,7 +150,6 @@
         final List<TaskFragmentInfo> infos = savedState.getParcelableArrayList(
                 KEY_RESTORE_TASK_FRAGMENTS_INFO, TaskFragmentInfo.class);
         for (TaskFragmentInfo info : infos) {
-            if (DEBUG) Log.d(TAG, "Retrieved: " + info);
             mTaskFragmentInfos.put(info.getFragmentToken(), info);
             mPresenter.updateTaskFragmentInfo(info);
         }
@@ -140,6 +161,11 @@
             if (DEBUG) Log.d(TAG, "Retrieved: " + info);
             mTaskFragmentParentInfos.put(info.getTaskId(), info);
         }
+
+        if (DEBUG) {
+            Log.d(TAG, "Retrieved task-fragment info: " + infos.size() + ", task info: "
+                    + parentInfos.size());
+        }
     }
 
     void abortTaskContainerRebuilding(@NonNull WindowContainerTransaction wct) {
@@ -148,7 +174,6 @@
             final TaskFragmentInfo info = mTaskFragmentInfos.valueAt(i);
             mPresenter.deleteTaskFragment(wct, info.getFragmentToken());
         }
-
         removeSavedState();
     }
 
@@ -190,6 +215,9 @@
         final ArrayMap<String, EmbeddingRule> embeddingRuleMap = new ArrayMap<>();
         for (EmbeddingRule rule : rules) {
             embeddingRuleMap.put(rule.getTag(), rule);
+            if (DEBUG) {
+                Log.d(TAG, "Tag: " + rule.getTag() + " rule: " + rule);
+            }
         }
 
         boolean restoredAny = false;
@@ -201,7 +229,7 @@
                 // has unknown tag, unable to restore.
                 if (DEBUG) {
                     Log.d(TAG, "Rebuilding TaskContainer abort! Unknown Tag. Task#"
-                            + parcelableTaskContainerData.mTaskId);
+                            + parcelableTaskContainerData.mTaskId + ", tags = " + tags);
                 }
                 continue;
             }
@@ -217,7 +245,7 @@
 
             final TaskContainer taskContainer = new TaskContainer(parcelableTaskContainerData,
                     mController, mTaskFragmentInfos);
-            if (DEBUG) Log.d(TAG, "Created TaskContainer " + taskContainer);
+            if (DEBUG) Log.d(TAG, "Created TaskContainer " + taskContainer.getTaskId());
             mController.addTaskContainer(taskContainer.getTaskId(), taskContainer);
 
             for (ParcelableSplitContainerData splitData :
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 3368e2e..60e1a50 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -2886,6 +2886,18 @@
         return getActiveSplitForContainer(container) != null;
     }
 
+
+    @Override
+    public void setAutoSaveEmbeddingState(boolean saveEmbeddingState) {
+        if (!Flags.aeBackStackRestore()) {
+            return;
+        }
+
+        synchronized (mLock) {
+            mPresenter.setAutoSaveEmbeddingState(saveEmbeddingState);
+        }
+    }
+
     void scheduleBackup() {
         synchronized (mLock) {
             mPresenter.scheduleBackup();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index b498ee2..9a2f32e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -183,6 +183,10 @@
         }
     }
 
+    void setAutoSaveEmbeddingState(boolean saveEmbeddingState) {
+        mBackupHelper.setAutoSaveEmbeddingState(saveEmbeddingState);
+    }
+
     void scheduleBackup() {
         mBackupHelper.scheduleBackup();
     }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index b453f1d..6928409 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -48,8 +48,6 @@
 import androidx.window.extensions.embedding.SplitAttributes.SplitType.ExpandContainersSplitType;
 import androidx.window.extensions.embedding.SplitAttributes.SplitType.RatioSplitType;
 
-import com.android.window.flags.Flags;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -634,11 +632,7 @@
         // pin container.
         updateAlwaysOnTopOverlayIfNecessary();
 
-        // TODO(b/289875940): Making backup-restore as an opt-in solution, before the flag goes
-        //  to next-food.
-        if (Flags.aeBackStackRestore()) {
-            mSplitController.scheduleBackup();
-        }
+        mSplitController.scheduleBackup();
     }
 
     private void updateAlwaysOnTopOverlayIfNecessary() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
index 9ca9b73..4569cf3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java
@@ -26,6 +26,7 @@
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
 import android.window.IBackAnimationRunner;
 import android.window.IOnBackInvokedCallback;
 
@@ -34,6 +35,8 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Used to register the animation callback and runner, it will trigger result if gesture was finish
  * before it received IBackAnimationRunner#onAnimationStart, so the controller could continue
@@ -101,6 +104,40 @@
         return mCallback;
     }
 
+    private Runnable mFinishedCallback;
+    private RemoteAnimationTarget[] mApps;
+    private IRemoteAnimationFinishedCallback mRemoteCallback;
+
+    private static class RemoteAnimationFinishedStub extends IRemoteAnimationFinishedCallback.Stub {
+        //the binder callback should not hold strong reference to it to avoid memory leak.
+        private WeakReference<BackAnimationRunner> mRunnerRef;
+
+        private RemoteAnimationFinishedStub(BackAnimationRunner runner) {
+            mRunnerRef = new WeakReference<>(runner);
+        }
+
+        @Override
+        public void onAnimationFinished() {
+            BackAnimationRunner runner = mRunnerRef.get();
+            if (runner == null) {
+                return;
+            }
+            if (runner.shouldMonitorCUJ(runner.mApps)) {
+                InteractionJankMonitor.getInstance().end(runner.mCujType);
+            }
+
+            runner.mFinishedCallback.run();
+            for (int i = runner.mApps.length - 1; i >= 0; --i) {
+                 SurfaceControl sc = runner.mApps[i].leash;
+                 if (sc != null && sc.isValid()) {
+                     sc.release();
+                 }
+            }
+            runner.mApps = null;
+            runner.mFinishedCallback = null;
+        }
+    }
+
     /**
      * Called from {@link IBackAnimationRunner}, it will deliver these
      * {@link RemoteAnimationTarget}s to the corresponding runner.
@@ -108,16 +145,9 @@
     void startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
             RemoteAnimationTarget[] nonApps, Runnable finishedCallback) {
         InteractionJankMonitor interactionJankMonitor = InteractionJankMonitor.getInstance();
-        final IRemoteAnimationFinishedCallback callback =
-                new IRemoteAnimationFinishedCallback.Stub() {
-                    @Override
-                    public void onAnimationFinished() {
-                        if (shouldMonitorCUJ(apps)) {
-                            interactionJankMonitor.end(mCujType);
-                        }
-                        finishedCallback.run();
-                    }
-                };
+        mFinishedCallback = finishedCallback;
+        mApps = apps;
+        if (mRemoteCallback == null) mRemoteCallback = new RemoteAnimationFinishedStub(this);
         mWaitingAnimation = false;
         if (shouldMonitorCUJ(apps)) {
             interactionJankMonitor.begin(
@@ -125,7 +155,7 @@
         }
         try {
             getRunner().onAnimationStart(TRANSIT_OLD_UNSET, apps, wallpapers,
-                    nonApps, callback);
+                    nonApps, mRemoteCallback);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed call onAnimationStart", e);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 09a4481..b505bee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -422,7 +422,7 @@
         interactionJankMonitor.begin(taskSurface, context, handler,
             CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
         dragToDesktopTransitionHandler.startDragToDesktopTransition(
-            taskInfo,
+            taskInfo.taskId,
             dragToDesktopValueAnimator
         )
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index 34c2f1e..d7d5519 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -109,8 +109,8 @@
      * after one of the "end" or "cancel" transitions is merged into this transition.
      */
     fun startDragToDesktopTransition(
-        taskInfo: RunningTaskInfo,
-        dragToDesktopAnimator: MoveToDesktopAnimator
+        taskId: Int,
+        dragToDesktopAnimator: MoveToDesktopAnimator,
     ) {
         if (inProgress) {
             ProtoLog.v(
@@ -137,26 +137,23 @@
             )
         val wct = WindowContainerTransaction()
         wct.sendPendingIntent(pendingIntent, launchHomeIntent, Bundle())
-        // The home launch done above will result in an attempt to move the task to pip if
-        // applicable, resulting in a broken state. Prevent that here.
-        wct.setDoNotPip(taskInfo.token)
         val startTransitionToken =
             transitions.startTransition(TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, wct, this)
 
         transitionState =
-            if (isSplitTask(taskInfo.taskId)) {
+            if (isSplitTask(taskId)) {
                 val otherTask =
-                    getOtherSplitTask(taskInfo.taskId)
+                    getOtherSplitTask(taskId)
                         ?: throw IllegalStateException("Expected split task to have a counterpart.")
                 TransitionState.FromSplit(
-                    draggedTaskId = taskInfo.taskId,
+                    draggedTaskId = taskId,
                     dragAnimator = dragToDesktopAnimator,
                     startTransitionToken = startTransitionToken,
                     otherSplitTask = otherTask
                 )
             } else {
                 TransitionState.FromFullscreen(
-                    draggedTaskId = taskInfo.taskId,
+                    draggedTaskId = taskId,
                     dragAnimator = dragToDesktopAnimator,
                     startTransitionToken = startTransitionToken
                 )
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index b36b1f8..3e6d36c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -110,12 +110,12 @@
     void registerSplitAnimationListener(@NonNull SplitInvocationListener listener,
             @NonNull Executor executor);
 
-    /** Called when device waking up finished. */
-    void onFinishedWakingUp();
-
     /** Called when device starts going to sleep (screen off). */
     void onStartedGoingToSleep();
 
+    /** Called when device wakes up. */
+    void onStartedWakingUp();
+
     /** Called when requested to go to fullscreen from the current active split app. */
     void goToFullscreenFromSplit();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index a23b576..6398d31 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -471,14 +471,14 @@
         mStageCoordinator.onKeyguardStateChanged(visible, occluded);
     }
 
-    public void onFinishedWakingUp() {
-        mStageCoordinator.onFinishedWakingUp();
-    }
-
     public void onStartedGoingToSleep() {
         mStageCoordinator.onStartedGoingToSleep();
     }
 
+    public void onStartedWakingUp() {
+        mStageCoordinator.onStartedWakingUp();
+    }
+
     public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
     }
@@ -1084,13 +1084,13 @@
         }
 
         @Override
-        public void onFinishedWakingUp() {
-            mMainExecutor.execute(SplitScreenController.this::onFinishedWakingUp);
+        public void onStartedGoingToSleep() {
+            mMainExecutor.execute(SplitScreenController.this::onStartedGoingToSleep);
         }
 
         @Override
-        public void onStartedGoingToSleep() {
-            mMainExecutor.execute(SplitScreenController.this::onStartedGoingToSleep);
+        public void onStartedWakingUp() {
+            mMainExecutor.execute(SplitScreenController.this::onStartedWakingUp);
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9239fb7..7893267 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1138,14 +1138,10 @@
                 "onKeyguardVisibilityChanged: active=%b occludingTaskRunning=%b",
                 active, occludingTaskRunning);
         setDividerVisibility(!mKeyguardActive, null);
-
-        if (active && occludingTaskRunning) {
-            dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
-        }
     }
 
-    void onFinishedWakingUp() {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onFinishedWakingUp");
+    void onStartedWakingUp() {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onStartedWakingUp");
         if (mBreakOnNextWake) {
             dismissSplitKeepingLastActiveStage(EXIT_REASON_DEVICE_FOLDED);
         }
@@ -2431,6 +2427,10 @@
             final int transitType = info.getType();
             TransitionInfo.Change pipChange = null;
             int closingSplitTaskId = -1;
+            // This array tracks if we are sending stages TO_BACK in this transition.
+            // TODO (b/349828130): Update for n apps
+            boolean[] stagesSentToBack = new boolean[2];
+
             for (int iC = 0; iC < info.getChanges().size(); ++iC) {
                 final TransitionInfo.Change change = info.getChanges().get(iC);
                 if (change.getMode() == TRANSIT_CHANGE
@@ -2498,23 +2498,31 @@
                     }
                     continue;
                 }
+                final int taskId = taskInfo.taskId;
                 if (isOpeningType(change.getMode())) {
-                    if (!stage.containsTask(taskInfo.taskId)) {
+                    if (!stage.containsTask(taskId)) {
                         Log.w(TAG, "Expected onTaskAppeared on " + stage + " to have been called"
-                                + " with " + taskInfo.taskId + " before startAnimation().");
-                        record.addRecord(stage, true, taskInfo.taskId);
+                                + " with " + taskId + " before startAnimation().");
+                        record.addRecord(stage, true, taskId);
                     }
                 } else if (change.getMode() == TRANSIT_CLOSE) {
-                    if (stage.containsTask(taskInfo.taskId)) {
-                        record.addRecord(stage, false, taskInfo.taskId);
+                    if (stage.containsTask(taskId)) {
+                        record.addRecord(stage, false, taskId);
                         Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
-                                + " with " + taskInfo.taskId + " before startAnimation().");
+                                + " with " + taskId + " before startAnimation().");
                     }
                 }
                 if (isClosingType(change.getMode()) &&
-                        getStageOfTask(change.getTaskInfo().taskId) != STAGE_TYPE_UNDEFINED) {
-                    // If either one of the 2 stages is closing we're assuming we'll break split
-                    closingSplitTaskId = change.getTaskInfo().taskId;
+                        getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED) {
+
+                    // Record which stages are getting sent to back
+                    if (change.getMode() == TRANSIT_TO_BACK) {
+                        stagesSentToBack[getStageOfTask(taskId)] = true;
+                    }
+
+                    // (For PiP transitions) If either one of the 2 stages is closing we're assuming
+                    // we'll break split
+                    closingSplitTaskId = taskId;
                 }
             }
 
@@ -2540,6 +2548,21 @@
                 return true;
             }
 
+            // If keyguard is active, check to see if we have our TO_BACK transitions in order.
+            // This array should either be all false (no split stages sent to back) or all true
+            // (all stages sent to back). In any other case (which can happen with SHOW_ABOVE_LOCKED
+            // apps) we should break split.
+            if (mKeyguardActive) {
+                boolean isFirstStageSentToBack = stagesSentToBack[0];
+                for (boolean b : stagesSentToBack) {
+                    // Compare each boolean to the first one. If any are different, break split.
+                    if (b != isFirstStageSentToBack) {
+                        dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+                        break;
+                    }
+                }
+            }
+
             final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
             if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
                     || dismissStages.size() == 1) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 0bd3e08..79e16fe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -607,7 +607,7 @@
                 )
             )
             .thenReturn(token)
-        handler.startDragToDesktopTransition(task, dragAnimator)
+        handler.startDragToDesktopTransition(task.taskId, dragAnimator)
         return token
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a6e33e5..a252a9d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -320,7 +320,7 @@
 
         assertEquals(mStageCoordinator.mLastActiveStage, STAGE_TYPE_MAIN);
 
-        mStageCoordinator.onFinishedWakingUp();
+        mStageCoordinator.onStartedWakingUp();
 
         verify(mTaskOrganizer).startNewTransition(eq(TRANSIT_SPLIT_DISMISS), notNull());
     }
diff --git a/libs/hwui/tests/common/scenes/WindowBlurKawase.cpp b/libs/hwui/tests/common/scenes/WindowBlurKawase.cpp
new file mode 100644
index 0000000..5905b32
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/WindowBlurKawase.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkRefCnt.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <math.h>
+
+#include "SkImageFilters.h"
+#include "TestSceneBase.h"
+#include "include/gpu/GpuTypes.h"  // from Skia
+#include "tests/common/BitmapAllocationTestUtils.h"
+#include "utils/Color.h"
+
+class WindowBlurKawase;
+
+static TestScene::Registrar _WindowBlurKawase(TestScene::Info{
+        "windowblurkawase", "Draws window Kawase blur",
+        TestScene::simpleCreateScene<WindowBlurKawase>});
+
+/**
+ * Simulates the multi-pass Kawase blur algorithm in
+ * frameworks/native/libs/renderengine/skia/filters/WindowBlurKawaseFilter.cpp
+ */
+class WindowBlurKawase : public TestScene {
+private:
+    // Keep in sync with
+    // frameworks/native/libs/renderengine/skia/filters/KawaseBlurFilter.h
+    static constexpr uint32_t kMaxPasses = 4;
+    // Keep in sync with frameworks/native/libs/renderengine/skia/filters/BlurFilter.h
+    static constexpr float kInputScale = 0.25f;
+
+    static constexpr uint32_t kLoopLength = 500;
+    static constexpr uint32_t kMaxBlurRadius = 300;
+    sk_sp<SkRuntimeEffect> mBlurEffect;
+
+    sp<RenderNode> card;
+    sp<RenderNode> contentNode;
+
+public:
+    explicit WindowBlurKawase() {
+        SkString blurString(
+                "uniform shader child;"
+                "uniform float in_blurOffset;"
+
+                "half4 main(float2 xy) {"
+                "half4 c = child.eval(xy);"
+                "c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));"
+                "c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));"
+                "c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));"
+                "c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));"
+                "return half4(c.rgb * 0.2, 1.0);"
+                "}");
+
+        auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
+        if (!blurEffect) {
+            LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
+        }
+        mBlurEffect = std::move(blurEffect);
+    }
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        contentNode = TestUtils::createNode(
+                0, 0, width, height, [width, height](RenderProperties& props, Canvas& canvas) {
+                    canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+                    Paint paint;
+                    paint.setColor(Color::Red_500);
+                    canvas.drawRect(0, 0, width / 2, height / 2, paint);
+                    paint.setColor(Color::Blue_500);
+                    canvas.drawRect(width / 2, height / 2, width, height, paint);
+                });
+
+        card = TestUtils::createNode(
+                0, 0, width, height,
+                [this](RenderProperties& props, Canvas& canvas) { blurFrame(canvas, 0); });
+        canvas.drawRenderNode(card.get());
+    }
+
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % kLoopLength;
+        float blurRadius =
+                (sin((float)curFrame / kLoopLength * M_PI * 2) + 1) * 0.5 * kMaxBlurRadius;
+        TestUtils::recordNode(
+                *card, [this, blurRadius](Canvas& canvas) { blurFrame(canvas, blurRadius); });
+    }
+
+    void blurFrame(Canvas& canvas, float blurRadius) {
+        if (blurRadius == 0) {
+            canvas.drawRenderNode(contentNode.get());
+            return;
+        }
+
+        int width = canvas.width();
+        int height = canvas.height();
+        float tmpRadius = (float)blurRadius / 2.0f;
+        uint32_t numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
+        float radiusByPasses = tmpRadius / (float)numberOfPasses;
+
+        SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+
+        sp<RenderNode> node = contentNode;
+        for (int i = 0; i < numberOfPasses; i++) {
+            blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale * (i + 1);
+            sk_sp<SkImageFilter> blurFilter =
+                    SkImageFilters::RuntimeShader(blurBuilder, radiusByPasses, "child", nullptr);
+            // Also downsample the image in the first pass.
+            float canvasScale = i == 0 ? kInputScale : 1;
+
+            // Apply the blur effect as an image filter.
+            node = TestUtils::createNode(
+                    0, 0, width * kInputScale, height * kInputScale,
+                    [node, blurFilter, canvasScale](RenderProperties& props, Canvas& canvas) {
+                        props.mutateLayerProperties().setImageFilter(blurFilter.get());
+                        canvas.scale(canvasScale, canvasScale);
+                        canvas.drawRenderNode(node.get());
+                    });
+        }
+
+        // Finally upsample the image to its original size.
+        canvas.scale(1 / kInputScale, 1 / kInputScale);
+        canvas.drawRenderNode(node.get());
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/WindowBlurSkia.cpp b/libs/hwui/tests/common/scenes/WindowBlurSkia.cpp
new file mode 100644
index 0000000..36e6d8f
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/WindowBlurSkia.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkRefCnt.h>
+#include <SkRuntimeEffect.h>
+#include <SkSurface.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <math.h>
+
+#include "SkImageFilters.h"
+#include "TestSceneBase.h"
+#include "include/gpu/GpuTypes.h"  // from Skia
+#include "tests/common/BitmapAllocationTestUtils.h"
+#include "utils/Color.h"
+
+class WindowBlurSkia;
+
+static TestScene::Registrar _WindowBlurSkia(TestScene::Info{
+        "windowblurskia", "Draws window Skia blur", TestScene::simpleCreateScene<WindowBlurSkia>});
+
+/**
+ * Simulates the Skia window blur in
+ * frameworks/native/libs/renderengine/skia/filters/GaussianBlurFilter.cpp
+ */
+class WindowBlurSkia : public TestScene {
+private:
+    // Keep in sync with frameworks/native/libs/renderengine/skia/filters/BlurFilter.h
+    static constexpr float kInputScale = 0.25f;
+
+    static constexpr uint32_t kLoopLength = 500;
+    static constexpr uint32_t kMaxBlurRadius = 300;
+
+    sp<RenderNode> card;
+    sp<RenderNode> contentNode;
+
+public:
+    void createContent(int width, int height, Canvas& canvas) override {
+        contentNode = TestUtils::createNode(
+                0, 0, width, height, [width, height](RenderProperties& props, Canvas& canvas) {
+                    canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+                    Paint paint;
+                    paint.setColor(Color::Red_500);
+                    canvas.drawRect(0, 0, width / 2, height / 2, paint);
+                    paint.setColor(Color::Blue_500);
+                    canvas.drawRect(width / 2, height / 2, width, height, paint);
+                });
+
+        card = TestUtils::createNode(
+                0, 0, width, height,
+                [this](RenderProperties& props, Canvas& canvas) { blurFrame(canvas, 0); });
+        canvas.drawRenderNode(card.get());
+    }
+
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % kLoopLength;
+        float blurRadius =
+                (sin((float)curFrame / kLoopLength * M_PI * 2) + 1) * 0.5 * kMaxBlurRadius;
+        TestUtils::recordNode(
+                *card, [this, blurRadius](Canvas& canvas) { blurFrame(canvas, blurRadius); });
+    }
+
+    void blurFrame(Canvas& canvas, float blurRadius) {
+        if (blurRadius == 0) {
+            canvas.drawRenderNode(contentNode.get());
+            return;
+        }
+
+        int width = canvas.width();
+        int height = canvas.height();
+
+        // Downsample and blur the image with the Skia blur filter.
+        sp<RenderNode> node = contentNode;
+        sk_sp<SkImageFilter> blurFilter =
+                SkImageFilters::Blur(blurRadius, blurRadius, SkTileMode::kClamp, nullptr, nullptr);
+        node = TestUtils::createNode(
+                0, 0, width * kInputScale, height * kInputScale,
+                [node, blurFilter](RenderProperties& props, Canvas& canvas) {
+                    props.mutateLayerProperties().setImageFilter(blurFilter.get());
+                    canvas.scale(kInputScale, kInputScale);
+                    canvas.drawRenderNode(node.get());
+                });
+
+        // Upsample the image to its original size.
+        canvas.scale(1 / kInputScale, 1 / kInputScale);
+        canvas.drawRenderNode(node.get());
+    }
+};
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
index ad996c7..b64f5dc 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt
@@ -38,3 +38,11 @@
     @StringRes override val title: Int = 0,
     @StringRes override val summary: Int = 0,
 ) : TwoStatePreference
+
+/** A preference that provides a two-state toggleable option that can be used as a main switch. */
+open class MainSwitchPreference
+@JvmOverloads
+constructor(
+    override val key: String,
+    @StringRes override val title: Int = 0,
+) : TwoStatePreference
\ No newline at end of file
diff --git a/packages/SettingsLib/Preference/Android.bp b/packages/SettingsLib/Preference/Android.bp
index bff95ce..fb06be9 100644
--- a/packages/SettingsLib/Preference/Android.bp
+++ b/packages/SettingsLib/Preference/Android.bp
@@ -32,6 +32,7 @@
     static_libs: [
         "SettingsLibDataStore",
         "SettingsLibMetadata",
+        "SettingsLibMainSwitchPreference",
         "androidx.annotation_annotation",
         "androidx.preference_preference",
         "guava",
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindingFactory.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindingFactory.kt
index 4c2e1ba..43f2cb6 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindingFactory.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindingFactory.kt
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.preference
 
+import com.android.settingslib.metadata.MainSwitchPreference
 import com.android.settingslib.metadata.PreferenceGroup
 import com.android.settingslib.metadata.PreferenceMetadata
 import com.android.settingslib.metadata.SwitchPreference
@@ -36,6 +37,7 @@
                 is SwitchPreference -> SwitchPreferenceBinding.INSTANCE
                 is PreferenceGroup -> PreferenceGroupBinding.INSTANCE
                 is PreferenceScreenCreator -> PreferenceScreenBinding.INSTANCE
+                is MainSwitchPreference -> MainSwitchPreferenceBinding.INSTANCE
                 else -> DefaultPreferenceBinding
             }
 }
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
index ede970e..d40a6f6 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt
@@ -21,11 +21,13 @@
 import androidx.preference.PreferenceCategory
 import androidx.preference.PreferenceScreen
 import androidx.preference.SwitchPreferenceCompat
+import androidx.preference.TwoStatePreference
 import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY
 import com.android.settingslib.metadata.PersistentPreference
 import com.android.settingslib.metadata.PreferenceMetadata
 import com.android.settingslib.metadata.PreferenceScreenMetadata
 import com.android.settingslib.metadata.PreferenceTitleProvider
+import com.android.settingslib.widget.MainSwitchPreference
 
 /** Binding of preference group associated with [PreferenceCategory]. */
 interface PreferenceScreenBinding : PreferenceBinding {
@@ -64,23 +66,37 @@
     }
 }
 
-/** A boolean value type preference associated with [SwitchPreferenceCompat]. */
-interface SwitchPreferenceBinding : PreferenceBinding {
-
-    override fun createWidget(context: Context): Preference = SwitchPreferenceCompat(context)
+/** A boolean value type preference associated with the abstract [TwoStatePreference]. */
+interface TwoStatePreferenceBinding : PreferenceBinding {
 
     override fun bind(preference: Preference, metadata: PreferenceMetadata) {
         super.bind(preference, metadata)
         (metadata as? PersistentPreference<*>)
             ?.storage(preference.context)
             ?.getValue(metadata.key, Boolean::class.javaObjectType)
-            ?.let { (preference as SwitchPreferenceCompat).isChecked = it }
+            ?.let { (preference as TwoStatePreference).isChecked = it }
     }
+}
+
+/** A boolean value type preference associated with [SwitchPreferenceCompat]. */
+interface SwitchPreferenceBinding : TwoStatePreferenceBinding {
+
+    override fun createWidget(context: Context): Preference = SwitchPreferenceCompat(context)
 
     companion object {
         @JvmStatic val INSTANCE = object : SwitchPreferenceBinding {}
     }
 }
 
+/** A boolean value type preference associated with [MainSwitchPreference]. */
+interface MainSwitchPreferenceBinding : TwoStatePreferenceBinding {
+
+    override fun createWidget(context: Context): Preference = MainSwitchPreference(context)
+
+    companion object {
+        @JvmStatic val INSTANCE = object : MainSwitchPreferenceBinding {}
+    }
+}
+
 /** Default [PreferenceBinding] for [Preference]. */
 object DefaultPreferenceBinding : PreferenceBinding
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 65b2275..00ae05c 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -76,6 +76,7 @@
         "truth",
         "Nene",
         "Harrier",
+        "bedstead-enterprise",
     ],
     libs: [
         "android.test.base.stubs.system",
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java
index e86e727..9cce431 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderMultiUsersTest.java
@@ -20,6 +20,9 @@
 import static android.provider.Settings.Secure.SYNC_PARENT_SOUNDS;
 import static android.provider.Settings.System.RINGTONE;
 
+import static com.android.bedstead.enterprise.EnterpriseDeviceStateExtensionsKt.workProfile;
+import static com.android.bedstead.multiuser.MultiUserDeviceStateExtensionsKt.secondaryUser;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.pm.PackageManager;
@@ -82,7 +85,7 @@
     @RequireFeature(PackageManager.FEATURE_MANAGED_USERS)
     @EnsureHasWorkProfile
     public void testSettings_workProfile() throws Exception {
-        UserReference profile = sDeviceState.workProfile();
+        UserReference profile = workProfile(sDeviceState);
 
         // Settings.Global settings are shared between different users
         assertSettingsShared(SPACE_GLOBAL, mPrimaryUser.id(), profile.id());
@@ -96,7 +99,7 @@
     @RequireRunOnInitialUser
     @EnsureHasSecondaryUser
     public void testSettings_secondaryUser() throws Exception {
-        UserReference secondaryUser = sDeviceState.secondaryUser();
+        UserReference secondaryUser = secondaryUser(sDeviceState);
 
         // Settings.Global settings are shared between different users
         assertSettingsShared(SPACE_GLOBAL, mPrimaryUser.id(), secondaryUser.id());
@@ -223,7 +226,7 @@
     @RequireRunOnInitialUser
     @EnsureHasSecondaryUser
     public void testSettings_stopAndRestartSecondaryUser() throws Exception {
-        UserReference secondaryUser = sDeviceState.secondaryUser();
+        UserReference secondaryUser = secondaryUser(sDeviceState);
 
         assertSettingsDifferent(SPACE_SECURE, mPrimaryUser.id(), secondaryUser.id());
 
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 3c560fd..5f90b39 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -276,8 +276,6 @@
 filegroup {
     name: "SystemUI-tests-broken-robofiles-compile",
     srcs: [
-        "tests/src/**/*DeviceOnlyTest.java",
-        "tests/src/**/*DeviceOnlyTest.kt",
         "tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
         "tests/src/**/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt",
         "tests/src/**/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt",
@@ -293,7 +291,6 @@
         "tests/src/**/systemui/keyguard/ResourceTrimmerTest.kt",
         "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt",
         "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt",
         "tests/src/**/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
         "tests/src/**/systemui/mediaprojection/taskswitcher/MediaProjectionTaskSwitcherCoreStartableTest.kt",
         "tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
@@ -303,14 +300,12 @@
         "tests/src/**/systemui/screenshot/ActionIntentCreatorTest.kt",
         "tests/src/**/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt",
         "tests/src/**/systemui/screenshot/TakeScreenshotServiceTest.kt",
-        "tests/src/**/systemui/statusbar/commandline/CommandRegistryTest.kt",
         "tests/src/**/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt",
         "tests/src/**/systemui/statusbar/notification/icon/IconManagerTest.kt",
         "tests/src/**/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt",
         "tests/src/**/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt",
         "tests/src/**/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerTest.kt",
         "tests/src/**/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt",
-        "tests/src/**/systemui/statusbar/policy/BatteryStateNotifierTest.kt",
         "tests/src/**/systemui/statusbar/policy/FlashlightControllerImplTest.kt",
         "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt",
         "tests/src/**/systemui/stylus/StylusUsiPowerStartableTest.kt",
@@ -449,27 +444,20 @@
         "tests/src/**/systemui/media/dialog/MediaSwitchingControllerTest.java",
         "tests/src/**/systemui/navigationbar/views/NavigationBarTest.java",
         "tests/src/**/systemui/power/PowerNotificationWarningsTest.java",
-        "tests/src/**/systemui/power/PowerUITest.java",
         "tests/src/**/systemui/qs/QSFooterViewControllerTest.java",
         "tests/src/**/systemui/qs/QSImplTest.java",
-        "tests/src/**/systemui/qs/QSSecurityFooterTest.java",
-        "tests/src/**/systemui/qs/tileimpl/QSTileImplTest.java",
         "tests/src/**/systemui/qs/tiles/QuickAccessWalletTileTest.java",
         "tests/src/**/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java",
-        "tests/src/**/systemui/shared/plugins/PluginActionManagerTest.java",
-        "tests/src/**/systemui/statusbar/CommandQueueTest.java",
-        "tests/src/**/systemui/statusbar/connectivity/CallbackHandlerTest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerBaseTest.java",
-        "tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
-        "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java",
-        "tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
-        "tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
-        "tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
-        "tests/src/**/systemui/toast/ToastUITest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerDataTest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerSignalTest.java",
         "tests/src/**/systemui/statusbar/connectivity/NetworkControllerWifiTest.java",
+        "tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
+        "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java",
+        "tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
+        "tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
+        "tests/src/**/systemui/toast/ToastUITest.java",
     ],
     visibility: ["//visibility:private"],
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 0b18110..a984b7d 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1148,6 +1148,13 @@
 }
 
 flag {
+  name: "media_controls_button_media3_placement"
+  namespace: "systemui"
+  description: "Use media3 API for action button placement preferences"
+  bug: "360196209"
+}
+
+flag {
   name: "media_controls_drawables_reuse"
   namespace: "systemui"
   description: "Re-use created media drawables for media controls"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt
index 855b6d0..587d3d9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SeekbarHapticPluginTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.haptics.msdl.msdlPlayer
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.VibratorHelper
@@ -141,11 +142,7 @@
         }
 
     private fun createPlugin() {
-        plugin =
-            SeekbarHapticPlugin(
-                vibratorHelper,
-                kosmos.fakeSystemClock,
-            )
+        plugin = SeekbarHapticPlugin(vibratorHelper, kosmos.msdlPlayer, kosmos.fakeSystemClock)
     }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
index 28f88fe..3467382 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProviderTest.kt
@@ -16,16 +16,26 @@
 
 package com.android.systemui.haptics.slider
 
+import android.os.VibrationAttributes
 import android.os.VibrationEffect
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.haptics.fakeVibratorHelper
+import com.android.systemui.haptics.msdl.fakeMSDLPlayer
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import com.android.systemui.util.time.fakeSystemClock
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.InteractionProperties
+import com.google.common.truth.Truth.assertThat
 import kotlin.math.max
 import kotlin.test.assertEquals
 import kotlin.test.assertTrue
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -35,6 +45,7 @@
 class SliderHapticFeedbackProviderTest : SysuiTestCase() {
 
     private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
 
     private val config = SliderHapticFeedbackConfig()
 
@@ -44,7 +55,14 @@
     private val dragTextureThresholdMillis =
         lowTickDuration * config.numberOfLowTicks + config.deltaMillisForDragInterval
     private val vibratorHelper = kosmos.fakeVibratorHelper
+    private val msdlPlayer = kosmos.fakeMSDLPlayer
     private lateinit var sliderHapticFeedbackProvider: SliderHapticFeedbackProvider
+    private val pipeliningAttributes =
+        VibrationAttributes.Builder()
+            .setUsage(VibrationAttributes.USAGE_TOUCH)
+            .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT)
+            .build()
+    private lateinit var dynamicProperties: InteractionProperties.DynamicVibrationScale
 
     @Before
     fun setup() {
@@ -54,13 +72,20 @@
         sliderHapticFeedbackProvider =
             SliderHapticFeedbackProvider(
                 vibratorHelper,
+                msdlPlayer,
                 dragVelocityProvider,
                 config,
                 kosmos.fakeSystemClock,
             )
+        dynamicProperties =
+            InteractionProperties.DynamicVibrationScale(
+                sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
+                pipeliningAttributes,
+            )
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtLowerBookend_playsClick() =
         with(kosmos) {
             val vibration =
@@ -77,6 +102,18 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtLowerBookend_playsDragThresholdLimitToken() =
+        testScope.runTest {
+            sliderHapticFeedbackProvider.onLowerBookend()
+
+            assertThat(msdlPlayer.latestTokenPlayed)
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(dynamicProperties)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtLowerBookend_twoTimes_playsClickOnlyOnce() =
         with(kosmos) {
             val vibration =
@@ -94,6 +131,20 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtLowerBookend_twoTimes_playsDragThresholdLimitTokenOnlyOnce() =
+        testScope.runTest {
+            sliderHapticFeedbackProvider.onLowerBookend()
+            sliderHapticFeedbackProvider.onLowerBookend()
+
+            assertThat(msdlPlayer.latestTokenPlayed)
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(dynamicProperties)
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(1)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtUpperBookend_playsClick() =
         with(kosmos) {
             val vibration =
@@ -110,6 +161,18 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtUpperBookend_playsDragThresholdLimitToken() =
+        testScope.runTest {
+            sliderHapticFeedbackProvider.onUpperBookend()
+
+            assertThat(msdlPlayer.latestTokenPlayed)
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(dynamicProperties)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtUpperBookend_twoTimes_playsClickOnlyOnce() =
         with(kosmos) {
             val vibration =
@@ -127,6 +190,20 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtUpperBookend_twoTimes_playsDragThresholdLimitTokenOnlyOnce() =
+        testScope.runTest {
+            sliderHapticFeedbackProvider.onUpperBookend()
+            sliderHapticFeedbackProvider.onUpperBookend()
+
+            assertThat(msdlPlayer.latestTokenPlayed)
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(dynamicProperties)
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(1)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtProgress_onQuickSuccession_playsLowTicksOnce() =
         with(kosmos) {
             // GIVEN max velocity and slider progress
@@ -150,6 +227,31 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtProgress_onQuickSuccession_playsContinuousDragTokenOnce() =
+        with(kosmos) {
+            // GIVEN max velocity and slider progress
+            val progress = 1f
+            val expectedScale =
+                sliderHapticFeedbackProvider.scaleOnDragTexture(config.maxVelocityToScale, progress)
+            val expectedProperties =
+                InteractionProperties.DynamicVibrationScale(expectedScale, pipeliningAttributes)
+
+            // GIVEN system running for 1s
+            fakeSystemClock.advanceTime(1000)
+
+            // WHEN two calls to play occur immediately
+            sliderHapticFeedbackProvider.onProgress(progress)
+            sliderHapticFeedbackProvider.onProgress(progress)
+
+            // THEN the correct token plays once
+            assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.DRAG_INDICATOR_CONTINUOUS)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(expectedProperties)
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(1)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtProgress_beforeNextDragThreshold_playsLowTicksOnce() =
         with(kosmos) {
             // GIVEN max velocity and a slider progress at half progress
@@ -175,6 +277,41 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtProgress_beforeNextDragThreshold_playsContinousDragTokenOnce() =
+        with(kosmos) {
+            // GIVEN max velocity and a slider progress at half progress
+            val firstProgress = 0.5f
+
+            // Given a second slider progress event smaller than the progress threshold
+            val secondProgress =
+                firstProgress + max(0f, config.deltaProgressForDragThreshold - 0.01f)
+
+            // GIVEN system running for 1s
+            fakeSystemClock.advanceTime(1000)
+
+            // WHEN two calls to play occur with the required threshold separation (time and
+            // progress)
+            sliderHapticFeedbackProvider.onProgress(firstProgress)
+            fakeSystemClock.advanceTime(dragTextureThresholdMillis.toLong())
+            sliderHapticFeedbackProvider.onProgress(secondProgress)
+
+            // THEN Only the first event plays the expected token and propertiesv
+            val expectedProperties =
+                InteractionProperties.DynamicVibrationScale(
+                    sliderHapticFeedbackProvider.scaleOnDragTexture(
+                        config.maxVelocityToScale,
+                        firstProgress,
+                    ),
+                    pipeliningAttributes,
+                )
+            assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.DRAG_INDICATOR_CONTINUOUS)
+            assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(expectedProperties)
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(1)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtProgress_afterNextDragThreshold_playsLowTicksTwice() =
         with(kosmos) {
             // GIVEN max velocity and a slider progress at half progress
@@ -200,6 +337,51 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtProgress_afterNextDragThreshold_playsContinuousDragTokenTwice() =
+        with(kosmos) {
+            // GIVEN max velocity and a slider progress at half progress
+            val firstProgress = 0.5f
+
+            // Given a second slider progress event beyond progress threshold
+            val secondProgress = firstProgress + config.deltaProgressForDragThreshold + 0.01f
+
+            // GIVEN system running for 1s
+            fakeSystemClock.advanceTime(1000)
+
+            // WHEN two calls to play occur with the required threshold separation (time and
+            // progress)
+            sliderHapticFeedbackProvider.onProgress(firstProgress)
+            fakeSystemClock.advanceTime(dragTextureThresholdMillis.toLong())
+            sliderHapticFeedbackProvider.onProgress(secondProgress)
+
+            // THEN the correct token plays twice with the correct properties
+            val firstProperties =
+                InteractionProperties.DynamicVibrationScale(
+                    sliderHapticFeedbackProvider.scaleOnDragTexture(
+                        config.maxVelocityToScale,
+                        firstProgress,
+                    ),
+                    pipeliningAttributes,
+                )
+            val secondProperties =
+                InteractionProperties.DynamicVibrationScale(
+                    sliderHapticFeedbackProvider.scaleOnDragTexture(
+                        config.maxVelocityToScale,
+                        secondProgress,
+                    ),
+                    pipeliningAttributes,
+                )
+
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(2)
+            assertThat(msdlPlayer.tokensPlayed[0]).isEqualTo(MSDLToken.DRAG_INDICATOR_CONTINUOUS)
+            assertThat(msdlPlayer.propertiesPlayed[0]).isEqualTo(firstProperties)
+            assertThat(msdlPlayer.tokensPlayed[1]).isEqualTo(MSDLToken.DRAG_INDICATOR_CONTINUOUS)
+            assertThat(msdlPlayer.propertiesPlayed[1]).isEqualTo(secondProperties)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtLowerBookend_afterPlayingAtProgress_playsTwice() =
         with(kosmos) {
             // GIVEN max velocity and slider progress
@@ -233,6 +415,36 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtLowerBookend_afterPlayingAtProgress_playsTokensTwice() =
+        with(kosmos) {
+            // GIVEN max velocity and slider progress
+            val progress = 1f
+            val expectedProperties =
+                InteractionProperties.DynamicVibrationScale(
+                    sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
+                    pipeliningAttributes,
+                )
+
+            // GIVEN a vibration at the lower bookend followed by a request to vibrate at progress
+            sliderHapticFeedbackProvider.onLowerBookend()
+            sliderHapticFeedbackProvider.onProgress(progress)
+
+            // WHEN a vibration is to trigger again at the lower bookend
+            sliderHapticFeedbackProvider.onLowerBookend()
+
+            // THEN there are two bookend token vibrations
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(2)
+            assertThat(msdlPlayer.tokensPlayed[0])
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.propertiesPlayed[0]).isEqualTo(expectedProperties)
+            assertThat(msdlPlayer.tokensPlayed[1])
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.propertiesPlayed[1]).isEqualTo(expectedProperties)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
     fun playHapticAtUpperBookend_afterPlayingAtProgress_playsTwice() =
         with(kosmos) {
             // GIVEN max velocity and slider progress
@@ -265,6 +477,36 @@
             )
         }
 
+    @Test
+    @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+    fun playHapticAtUpperBookend_afterPlayingAtProgress_playsTokensTwice() =
+        with(kosmos) {
+            // GIVEN max velocity and slider progress
+            val progress = 1f
+            val expectedProperties =
+                InteractionProperties.DynamicVibrationScale(
+                    sliderHapticFeedbackProvider.scaleOnEdgeCollision(config.maxVelocityToScale),
+                    pipeliningAttributes,
+                )
+
+            // GIVEN a vibration at the upper bookend followed by a request to vibrate at progress
+            sliderHapticFeedbackProvider.onUpperBookend()
+            sliderHapticFeedbackProvider.onProgress(progress)
+
+            // WHEN a vibration is to trigger again at the upper bookend
+            sliderHapticFeedbackProvider.onUpperBookend()
+
+            // THEN there are two bookend vibrations
+            assertThat(msdlPlayer.getHistory().size).isEqualTo(2)
+            assertThat(msdlPlayer.tokensPlayed[0])
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.propertiesPlayed[0]).isEqualTo(expectedProperties)
+            assertThat(msdlPlayer.tokensPlayed[1])
+                .isEqualTo(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT)
+            assertThat(msdlPlayer.propertiesPlayed[1]).isEqualTo(expectedProperties)
+        }
+
+    @Test
     fun dragTextureLastProgress_afterDragTextureHaptics_keepsLastDragTextureProgress() =
         with(kosmos) {
             // GIVEN max velocity and a slider progress at half progress
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
deleted file mode 100644
index 28d53c7..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2022 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.screenshot
-
-import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
-
-internal class FakeScreenshotPolicy : ScreenshotPolicy {
-
-    private val userTypes = mutableMapOf<Int, Boolean>()
-    private val contentInfo = mutableMapOf<Int, DisplayContentInfo?>()
-
-    fun setManagedProfile(userId: Int, managedUser: Boolean) {
-        userTypes[userId] = managedUser
-    }
-    override suspend fun isManagedProfile(userId: Int): Boolean {
-        return userTypes[userId] ?: error("No managedProfile value set for userId $userId")
-    }
-
-    fun setDisplayContentInfo(userId: Int, contentInfo: DisplayContentInfo) {
-        this.contentInfo[userId] = contentInfo
-    }
-
-    override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
-        return contentInfo[displayId] ?: error("No DisplayContentInfo set for displayId $displayId")
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
index fb91c78..080f46f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
+import com.google.android.msdl.domain.MSDLPlayer
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
@@ -46,34 +47,26 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.notNull
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 class BrightnessSliderControllerTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var brightnessSliderView: BrightnessSliderView
-    @Mock
-    private lateinit var enforcedAdmin: RestrictedLockUtils.EnforcedAdmin
-    @Mock
-    private lateinit var mirrorController: BrightnessMirrorController
-    @Mock
-    private lateinit var mirror: ToggleSlider
-    @Mock
-    private lateinit var motionEvent: MotionEvent
-    @Mock
-    private lateinit var listener: ToggleSlider.Listener
-    @Mock
-    private lateinit var vibratorHelper: VibratorHelper
-    @Mock
-    private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var brightnessSliderView: BrightnessSliderView
+    @Mock private lateinit var enforcedAdmin: RestrictedLockUtils.EnforcedAdmin
+    @Mock private lateinit var mirrorController: BrightnessMirrorController
+    @Mock private lateinit var mirror: ToggleSlider
+    @Mock private lateinit var motionEvent: MotionEvent
+    @Mock private lateinit var listener: ToggleSlider.Listener
+    @Mock private lateinit var vibratorHelper: VibratorHelper
+    @Mock private lateinit var msdlPlayer: MSDLPlayer
+    @Mock private lateinit var activityStarter: ActivityStarter
 
     @Captor
     private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener>
-    @Mock
-    private lateinit var seekBar: SeekBar
+    @Mock private lateinit var seekBar: SeekBar
     private val uiEventLogger = UiEventLoggerFake()
     private var mFalsingManager: FalsingManagerFake = FalsingManagerFake()
     private val systemClock = FakeSystemClock()
@@ -93,7 +86,7 @@
                 brightnessSliderView,
                 mFalsingManager,
                 uiEventLogger,
-                SeekbarHapticPlugin(vibratorHelper, systemClock),
+                SeekbarHapticPlugin(vibratorHelper, msdlPlayer, systemClock),
                 activityStarter,
             )
         mController.init()
@@ -241,4 +234,4 @@
         assertThat(uiEventLogger.numLogs()).isEqualTo(1)
         assertThat(uiEventLogger.eventId(0)).isEqualTo(event.id)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index cfac486..ea5c29e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -66,7 +65,6 @@
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -100,7 +98,6 @@
     @Mock private VisibilityLocationProvider mVisibilityLocationProvider;
     @Mock private VisualStabilityProvider mVisualStabilityProvider;
     @Mock private VisualStabilityCoordinatorLogger mLogger;
-    @Mock private KeyguardStateController mKeyguardStateController;
 
     @Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor;
     @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor;
@@ -141,7 +138,6 @@
                 mKosmos.getCommunalSceneInteractor(),
                 mKosmos.getShadeInteractor(),
                 mKosmos.getKeyguardTransitionInteractor(),
-                mKeyguardStateController,
                 mLogger);
         mCoordinator.attach(mNotifPipeline);
         mTestScope.getTestScheduler().runCurrent();
@@ -526,13 +522,23 @@
     @EnableFlags(Flags.FLAG_CHECK_LOCKSCREEN_GONE_TRANSITION)
     public void testNotLockscreenInGoneTransition_invalidationCalled() {
         // GIVEN visual stability is being maintained b/c animation is playing
-        doReturn(true).when(mKeyguardStateController).isKeyguardFadingAway();
-        mCoordinator.mKeyguardFadeAwayAnimationCallback.onKeyguardFadingAwayChanged();
+        mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava(
+                mTestScope, new TransitionStep(
+                        KeyguardState.LOCKSCREEN,
+                        KeyguardState.GONE,
+                        1f,
+                        TransitionState.RUNNING),  /* validateStep = */ false);
+        mTestScope.getTestScheduler().runCurrent();
         assertFalse(mNotifStabilityManager.isPipelineRunAllowed());
 
         // WHEN the animation has stopped playing
-        doReturn(false).when(mKeyguardStateController).isKeyguardFadingAway();
-        mCoordinator.mKeyguardFadeAwayAnimationCallback.onKeyguardFadingAwayChanged();
+        mKosmos.getKeyguardTransitionRepository().sendTransitionStepJava(
+                mTestScope, new TransitionStep(
+                        KeyguardState.LOCKSCREEN,
+                        KeyguardState.GONE,
+                        1f,
+                        TransitionState.FINISHED),  /* validateStep = */ false);
+        mTestScope.getTestScheduler().runCurrent();
 
         // invalidate is called, b/c we were previously suppressing the pipeline from running
         verifyStabilityManagerWasInvalidated(times(1));
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
index 932e5af..cc77f68a 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekbarHapticPlugin.kt
@@ -22,6 +22,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.statusbar.VibratorHelper
 import com.android.systemui.util.time.SystemClock
+import com.google.android.msdl.domain.MSDLPlayer
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
@@ -39,6 +40,7 @@
 @JvmOverloads
 constructor(
     vibratorHelper: VibratorHelper,
+    msdlPlayer: MSDLPlayer,
     systemClock: SystemClock,
     sliderHapticFeedbackConfig: SliderHapticFeedbackConfig = SliderHapticFeedbackConfig(),
     private val sliderTrackerConfig: SeekableSliderTrackerConfig = SeekableSliderTrackerConfig(),
@@ -63,6 +65,7 @@
     private val sliderHapticFeedbackProvider =
         SliderHapticFeedbackProvider(
             vibratorHelper,
+            msdlPlayer,
             dragVelocityProvider,
             sliderHapticFeedbackConfig,
             systemClock,
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
index 06428b7..bc4f531 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt
@@ -22,7 +22,11 @@
 import android.view.animation.AccelerateInterpolator
 import androidx.annotation.FloatRange
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.Flags
 import com.android.systemui.statusbar.VibratorHelper
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.InteractionProperties
+import com.google.android.msdl.domain.MSDLPlayer
 import kotlin.math.abs
 import kotlin.math.min
 import kotlin.math.pow
@@ -38,6 +42,7 @@
  */
 class SliderHapticFeedbackProvider(
     private val vibratorHelper: VibratorHelper,
+    private val msdlPlayer: MSDLPlayer,
     private val velocityProvider: SliderDragVelocityProvider,
     private val config: SliderHapticFeedbackConfig = SliderHapticFeedbackConfig(),
     private val clock: com.android.systemui.util.time.SystemClock,
@@ -67,11 +72,20 @@
      */
     private fun vibrateOnEdgeCollision(absoluteVelocity: Float) {
         val powerScale = scaleOnEdgeCollision(absoluteVelocity)
-        val vibration =
-            VibrationEffect.startComposition()
-                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, powerScale)
-                .compose()
-        vibratorHelper.vibrate(vibration, VIBRATION_ATTRIBUTES_PIPELINING)
+        if (Flags.msdlFeedback()) {
+            val properties =
+                InteractionProperties.DynamicVibrationScale(
+                    powerScale,
+                    VIBRATION_ATTRIBUTES_PIPELINING,
+                )
+            msdlPlayer.playToken(MSDLToken.DRAG_THRESHOLD_INDICATOR_LIMIT, properties)
+        } else {
+            val vibration =
+                VibrationEffect.startComposition()
+                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, powerScale)
+                    .compose()
+            vibratorHelper.vibrate(vibration, VIBRATION_ATTRIBUTES_PIPELINING)
+        }
     }
 
     /**
@@ -112,16 +126,26 @@
 
         val powerScale = scaleOnDragTexture(absoluteVelocity, normalizedSliderProgress)
 
-        // Trigger the vibration composition
-        val composition = VibrationEffect.startComposition()
-        repeat(config.numberOfLowTicks) {
-            composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK, powerScale)
-        }
-        vibratorHelper.vibrate(composition.compose(), VIBRATION_ATTRIBUTES_PIPELINING)
+        // Deliver haptic feedback
+        performContinuousSliderDragVibration(powerScale)
         dragTextureLastTime = currentTime
         dragTextureLastProgress = normalizedSliderProgress
     }
 
+    private fun performContinuousSliderDragVibration(scale: Float) {
+        if (Flags.msdlFeedback()) {
+            val properties =
+                InteractionProperties.DynamicVibrationScale(scale, VIBRATION_ATTRIBUTES_PIPELINING)
+            msdlPlayer.playToken(MSDLToken.DRAG_INDICATOR_CONTINUOUS, properties)
+        } else {
+            val composition = VibrationEffect.startComposition()
+            repeat(config.numberOfLowTicks) {
+                composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK, scale)
+            }
+            vibratorHelper.vibrate(composition.compose(), VIBRATION_ATTRIBUTES_PIPELINING)
+        }
+    }
+
     /**
      * Get the scale of the drag texture vibration.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
index 1dbcb3df..de24259 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.statusbar.VibratorHelper
 import com.android.systemui.util.time.SystemClock
+import com.google.android.msdl.domain.MSDLPlayer
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -50,6 +51,7 @@
     @Assisted private val sliderHapticFeedbackConfig: SliderHapticFeedbackConfig,
     @Assisted private val sliderTrackerConfig: SeekableSliderTrackerConfig,
     vibratorHelper: VibratorHelper,
+    msdlPlayer: MSDLPlayer,
     systemClock: SystemClock,
 ) : ExclusiveActivatable() {
 
@@ -78,6 +80,7 @@
     private val sliderHapticFeedbackProvider =
         SliderHapticFeedbackProvider(
             vibratorHelper,
+            msdlPlayer,
             dragVelocityProvider,
             sliderHapticFeedbackConfig,
             systemClock,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
deleted file mode 100644
index f73d204..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 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.screenshot
-
-import android.annotation.UserIdInt
-import android.content.ComponentName
-import android.graphics.Rect
-import android.os.UserHandle
-import android.view.Display
-
-/**
- * Provides policy decision-making information to screenshot request handling.
- */
-interface ScreenshotPolicy {
-
-    /** @return true if the user is a managed profile (a.k.a. work profile) */
-    suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean
-
-    /**
-     * Requests information about the owner of display content which occupies a majority of the
-     * screenshot and/or has most recently been interacted with at the time the screenshot was
-     * requested.
-     *
-     * @param displayId the id of the display to inspect
-     * @return content info for the primary content on the display
-     */
-    suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo
-
-    data class DisplayContentInfo(
-        val component: ComponentName,
-        val bounds: Rect,
-        val user: UserHandle,
-        val taskId: Int,
-    )
-
-    fun getDefaultDisplayId(): Int = Display.DEFAULT_DISPLAY
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
deleted file mode 100644
index 21a7310..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2022 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.screenshot
-
-import android.annotation.UserIdInt
-import android.app.ActivityTaskManager
-import android.app.ActivityTaskManager.RootTaskInfo
-import android.app.IActivityTaskManager
-import android.app.WindowConfiguration
-import android.app.WindowConfiguration.activityTypeToString
-import android.app.WindowConfiguration.windowingModeToString
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.graphics.Rect
-import android.os.Process
-import android.os.RemoteException
-import android.os.UserHandle
-import android.os.UserManager
-import android.util.Log
-import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.infra.ServiceConnector
-import com.android.systemui.SystemUIService
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.settings.DisplayTracker
-import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
-import java.util.Arrays
-import javax.inject.Inject
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.withContext
-
-@SysUISingleton
-internal open class ScreenshotPolicyImpl @Inject constructor(
-    context: Context,
-    private val userMgr: UserManager,
-    private val atmService: IActivityTaskManager,
-    @Background val bgDispatcher: CoroutineDispatcher,
-    private val displayTracker: DisplayTracker
-) : ScreenshotPolicy {
-
-    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
-        ServiceConnector.Impl(
-            context,
-            Intent(context, ScreenshotProxyService::class.java),
-            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
-            context.userId,
-            IScreenshotProxy.Stub::asInterface
-        )
-
-    override fun getDefaultDisplayId(): Int {
-        return displayTracker.defaultDisplayId
-    }
-
-    override suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean {
-        val managed = withContext(bgDispatcher) { userMgr.isManagedProfile(userId) }
-        Log.d(TAG, "isManagedProfile: $managed")
-        return managed
-    }
-
-    private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
-        if (DEBUG) {
-            debugLogRootTaskInfo(info)
-        }
-        return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
-            info.isVisible &&
-            info.isRunning &&
-            info.numActivities > 0 &&
-            info.topActivity != null &&
-            info.childTaskIds.isNotEmpty()
-    }
-
-    /**
-     * Uses RootTaskInfo from ActivityTaskManager to guess at the primary focused task within a
-     * display. If no task is visible or the top task is covered by a system window, the info
-     * reported will reference a SystemUI component instead.
-     */
-    override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
-        // Determine if the notification shade is expanded. If so, task windows are not
-        // visible behind it, so the screenshot should instead be associated with SystemUI.
-        if (isNotificationShadeExpanded()) {
-            return systemUiContent
-        }
-
-        val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
-
-        // If no visible task is located, then report SystemUI as the foreground content
-        val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent
-        return target.toDisplayContentInfo()
-    }
-
-    private fun debugLogRootTaskInfo(info: RootTaskInfo) {
-        Log.d(TAG, "RootTaskInfo={" +
-                "taskId=${info.taskId} " +
-                "parentTaskId=${info.parentTaskId} " +
-                "position=${info.position} " +
-                "positionInParent=${info.positionInParent} " +
-                "isVisible=${info.isVisible()} " +
-                "visible=${info.visible} " +
-                "isFocused=${info.isFocused} " +
-                "isSleeping=${info.isSleeping} " +
-                "isRunning=${info.isRunning} " +
-                "windowMode=${windowingModeToString(info.windowingMode)} " +
-                "activityType=${activityTypeToString(info.activityType)} " +
-                "topActivity=${info.topActivity} " +
-                "topActivityInfo=${info.topActivityInfo} " +
-                "numActivities=${info.numActivities} " +
-                "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
-                "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
-                "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
-                "childTaskNames=${Arrays.toString(info.childTaskNames)}" +
-                "}"
-        )
-
-        for (j in 0 until info.childTaskIds.size) {
-            Log.d(TAG, "    *** [$j] ******")
-            Log.d(TAG, "        ***  childTaskIds[$j]: ${info.childTaskIds[j]}")
-            Log.d(TAG, "        ***  childTaskUserIds[$j]: ${info.childTaskUserIds[j]}")
-            Log.d(TAG, "        ***  childTaskBounds[$j]: ${info.childTaskBounds[j]}")
-            Log.d(TAG, "        ***  childTaskNames[$j]: ${info.childTaskNames[j]}")
-        }
-    }
-
-    @VisibleForTesting
-    open suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
-        withContext(bgDispatcher) {
-            try {
-                atmService.getAllRootTaskInfosOnDisplay(displayId)
-            } catch (e: RemoteException) {
-                Log.e(TAG, "getAllRootTaskInfosOnDisplay", e)
-                listOf()
-            }
-        }
-
-    @VisibleForTesting
-    open suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
-        proxyConnector
-            .postForResult { it.isNotificationShadeExpanded }
-            .whenComplete { expanded, error ->
-                if (error != null) {
-                    Log.e(TAG, "isNotificationShadeExpanded", error)
-                }
-                k.resume(expanded ?: false)
-            }
-    }
-
-    @VisibleForTesting
-    internal val systemUiContent =
-        DisplayContentInfo(
-            ComponentName(context, SystemUIService::class.java),
-            Rect(),
-            Process.myUserHandle(),
-            ActivityTaskManager.INVALID_TASK_ID
-        )
-}
-
-private const val TAG: String = "ScreenshotPolicyImpl"
-private const val DEBUG: Boolean = false
-
-@VisibleForTesting
-internal fun RootTaskInfo.toDisplayContentInfo(): DisplayContentInfo {
-    val topActivity: ComponentName = topActivity ?: error("should not be null")
-    val topChildTask = childTaskIds.size - 1
-    val childTaskId = childTaskIds[topChildTask]
-    val childTaskUserId = childTaskUserIds[topChildTask]
-    val childTaskBounds = childTaskBounds[topChildTask]
-
-    return DisplayContentInfo(
-        topActivity,
-        childTaskBounds,
-        UserHandle.of(childTaskUserId),
-        childTaskId)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 254dde4..90695fa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -27,8 +27,6 @@
 import com.android.systemui.screenshot.InteractiveScreenshotHandler;
 import com.android.systemui.screenshot.LegacyScreenshotController;
 import com.android.systemui.screenshot.ScreenshotController;
-import com.android.systemui.screenshot.ScreenshotPolicy;
-import com.android.systemui.screenshot.ScreenshotPolicyImpl;
 import com.android.systemui.screenshot.ScreenshotSoundController;
 import com.android.systemui.screenshot.ScreenshotSoundControllerImpl;
 import com.android.systemui.screenshot.ScreenshotSoundProvider;
@@ -66,9 +64,6 @@
             TakeScreenshotExecutorImpl impl);
 
     @Binds
-    abstract ScreenshotPolicy bindScreenshotPolicyImpl(ScreenshotPolicyImpl impl);
-
-    @Binds
     abstract ImageCapture bindImageCaptureImpl(ImageCaptureImpl capture);
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 75165cb..8703f68 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -40,6 +40,8 @@
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.time.SystemClock;
 
+import com.google.android.msdl.domain.MSDLPlayer;
+
 import javax.inject.Inject;
 
 /**
@@ -283,12 +285,14 @@
         private final VibratorHelper mVibratorHelper;
         private final SystemClock mSystemClock;
         private final ActivityStarter mActivityStarter;
+        private final MSDLPlayer mMSDLPlayer;
 
         @Inject
         public Factory(
                 FalsingManager falsingManager,
                 UiEventLogger uiEventLogger,
                 VibratorHelper vibratorHelper,
+                MSDLPlayer msdlPlayer,
                 SystemClock clock,
                 ActivityStarter activityStarter
         ) {
@@ -297,6 +301,7 @@
             mVibratorHelper = vibratorHelper;
             mSystemClock = clock;
             mActivityStarter = activityStarter;
+            mMSDLPlayer = msdlPlayer;
         }
 
         /**
@@ -314,6 +319,7 @@
                     .inflate(layout, viewRoot, false);
             SeekbarHapticPlugin plugin = new SeekbarHapticPlugin(
                     mVibratorHelper,
+                    mMSDLPlayer,
                     mSystemClock);
             HapticSliderViewBinder.bind(viewRoot, plugin);
             return new BrightnessSliderController(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 6edffc0..8660cd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -29,9 +29,11 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.Edge;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
@@ -44,7 +46,6 @@
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.BooleanFlowOperators;
 import com.android.systemui.util.kotlin.JavaAdapter;
@@ -77,7 +78,6 @@
     private final CommunalSceneInteractor mCommunalSceneInteractor;
     private final ShadeInteractor mShadeInteractor;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
-    private final KeyguardStateController mKeyguardStateController;
     private final VisualStabilityCoordinatorLogger mLogger;
 
     private boolean mSleepy = true;
@@ -120,7 +120,6 @@
             CommunalSceneInteractor communalSceneInteractor,
             ShadeInteractor shadeInteractor,
             KeyguardTransitionInteractor keyguardTransitionInteractor,
-            KeyguardStateController keyguardStateController,
             VisualStabilityCoordinatorLogger logger) {
         mHeadsUpManager = headsUpManager;
         mShadeAnimationInteractor = shadeAnimationInteractor;
@@ -134,7 +133,6 @@
         mCommunalSceneInteractor = communalSceneInteractor;
         mShadeInteractor = shadeInteractor;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
-        mKeyguardStateController = keyguardStateController;
         mLogger = logger;
 
         dumpManager.registerDumpable(this);
@@ -164,23 +162,17 @@
                             KeyguardState.LOCKSCREEN),
                     this::onLockscreenKeyguardStateTransitionValueChanged);
         }
-
         if (Flags.checkLockscreenGoneTransition()) {
-            mKeyguardStateController.addCallback(mKeyguardFadeAwayAnimationCallback);
+            mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition(
+                            Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone),
+                            Edge.create(KeyguardState.LOCKSCREEN, KeyguardState.GONE)),
+                    this::onLockscreenInGoneTransitionChanged);
         }
 
+
         pipeline.setVisualStabilityManager(mNotifStabilityManager);
     }
 
-    final KeyguardStateController.Callback mKeyguardFadeAwayAnimationCallback =
-            new KeyguardStateController.Callback() {
-                @Override
-                public void onKeyguardFadingAwayChanged() {
-                    onLockscreenInGoneTransitionChanged(
-                            mKeyguardStateController.isKeyguardFadingAway());
-                }
-            };
-
     // TODO(b/203826051): Ensure stability manager can allow reordering off-screen
     //  HUNs to the top of the shade
     private final NotifStabilityManager mNotifStabilityManager =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7c5116d..3d2ebf2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -140,6 +140,7 @@
 import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
 import com.android.systemui.volume.ui.navigation.VolumeNavigator;
 
+import com.google.android.msdl.domain.MSDLPlayer;
 import com.google.common.collect.ImmutableList;
 
 import dagger.Lazy;
@@ -315,6 +316,7 @@
     private final Lazy<SecureSettings> mSecureSettings;
     private int mDialogTimeoutMillis;
     private final VibratorHelper mVibratorHelper;
+    private final MSDLPlayer mMSDLPlayer;
     private final com.android.systemui.util.time.SystemClock mSystemClock;
     private final VolumePanelFlag mVolumePanelFlag;
     private final VolumeDialogInteractor mInteractor;
@@ -340,12 +342,14 @@
             DumpManager dumpManager,
             Lazy<SecureSettings> secureSettings,
             VibratorHelper vibratorHelper,
+            MSDLPlayer msdlPlayer,
             com.android.systemui.util.time.SystemClock systemClock,
             VolumeDialogInteractor interactor) {
         mContext =
                 new ContextThemeWrapper(context, R.style.volume_dialog_theme);
         mHandler = new H(looper);
         mVibratorHelper = vibratorHelper;
+        mMSDLPlayer = msdlPlayer;
         mSystemClock = systemClock;
         mShouldListenForJank = shouldListenForJank;
         mController = volumeDialogController;
@@ -927,7 +931,7 @@
     }
 
     private void addSliderHapticsToRow(VolumeRow row) {
-        row.createPlugin(mVibratorHelper, mSystemClock);
+        row.createPlugin(mVibratorHelper, mMSDLPlayer, mSystemClock);
         HapticSliderViewBinder.bind(row.slider, row.mHapticPlugin);
     }
 
@@ -2707,11 +2711,13 @@
 
         void createPlugin(
                 VibratorHelper vibratorHelper,
+                MSDLPlayer msdlPlayer,
                 com.android.systemui.util.time.SystemClock systemClock) {
             if (mHapticPlugin != null) return;
 
             mHapticPlugin = new SeekbarHapticPlugin(
                 vibratorHelper,
+                msdlPlayer,
                 systemClock,
                 sSliderHapticFeedbackConfig,
                 sSliderTrackerConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index ed8de69..2009143 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -50,6 +50,8 @@
 import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
 import com.android.systemui.volume.ui.navigation.VolumeNavigator;
 
+import com.google.android.msdl.domain.MSDLPlayer;
+
 import dagger.Binds;
 import dagger.Lazy;
 import dagger.Module;
@@ -121,6 +123,7 @@
             DumpManager dumpManager,
             Lazy<SecureSettings> secureSettings,
             VibratorHelper vibratorHelper,
+            MSDLPlayer msdlPlayer,
             SystemClock systemClock,
             VolumeDialogInteractor interactor) {
         if (Flags.volumeRedesign()) {
@@ -144,6 +147,7 @@
                     dumpManager,
                     secureSettings,
                     vibratorHelper,
+                    msdlPlayer,
                     systemClock,
                     interactor);
             impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 02d0b57..8039e00 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -281,13 +281,13 @@
     void initSplitScreen(SplitScreen splitScreen) {
         mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
             @Override
-            public void onFinishedWakingUp() {
-                splitScreen.onFinishedWakingUp();
+            public void onStartedGoingToSleep() {
+                splitScreen.onStartedGoingToSleep();
             }
 
             @Override
-            public void onStartedGoingToSleep() {
-                splitScreen.onStartedGoingToSleep();
+            public void onStartedWakingUp() {
+                splitScreen.onStartedWakingUp();
             }
         });
         mCommandQueue.addCallback(new CommandQueue.Callbacks() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index e981d62..cad22d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.keyguard;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.argThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
index dcf32a5..51c8525 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
@@ -38,11 +38,11 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
@@ -61,7 +61,7 @@
 private const val SMARTSPACE_KEY = "SMARTSPACE_KEY"
 
 private fun <T> anyObject(): T {
-    return Mockito.anyObject<T>()
+    return ArgumentMatchers.any<T>()
 }
 
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index bdd8dc8..2aa300d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -21,7 +21,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.mock;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 2f41ac17..338ed75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -19,9 +19,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.anyObject;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -194,7 +193,7 @@
 
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_SKIN));
     }
 
     @Test
@@ -207,7 +206,7 @@
 
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_USB_PORT));
     }
 
     @Test
@@ -220,7 +219,7 @@
 
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(0))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_SKIN));
     }
 
     @Test
@@ -233,7 +232,7 @@
 
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(0))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_USB_PORT));
     }
 
     @Test
@@ -243,14 +242,14 @@
 
         // success registering skin thermal event listener
         when(mThermalServiceMock.registerThermalEventListenerWithType(
-                anyObject(), eq(Temperature.TYPE_SKIN))).thenReturn(true);
+                any(), eq(Temperature.TYPE_SKIN))).thenReturn(true);
 
         mPowerUI.doSkinThermalEventListenerRegistration();
 
         // verify registering skin thermal event listener, return true (success)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_SKIN));
 
         // Settings SHOW_TEMPERATURE_WARNING is set to 0
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 0);
@@ -259,7 +258,7 @@
 
         // verify unregistering skin thermal event listener
         TestableLooper.get(this).processAllMessages();
-        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(anyObject());
+        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(any());
     }
 
     @Test
@@ -269,14 +268,14 @@
 
         // fail registering skin thermal event listener
         when(mThermalServiceMock.registerThermalEventListenerWithType(
-                anyObject(), eq(Temperature.TYPE_SKIN))).thenReturn(false);
+                any(), eq(Temperature.TYPE_SKIN))).thenReturn(false);
 
         mPowerUI.doSkinThermalEventListenerRegistration();
 
         // verify registering skin thermal event listener, return false (fail)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_SKIN));
 
         // Settings SHOW_TEMPERATURE_WARNING is set to 0
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 0);
@@ -285,7 +284,7 @@
 
         // verify that cannot unregister listener (current state is unregistered)
         TestableLooper.get(this).processAllMessages();
-        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(anyObject());
+        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(any());
 
         // Settings SHOW_TEMPERATURE_WARNING is set to 1
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);
@@ -295,7 +294,7 @@
         // verify that can register listener (current state is unregistered)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(2))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_SKIN));
     }
 
     @Test
@@ -305,14 +304,14 @@
 
         // success registering usb thermal event listener
         when(mThermalServiceMock.registerThermalEventListenerWithType(
-                anyObject(), eq(Temperature.TYPE_USB_PORT))).thenReturn(true);
+                any(), eq(Temperature.TYPE_USB_PORT))).thenReturn(true);
 
         mPowerUI.doUsbThermalEventListenerRegistration();
 
         // verify registering usb thermal event listener, return true (success)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_USB_PORT));
 
         // Settings SHOW_USB_TEMPERATURE_ALARM is set to 0
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 0);
@@ -320,7 +319,7 @@
         // verify unregistering usb thermal event listener
         mPowerUI.doUsbThermalEventListenerRegistration();
         TestableLooper.get(this).processAllMessages();
-        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(anyObject());
+        verify(mThermalServiceMock, times(1)).unregisterThermalEventListener(any());
     }
 
     @Test
@@ -330,14 +329,14 @@
 
         // fail registering usb thermal event listener
         when(mThermalServiceMock.registerThermalEventListenerWithType(
-                anyObject(), eq(Temperature.TYPE_USB_PORT))).thenReturn(false);
+                any(), eq(Temperature.TYPE_USB_PORT))).thenReturn(false);
 
         mPowerUI.doUsbThermalEventListenerRegistration();
 
         // verify registering usb thermal event listener, return false (fail)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(1))
-                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
+                .registerThermalEventListenerWithType(any(), eq(Temperature.TYPE_USB_PORT));
 
         // Settings SHOW_USB_TEMPERATURE_ALARM is set to 0
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 0);
@@ -346,7 +345,7 @@
 
         // verify that cannot unregister listener (current state is unregistered)
         TestableLooper.get(this).processAllMessages();
-        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(anyObject());
+        verify(mThermalServiceMock, times(0)).unregisterThermalEventListener(any());
 
         // Settings SHOW_USB_TEMPERATURE_ALARM is set to 1
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);
@@ -356,7 +355,7 @@
         // verify that can register listener (current state is unregistered)
         TestableLooper.get(this).processAllMessages();
         verify(mThermalServiceMock, times(2)).registerThermalEventListenerWithType(
-                anyObject(), eq(Temperature.TYPE_USB_PORT));
+                any(), eq(Temperature.TYPE_USB_PORT));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index dad65f5..f6d5732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -25,7 +25,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 748c7d9..296478b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -36,7 +36,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.argThat;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
deleted file mode 100644
index 3756ec1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2022 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.screenshot
-
-import android.app.ActivityTaskManager.RootTaskInfo
-import android.app.IActivityTaskManager
-import android.content.ComponentName
-import android.content.Context
-import android.graphics.Rect
-import android.os.UserHandle
-import android.os.UserManager
-import android.testing.AndroidTestingRunner
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
-import com.android.systemui.screenshot.policy.ActivityType.Home
-import com.android.systemui.screenshot.policy.ActivityType.Undefined
-import com.android.systemui.screenshot.policy.WindowingMode.FullScreen
-import com.android.systemui.screenshot.policy.WindowingMode.PictureInPicture
-import com.android.systemui.screenshot.policy.newChildTask
-import com.android.systemui.screenshot.policy.newRootTaskInfo
-import com.android.systemui.settings.FakeDisplayTracker
-import com.android.systemui.util.mockito.mock
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-import org.junit.runner.RunWith
-
-// The following values are chosen to be distinct from commonly seen real values
-private const val DISPLAY_ID = 100
-private const val PRIMARY_USER = 2000
-private const val MANAGED_PROFILE_USER = 3000
-
-@RunWith(AndroidTestingRunner::class)
-class ScreenshotPolicyImplTest : SysuiTestCase() {
-
-    @Test
-    fun testToDisplayContentInfo() {
-        assertThat(fullScreenWorkProfileTask.toDisplayContentInfo())
-            .isEqualTo(
-                DisplayContentInfo(
-                    ComponentName(
-                        "com.google.android.apps.nbu.files",
-                        "com.google.android.apps.nbu.files.home.HomeActivity"
-                    ),
-                    Rect(0, 0, 1080, 2400),
-                    UserHandle.of(MANAGED_PROFILE_USER),
-                    65
-                )
-            )
-    }
-
-    @Test
-    fun findPrimaryContent_ignoresPipTask() = runBlocking {
-        val policy =
-            fakeTasksPolicyImpl(
-                mContext,
-                shadeExpanded = false,
-                tasks = listOf(pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask)
-            )
-
-        val info = policy.findPrimaryContent(DISPLAY_ID)
-        assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo())
-    }
-
-    @Test
-    fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking {
-        val policy =
-            fakeTasksPolicyImpl(
-                mContext,
-                shadeExpanded = true,
-                tasks = listOf(fullScreenWorkProfileTask, launcherTask, emptyTask)
-            )
-
-        val info = policy.findPrimaryContent(DISPLAY_ID)
-        assertThat(info).isEqualTo(policy.systemUiContent)
-    }
-
-    @Test
-    fun findPrimaryContent_emptyTaskList() = runBlocking {
-        val policy = fakeTasksPolicyImpl(mContext, shadeExpanded = false, tasks = listOf())
-
-        val info = policy.findPrimaryContent(DISPLAY_ID)
-        assertThat(info).isEqualTo(policy.systemUiContent)
-    }
-
-    @Test
-    fun findPrimaryContent_workProfileNotOnTop() = runBlocking {
-        val policy =
-            fakeTasksPolicyImpl(
-                mContext,
-                shadeExpanded = false,
-                tasks = listOf(launcherTask, fullScreenWorkProfileTask, emptyTask)
-            )
-
-        val info = policy.findPrimaryContent(DISPLAY_ID)
-        assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo())
-    }
-
-    private fun fakeTasksPolicyImpl(
-        context: Context,
-        shadeExpanded: Boolean,
-        tasks: List<RootTaskInfo>
-    ): ScreenshotPolicyImpl {
-        val userManager = mock<UserManager>()
-        val atmService = mock<IActivityTaskManager>()
-        val dispatcher = Dispatchers.Unconfined
-        val displayTracker = FakeDisplayTracker(context)
-
-        return object :
-            ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) {
-            override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)
-            override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks
-            override suspend fun isNotificationShadeExpanded() = shadeExpanded
-        }
-    }
-
-    private val pipTask =
-        newRootTaskInfo(
-            taskId = 66,
-            userId = PRIMARY_USER,
-            displayId = DISPLAY_ID,
-            bounds = Rect(628, 1885, 1038, 2295),
-            windowingMode = PictureInPicture,
-            topActivity = ComponentName.unflattenFromString(YOUTUBE_PIP_ACTIVITY),
-        ) {
-            listOf(newChildTask(taskId = 66, userId = 0, name = YOUTUBE_HOME_ACTIVITY))
-        }
-
-    private val fullScreenWorkProfileTask =
-        newRootTaskInfo(
-            taskId = 65,
-            userId = MANAGED_PROFILE_USER,
-            displayId = DISPLAY_ID,
-            bounds = Rect(0, 0, 1080, 2400),
-            windowingMode = FullScreen,
-            topActivity = ComponentName.unflattenFromString(FILES_HOME_ACTIVITY),
-        ) {
-            listOf(
-                newChildTask(taskId = 65, userId = MANAGED_PROFILE_USER, name = FILES_HOME_ACTIVITY)
-            )
-        }
-    private val launcherTask =
-        newRootTaskInfo(
-            taskId = 1,
-            userId = PRIMARY_USER,
-            displayId = DISPLAY_ID,
-            activityType = Home,
-            windowingMode = FullScreen,
-            bounds = Rect(0, 0, 1080, 2400),
-            topActivity = ComponentName.unflattenFromString(LAUNCHER_ACTIVITY),
-        ) {
-            listOf(newChildTask(taskId = 1, userId = 0, name = LAUNCHER_ACTIVITY))
-        }
-
-    private val emptyTask =
-        newRootTaskInfo(
-            taskId = 2,
-            userId = PRIMARY_USER,
-            displayId = DISPLAY_ID,
-            visible = false,
-            running = false,
-            numActivities = 0,
-            activityType = Undefined,
-            bounds = Rect(0, 0, 1080, 2400),
-        ) {
-            listOf(
-                newChildTask(taskId = 3, name = ""),
-                newChildTask(taskId = 4, name = ""),
-            )
-        }
-}
-
-private const val YOUTUBE_HOME_ACTIVITY =
-    "com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity"
-
-private const val FILES_HOME_ACTIVITY =
-    "com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity"
-
-private const val YOUTUBE_PIP_ACTIVITY =
-    "com.google.android.youtube/" +
-        "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity"
-
-private const val LAUNCHER_ACTIVITY =
-    "com.google.android.apps.nexuslauncher/" +
-        "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
index 040a9e9..8bd8b72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package systemui.shared.clocks.view
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
index e9222c3e..3ad0605 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java
@@ -19,8 +19,8 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 2b5e014..b730b37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -21,8 +21,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
index b18b7f8..72ffa0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
@@ -16,41 +16,39 @@
 
 package com.android.systemui.statusbar.commandline
 
-import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
-
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-
-import org.mockito.ArgumentMatchers.anyList
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
 import java.io.PrintWriter
 import java.io.StringWriter
 import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyList
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 
 private fun <T> anyObject(): T {
-    return Mockito.anyObject<T>()
+    return any<T>()
 }
 
 private fun <T : Any> safeEq(value: T): T = eq(value) ?: value
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 @SmallTest
 class CommandRegistryTest : SysuiTestCase() {
     lateinit var registry: CommandRegistry
-    val inLineExecutor = object : Executor {
-        override fun execute(command: Runnable) {
-            command.run()
+    val inLineExecutor =
+        object : Executor {
+            override fun execute(command: Runnable) {
+                command.run()
+            }
         }
-    }
 
     val writer: PrintWriter = PrintWriter(StringWriter())
 
@@ -83,11 +81,9 @@
     }
 
     class FakeCommand() : Command {
-        override fun execute(pw: PrintWriter, args: List<String>) {
-        }
+        override fun execute(pw: PrintWriter, args: List<String>) {}
 
-        override fun help(pw: PrintWriter) {
-        }
+        override fun help(pw: PrintWriter) {}
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
index 7bd77a6..5fce08b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
@@ -18,7 +18,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.eq;
 
 import android.os.HandlerThread;
 import android.telephony.SubscriptionInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index 83dbfa0..b00f9e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -25,10 +25,10 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -297,7 +297,8 @@
         assertNotNull(mDefaultCallbackInWifiTracker);
         assertNotNull(mDefaultCallbackInNetworkController);
         verify(mMockCm, atLeastOnce()).registerNetworkCallback(
-                isA(NetworkRequest.class), callbackArg.capture(), isA(Handler.class));
+                isA(NetworkRequest.class), callbackArg.capture(),
+                isA(Handler.class));
         mNetworkCallback = callbackArg.getValue();
         assertNotNull(mNetworkCallback);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
index dcd57f1..c2460f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
@@ -17,30 +17,27 @@
 package com.android.systemui.statusbar.policy
 
 import android.app.NotificationManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
-
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
-
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 private fun <T> anyObject(): T {
-    return Mockito.anyObject<T>()
+    return any<T>()
 }
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper()
 @SmallTest
 class BatteryStateNotifierTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 9bb7607..f91f373 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -22,10 +22,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.argThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -120,9 +119,9 @@
 
         verify(mBroadcastDispatcher).registerReceiverWithHandler(
                 brCaptor.capture(),
-                anyObject(),
-                anyObject(),
-                anyObject());
+                any(),
+                any(),
+                any());
 
         mBroadcastReceiver = brCaptor.getValue();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index ecc7909..3007eab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -92,6 +92,7 @@
 import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag;
 import com.android.systemui.volume.ui.navigation.VolumeNavigator;
 
+import com.google.android.msdl.domain.MSDLPlayer;
 import com.google.common.collect.ImmutableList;
 
 import dagger.Lazy;
@@ -169,6 +170,9 @@
     @Mock
     private VibratorHelper mVibratorHelper;
 
+    @Mock
+    private MSDLPlayer mMSDLPlayer;
+
     private int mLongestHideShowAnimationDuration = 250;
     private FakeSettings mSecureSettings;
 
@@ -222,6 +226,7 @@
                 mDumpManager,
                 mLazySecureSettings,
                 mVibratorHelper,
+                mMSDLPlayer,
                 new FakeSystemClock(),
                 mVolumeDialogInteractor);
         mDialog.init(0, null);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
index 2b81da3..fe82ab9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
@@ -23,19 +23,24 @@
 import com.google.android.msdl.logging.MSDLEvent
 
 class FakeMSDLPlayer : MSDLPlayer {
+    val tokensPlayed = mutableListOf<MSDLToken>()
+    val propertiesPlayed = mutableListOf<InteractionProperties?>()
     private val history = arrayListOf<MSDLEvent>()
+
     var currentFeedbackLevel = FeedbackLevel.DEFAULT
     var latestTokenPlayed: MSDLToken? = null
+        get() = tokensPlayed.lastOrNull()
         private set
 
     var latestPropertiesPlayed: InteractionProperties? = null
+        get() = propertiesPlayed.lastOrNull()
         private set
 
     override fun getSystemFeedbackLevel(): FeedbackLevel = currentFeedbackLevel
 
     override fun playToken(token: MSDLToken, properties: InteractionProperties?) {
-        latestTokenPlayed = token
-        latestPropertiesPlayed = properties
+        tokensPlayed.add(token)
+        propertiesPlayed.add(properties)
         history.add(MSDLEvent(token, properties))
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt
index 257d758..3fbcf77 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/slider/SliderHapticsViewModelFactoryKosmos.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.interaction.InteractionSource
+import com.android.systemui.haptics.msdl.msdlPlayer
 import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
 import com.android.systemui.haptics.vibratorHelper
 import com.android.systemui.kosmos.Kosmos
@@ -40,6 +41,7 @@
                     sliderHapticFeedbackConfig,
                     sliderTrackerConfig,
                     vibratorHelper,
+                    msdlPlayer,
                     fakeSystemClock,
                 )
         }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
index 8b7e5d8..88063c9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
@@ -18,6 +18,7 @@
 
 import com.android.internal.logging.uiEventLogger
 import com.android.systemui.classifier.falsingManager
+import com.android.systemui.haptics.msdl.msdlPlayer
 import com.android.systemui.haptics.vibratorHelper
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.plugins.activityStarter
@@ -31,6 +32,7 @@
             falsingManager,
             uiEventLogger,
             vibratorHelper,
+            msdlPlayer,
             systemClock,
             activityStarter,
         )
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index a77ba62..ce1a292 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -64,6 +64,7 @@
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.Flags;
+import com.android.server.input.InputManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.util.ArrayList;
@@ -396,7 +397,7 @@
                             mCurrentMagnificationSpec.offsetX, mCurrentMagnificationSpec.offsetY)) {
                         sendSpecToAnimation(mCurrentMagnificationSpec, null);
                     }
-                    onMagnificationChangedLocked();
+                    onMagnificationChangedLocked(/* isScaleTransient= */ false);
                 }
                 magnified.recycle();
             }
@@ -474,8 +475,16 @@
             return mIdOfLastServiceToMagnify;
         }
 
+        /**
+         * This is invoked whenever magnification change happens.
+         *
+         * @param isScaleTransient represents that if the scale is being changed and the changed
+         *                         value may be short lived and be updated again soon.
+         *                         Calling the method usually notifies input manager to update the
+         *                         cursor scale, but setting this value {@code true} prevents it.
+         */
         @GuardedBy("mLock")
-        void onMagnificationChangedLocked() {
+        void onMagnificationChangedLocked(boolean isScaleTransient) {
             final float scale = getScale();
             final float centerX = getCenterX();
             final float centerY = getCenterY();
@@ -498,6 +507,10 @@
             } else {
                 hideThumbnail();
             }
+
+            if (!isScaleTransient) {
+                notifyScaleForInput(mDisplayId, scale);
+            }
         }
 
         @GuardedBy("mLock")
@@ -611,8 +624,9 @@
          * Directly Zooms out the scale to 1f with animating the transition. This method is
          * triggered only by service automatically, such as when user context changed.
          */
+        @GuardedBy("mLock")
         void zoomOutFromService() {
-            setScaleAndCenter(1.0f, Float.NaN, Float.NaN,
+            setScaleAndCenter(1.0f, Float.NaN, Float.NaN, /* isScaleTransient= */ false,
                     transformToStubCallback(true),
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             mZoomedOutFromService = true;
@@ -640,7 +654,7 @@
             setActivated(false);
             if (changed) {
                 spec.clear();
-                onMagnificationChangedLocked();
+                onMagnificationChangedLocked(/* isScaleTransient= */ false);
             }
             mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
             sendSpecToAnimation(spec, animationCallback);
@@ -651,7 +665,7 @@
         }
 
         @GuardedBy("mLock")
-        boolean setScale(float scale, float pivotX, float pivotY,
+        boolean setScale(float scale, float pivotX, float pivotY, boolean isScaleTransient,
                 boolean animate, int id) {
             if (!mRegistered) {
                 return false;
@@ -674,12 +688,14 @@
             final float centerX = normPivotX + offsetX;
             final float centerY = normPivotY + offsetY;
             mIdOfLastServiceToMagnify = id;
-            return setScaleAndCenter(scale, centerX, centerY, transformToStubCallback(animate), id);
+            return setScaleAndCenter(scale, centerX, centerY, isScaleTransient,
+                    transformToStubCallback(animate), id);
         }
 
         @GuardedBy("mLock")
         boolean setScaleAndCenter(float scale, float centerX, float centerY,
-                MagnificationAnimationCallback animationCallback, int id) {
+                boolean isScaleTransient, MagnificationAnimationCallback animationCallback,
+                int id) {
             if (!mRegistered) {
                 return false;
             }
@@ -696,7 +712,7 @@
                                 + animationCallback + ", id = " + id + ")");
             }
             boolean changed = setActivated(true);
-            changed |= updateMagnificationSpecLocked(scale, centerX, centerY);
+            changed |= updateMagnificationSpecLocked(scale, centerX, centerY, isScaleTransient);
             sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
             if (isActivated() && (id != INVALID_SERVICE_ID)) {
                 mIdOfLastServiceToMagnify = id;
@@ -773,7 +789,9 @@
          * @return {@code true} if the magnification spec changed or {@code false}
          *         otherwise
          */
-        boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY) {
+        @GuardedBy("mLock")
+        boolean updateMagnificationSpecLocked(float scale, float centerX, float centerY,
+                boolean isScaleTransient) {
             // Handle defaults.
             if (Float.isNaN(centerX)) {
                 centerX = getCenterX();
@@ -801,7 +819,7 @@
             changed |= updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
 
             if (changed) {
-                onMagnificationChangedLocked();
+                onMagnificationChangedLocked(isScaleTransient);
             }
 
             return changed;
@@ -816,7 +834,7 @@
             final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
             final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
             if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
-                onMagnificationChangedLocked();
+                onMagnificationChangedLocked(/* isScaleTransient= */ false);
             }
             if (id != INVALID_SERVICE_ID) {
                 mIdOfLastServiceToMagnify = id;
@@ -861,7 +879,7 @@
                             }
                             synchronized (mLock) {
                                 mCurrentMagnificationSpec.setTo(lastSpecSent);
-                                onMagnificationChangedLocked();
+                                onMagnificationChangedLocked(/* isScaleTransient= */ false);
                             }
                         }
                     });
@@ -955,6 +973,7 @@
                         context,
                         traceManager,
                         LocalServices.getService(WindowManagerInternal.class),
+                        LocalServices.getService(InputManagerInternal.class),
                         new Handler(context.getMainLooper()),
                         context.getResources().getInteger(R.integer.config_longAnimTime)),
                 lock,
@@ -1464,20 +1483,24 @@
      * @param scale the target scale, must be >= 1
      * @param pivotX the screen-relative X coordinate around which to scale
      * @param pivotY the screen-relative Y coordinate around which to scale
+     * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+     *                         soon. {@code false} otherwise.
      * @param animate {@code true} to animate the transition, {@code false}
      *                to transition immediately
      * @param id the ID of the service requesting the change
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
     public boolean setScale(int displayId, float scale, float pivotX, float pivotY,
-            boolean animate, int id) {
+            boolean isScaleTransient, boolean animate, int id) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
             if (display == null) {
                 return false;
             }
-            return display.setScale(scale, pivotX, pivotY, animate, id);
+            return display.setScale(scale, pivotX, pivotY, isScaleTransient, animate, id);
         }
     }
 
@@ -1496,6 +1519,8 @@
      * @return {@code true} if the magnification spec changed, {@code false} if
      * the spec did not change
      */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
     public boolean setCenter(int displayId, float centerX, float centerY, boolean animate, int id) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
@@ -1503,7 +1528,7 @@
                 return false;
             }
             return display.setScaleAndCenter(Float.NaN, centerX, centerY,
-                    animate ? STUB_ANIMATION_CALLBACK : null, id);
+                    /* isScaleTransient= */ false, animate ? STUB_ANIMATION_CALLBACK : null, id);
         }
     }
 
@@ -1526,7 +1551,32 @@
      */
     public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
             boolean animate, int id) {
-        return setScaleAndCenter(displayId, scale, centerX, centerY,
+        return setScaleAndCenter(displayId, scale, centerX, centerY, /* isScaleTransient= */ false,
+                transformToStubCallback(animate), id);
+    }
+
+    /**
+     * Sets the scale and center of the magnified region, optionally
+     * animating the transition. If animation is disabled, the transition
+     * is immediate.
+     *
+     * @param displayId        The logical display id.
+     * @param scale            the target scale, or {@link Float#NaN} to leave unchanged
+     * @param centerX          the screen-relative X coordinate around which to
+     *                         center and scale, or {@link Float#NaN} to leave unchanged
+     * @param centerY          the screen-relative Y coordinate around which to
+     *                         center and scale, or {@link Float#NaN} to leave unchanged
+     * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+     *                         soon. {@code false} otherwise.
+     * @param animate          {@code true} to animate the transition, {@code false}
+     *                         to transition immediately
+     * @param id               the ID of the service requesting the change
+     * @return {@code true} if the magnification spec changed, {@code false} if
+     * the spec did not change
+     */
+    public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+            boolean isScaleTransient, boolean animate, int id) {
+        return setScaleAndCenter(displayId, scale, centerX, centerY, isScaleTransient,
                 transformToStubCallback(animate), id);
     }
 
@@ -1541,20 +1591,25 @@
      *                center and scale, or {@link Float#NaN} to leave unchanged
      * @param centerY the screen-relative Y coordinate around which to
      *                center and scale, or {@link Float#NaN} to leave unchanged
+     * @param isScaleTransient {@code true} if the scale is for a short time and potentially changed
+     *                         soon. {@code false} otherwise.
      * @param animationCallback Called when the animation result is valid.
      *                           {@code null} to transition immediately
      * @param id the ID of the service requesting the change
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
     public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
-            MagnificationAnimationCallback animationCallback, int id) {
+            boolean isScaleTransient, MagnificationAnimationCallback animationCallback, int id) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
             if (display == null) {
                 return false;
             }
-            return display.setScaleAndCenter(scale, centerX, centerY, animationCallback, id);
+            return display.setScaleAndCenter(scale, centerX, centerY, isScaleTransient,
+                    animationCallback, id);
         }
     }
 
@@ -1569,6 +1624,8 @@
      *                screen pixels.
      * @param id      the ID of the service requesting the change
      */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
     public void offsetMagnifiedRegion(int displayId, float offsetX, float offsetY, int id) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
@@ -1640,6 +1697,8 @@
      */
     public void persistScale(int displayId) {
         final float scale = getScale(displayId);
+        notifyScaleForInput(displayId, scale);
+
         if (scale < MagnificationConstants.PERSISTED_SCALE_MIN_VALUE) {
             return;
         }
@@ -1665,6 +1724,8 @@
      *
      * @param displayId The logical display id.
      */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
     private void zoomOutFromService(int displayId) {
         synchronized (mLock) {
             final DisplayMagnification display = mDisplays.get(displayId);
@@ -1691,6 +1752,20 @@
     }
 
     /**
+     * Notifies input manager that magnification scale changed non-transiently
+     * so that pointer cursor is scaled as well.
+     *
+     * @param displayId The logical display id.
+     * @param scale     The new scale factor.
+     */
+    public void notifyScaleForInput(int displayId, float scale) {
+        if (Flags.magnificationEnlargePointer()) {
+            mControllerCtx.getInputManager()
+                    .setAccessibilityPointerIconScaleFactor(displayId, scale);
+        }
+    }
+
+    /**
      * Resets all displays' magnification if last magnifying service is disabled.
      *
      * @param connectionId
@@ -2166,6 +2241,7 @@
         private final Context mContext;
         private final AccessibilityTraceManager mTrace;
         private final WindowManagerInternal mWindowManager;
+        private final InputManagerInternal mInputManager;
         private final Handler mHandler;
         private final Long mAnimationDuration;
 
@@ -2175,11 +2251,13 @@
         public ControllerContext(@NonNull Context context,
                 @NonNull AccessibilityTraceManager traceManager,
                 @NonNull WindowManagerInternal windowManager,
+                @NonNull InputManagerInternal inputManager,
                 @NonNull Handler handler,
                 long animationDuration) {
             mContext = context;
             mTrace = traceManager;
             mWindowManager = windowManager;
+            mInputManager = inputManager;
             mHandler = handler;
             mAnimationDuration = animationDuration;
         }
@@ -2209,6 +2287,14 @@
         }
 
         /**
+         * @return InputManagerInternal
+         */
+        @NonNull
+        public InputManagerInternal getInputManager() {
+            return mInputManager;
+        }
+
+        /**
          * @return Handler for main looper
          */
         @NonNull
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 963334b..c6a966f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -617,7 +617,8 @@
             }
 
             if (DEBUG_PANNING_SCALING) Slog.i(mLogTag, "Scaled content to: " + scale + "x");
-            mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false,
+            mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY,
+                    /* isScaleTransient= */ true, /* animate= */ false,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
 
             checkShouldDetectPassPersistedScale();
@@ -1974,6 +1975,7 @@
                     /* scale= */ scale,
                     /* centerX= */ mPivotEdge.x,
                     /* centerY= */ mPivotEdge.y,
+                    /* isScaleTransient= */ true,
                     /* animate= */ true,
                     /* id= */ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             if (scale == 1.0f) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 1489d16..d40e747 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -176,7 +176,8 @@
     public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
         if (getFullScreenMagnificationController().isActivated(displayId)) {
             getFullScreenMagnificationController().setScaleAndCenter(displayId, scale,
-                    Float.NaN, Float.NaN, false, MAGNIFICATION_GESTURE_HANDLER_ID);
+                    Float.NaN, Float.NaN, /* isScaleTransient= */ !updatePersistence, false,
+                    MAGNIFICATION_GESTURE_HANDLER_ID);
             if (updatePersistence) {
                 getFullScreenMagnificationController().persistScale(displayId);
             }
@@ -371,7 +372,7 @@
                         }
                         screenMagnificationController.setScaleAndCenter(displayId, targetScale,
                                 magnificationCenter.x, magnificationCenter.y,
-                                magnificationAnimationCallback, id);
+                                /* isScaleTransient= */ false, magnificationAnimationCallback, id);
                     } else {
                         if (screenMagnificationController.isRegistered(displayId)) {
                             screenMagnificationController.reset(displayId, false);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c47cad9..28b606c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -3178,12 +3178,15 @@
             mStats.collectPowerStatsSamples();
         }
 
-        BatteryUsageStats batteryUsageStats =
-                mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, query);
-        if (proto) {
-            batteryUsageStats.dumpToProto(fd);
-        } else {
-            batteryUsageStats.dump(pw, "  ");
+        try (BatteryUsageStats batteryUsageStats =
+                     mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, query)) {
+            if (proto) {
+                batteryUsageStats.dumpToProto(fd);
+            } else {
+                batteryUsageStats.dump(pw, "  ");
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Cannot close BatteryUsageStats", e);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index ba4b71c..17fcbf4 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -22,7 +22,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.ProcessRecord.TAG;
-import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
+import static com.android.internal.os.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -58,7 +58,7 @@
 import com.android.modules.expresslog.Counter;
 import com.android.server.ResourcePressureUtil;
 import com.android.server.criticalevents.CriticalEventLog;
-import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.internal.os.ProcfsMemoryUtil.MemorySnapshot;
 import com.android.server.wm.WindowProcessController;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index 99f7f12..c888eef 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -262,4 +262,12 @@
      */
     public abstract void handleKeyGestureInKeyGestureController(int deviceId, int[] keycodes,
             int modifierState, @KeyGestureEvent.KeyGestureType int event);
+
+    /**
+     * Sets the magnification scale factor for pointer icons.
+     *
+     * @param displayId   the ID of the display where the new scale factor is applied.
+     * @param scaleFactor the new scale factor to be applied for pointer icons.
+     */
+    public abstract void setAccessibilityPointerIconScaleFactor(int displayId, float scaleFactor);
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8acf583..98e5319 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3506,6 +3506,11 @@
                 int modifierState, @KeyGestureEvent.KeyGestureType int gestureType) {
             mKeyGestureController.handleKeyGesture(deviceId, keycodes, modifierState, gestureType);
         }
+
+        @Override
+        public void setAccessibilityPointerIconScaleFactor(int displayId, float scaleFactor) {
+            InputManagerService.this.setAccessibilityPointerIconScaleFactor(displayId, scaleFactor);
+        }
     }
 
     @Override
@@ -3688,6 +3693,10 @@
         mPointerIconCache.setPointerScale(scale);
     }
 
+    void setAccessibilityPointerIconScaleFactor(int displayId, float scaleFactor) {
+        mPointerIconCache.setAccessibilityScaleFactor(displayId, scaleFactor);
+    }
+
     interface KeyboardBacklightControllerInterface {
         default void incrementKeyboardBacklight(int deviceId) {}
         default void decrementKeyboardBacklight(int deviceId) {}
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
index 297cd68..e16031c 100644
--- a/services/core/java/com/android/server/input/PointerIconCache.java
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseDoubleArray;
 import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
@@ -34,6 +35,7 @@
 import android.view.PointerIcon;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.UiThread;
 
 import java.util.Objects;
@@ -51,7 +53,7 @@
     private final NativeInputManagerService mNative;
 
     // We use the UI thread for loading pointer icons.
-    private final Handler mUiThreadHandler = UiThread.getHandler();
+    private final Handler mUiThreadHandler;
 
     @GuardedBy("mLoadedPointerIconsByDisplayAndType")
     private final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType =
@@ -70,6 +72,9 @@
             POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
     @GuardedBy("mLoadedPointerIconsByDisplayAndType")
     private float mPointerIconScale = DEFAULT_POINTER_SCALE;
+    // Note that android doesn't have SparseFloatArray, so this falls back to use double instead.
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseDoubleArray mAccessibilityScaleFactorPerDisplay = new SparseDoubleArray();
 
     private final DisplayManager.DisplayListener mDisplayListener =
             new DisplayManager.DisplayListener() {
@@ -86,6 +91,7 @@
                         mLoadedPointerIconsByDisplayAndType.remove(displayId);
                         mDisplayContexts.remove(displayId);
                         mDisplayDensities.delete(displayId);
+                        mAccessibilityScaleFactorPerDisplay.delete(displayId);
                     }
                 }
 
@@ -96,8 +102,15 @@
             };
 
     /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService) {
+        this(context, nativeService, UiThread.getHandler());
+    }
+
+    @VisibleForTesting
+    /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService,
+            Handler handler) {
         mContext = context;
         mNative = nativeService;
+        mUiThreadHandler = handler;
     }
 
     public void systemRunning() {
@@ -134,6 +147,11 @@
         mUiThreadHandler.post(() -> handleSetPointerScale(scale));
     }
 
+    /** Set the scale for accessibility (magnification) for vector pointer icons. */
+    public void setAccessibilityScaleFactor(int displayId, float scaleFactor) {
+        mUiThreadHandler.post(() -> handleAccessibilityScaleFactor(displayId, scaleFactor));
+    }
+
     /**
      * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if
      * it isn't already cached.
@@ -155,8 +173,10 @@
                         /* force= */ true);
                 theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(mPointerIconStrokeStyle),
                         /* force= */ true);
+                final float scale = mPointerIconScale
+                        * (float) mAccessibilityScaleFactorPerDisplay.get(displayId, 1f);
                 icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme),
-                        type, mUseLargePointerIcons, mPointerIconScale);
+                        type, mUseLargePointerIcons, scale);
                 iconsByType.put(type, icon);
             }
             return Objects.requireNonNull(icon);
@@ -261,6 +281,19 @@
         mNative.reloadPointerIcons();
     }
 
+    @android.annotation.UiThread
+    private void handleAccessibilityScaleFactor(int displayId, float scale) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            if (mAccessibilityScaleFactorPerDisplay.get(displayId, 1f) == scale) {
+                return;
+            }
+            mAccessibilityScaleFactorPerDisplay.put(displayId, scale);
+            // Clear cached icons on the display.
+            mLoadedPointerIconsByDisplayAndType.remove(displayId);
+        }
+        mNative.reloadPointerIcons();
+    }
+
     // Updates the cached display density for the given displayId, and returns true if
     // the cached density changed.
     @GuardedBy("mLoadedPointerIconsByDisplayAndType")
diff --git a/services/core/java/com/android/server/power/stats/AccumulatedBatteryUsageStatsSection.java b/services/core/java/com/android/server/power/stats/AccumulatedBatteryUsageStatsSection.java
index dd6d5db..c0a06fc 100644
--- a/services/core/java/com/android/server/power/stats/AccumulatedBatteryUsageStatsSection.java
+++ b/services/core/java/com/android/server/power/stats/AccumulatedBatteryUsageStatsSection.java
@@ -51,6 +51,11 @@
         mBatteryUsageStats.build().dump(ipw, "");
     }
 
+    @Override
+    public void close() {
+        mBatteryUsageStats.discard();
+    }
+
     static class Reader implements PowerStatsSpan.SectionReader {
         @Override
         public String getType() {
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index c04158f..48174a6 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -11509,9 +11509,6 @@
                     mOnBatteryTimeBase);
         }
 
-        mPerDisplayBatteryStats = new DisplayBatteryStats[1];
-        mPerDisplayBatteryStats[0] = new DisplayBatteryStats(mClock, mOnBatteryTimeBase);
-
         mInteractiveTimer = new StopwatchTimer(mClock, null, -10, null, mOnBatteryTimeBase);
         mPowerSaveModeEnabledTimer = new StopwatchTimer(mClock, null, -2, null,
                 mOnBatteryTimeBase);
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 265f1dfc..b996c43 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -295,7 +295,8 @@
                     stats.builder = ((AccumulatedBatteryUsageStatsSection) section)
                             .getBatteryUsageStatsBuilder();
                     stats.startWallClockTime = powerStatsSpan.getMetadata().getStartTime();
-                    stats.startMonotonicTime = powerStatsSpan.getMetadata().getStartMonotonicTime();
+                    stats.startMonotonicTime =
+                            powerStatsSpan.getMetadata().getStartMonotonicTime();
                     stats.endMonotonicTime = powerStatsSpan.getMetadata().getEndMonotonicTime();
                     break;
                 }
@@ -484,29 +485,30 @@
                 continue;
             }
 
-            PowerStatsSpan powerStatsSpan = mPowerStatsStore.loadPowerStatsSpan(
-                    spanMetadata.getId(), BatteryUsageStatsSection.TYPE);
-            if (powerStatsSpan == null) {
-                continue;
-            }
-
-            for (PowerStatsSpan.Section section : powerStatsSpan.getSections()) {
-                BatteryUsageStats snapshot =
-                        ((BatteryUsageStatsSection) section).getBatteryUsageStats();
-                if (!Arrays.equals(snapshot.getCustomPowerComponentNames(),
-                        customEnergyConsumerNames)) {
-                    Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different "
-                            + "custom power components: "
-                            + Arrays.toString(snapshot.getCustomPowerComponentNames()));
+            try (PowerStatsSpan powerStatsSpan = mPowerStatsStore.loadPowerStatsSpan(
+                    spanMetadata.getId(), BatteryUsageStatsSection.TYPE)) {
+                if (powerStatsSpan == null) {
                     continue;
                 }
 
-                if (includeProcessStateData && !snapshot.isProcessStateDataIncluded()) {
-                    Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which "
-                            + " does not include process state data");
-                    continue;
+                for (PowerStatsSpan.Section section : powerStatsSpan.getSections()) {
+                    BatteryUsageStats snapshot =
+                            ((BatteryUsageStatsSection) section).getBatteryUsageStats();
+                    if (!Arrays.equals(snapshot.getCustomPowerComponentNames(),
+                            customEnergyConsumerNames)) {
+                        Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which has different "
+                                + "custom power components: "
+                                + Arrays.toString(snapshot.getCustomPowerComponentNames()));
+                        continue;
+                    }
+
+                    if (includeProcessStateData && !snapshot.isProcessStateDataIncluded()) {
+                        Log.w(TAG, "Ignoring older BatteryUsageStats snapshot, which "
+                                + " does not include process state data");
+                        continue;
+                    }
+                    builder.add(snapshot);
                 }
-                builder.add(snapshot);
             }
         }
         return builder.build();
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsSection.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsSection.java
index af36524..eb896e9 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsSection.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsSection.java
@@ -18,6 +18,7 @@
 
 import android.os.BatteryUsageStats;
 import android.util.IndentingPrintWriter;
+import android.util.Slog;
 
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -28,6 +29,7 @@
 
 class BatteryUsageStatsSection extends PowerStatsSpan.Section {
     public static final String TYPE = "battery-usage-stats";
+    private static final String TAG = "BatteryUsageStatsSection";
 
     private final BatteryUsageStats mBatteryUsageStats;
 
@@ -50,6 +52,15 @@
         mBatteryUsageStats.dump(ipw, "");
     }
 
+    @Override
+    public void close() {
+        try {
+            mBatteryUsageStats.close();
+        } catch (IOException e) {
+            Slog.e(TAG, "Closing BatteryUsageStats", e);
+        }
+    }
+
     static class Reader implements PowerStatsSpan.SectionReader {
         @Override
         public String getType() {
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
index 5105272..4f560cf 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
@@ -51,7 +51,7 @@
 /**
  * Contains power stats of various kinds, aggregated over a time span.
  */
-public class PowerStatsSpan {
+public class PowerStatsSpan implements AutoCloseable {
     private static final String TAG = "PowerStatsStore";
 
     /**
@@ -321,6 +321,13 @@
         public void dump(IndentingPrintWriter ipw) {
             ipw.println(mType);
         }
+
+        /**
+         * Closes the section, releasing any resources it held. Once closed, the Section
+         * should not be used.
+         */
+        public void close() {
+        }
     }
 
     /**
@@ -484,4 +491,10 @@
             ipw.decreaseIndent();
         }
     }
+    @Override
+    public void close() {
+        for (int i = 0; i < mSections.size(); i++) {
+            mSections.get(i).close();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsStore.java b/services/core/java/com/android/server/power/stats/PowerStatsStore.java
index 3673617..d83d355 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsStore.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsStore.java
@@ -331,9 +331,10 @@
         ipw.increaseIndent();
         List<PowerStatsSpan.Metadata> contents = getTableOfContents();
         for (PowerStatsSpan.Metadata metadata : contents) {
-            PowerStatsSpan span = loadPowerStatsSpan(metadata.getId());
-            if (span != null) {
-                span.dump(ipw);
+            try (PowerStatsSpan span = loadPowerStatsSpan(metadata.getId())) {
+                if (span != null) {
+                    span.dump(ipw);
+                }
             }
         }
         ipw.decreaseIndent();
diff --git a/services/core/java/com/android/server/power/stats/processor/AmbientDisplayPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/AmbientDisplayPowerStatsProcessor.java
index 32dfdf9..5f93bdf 100644
--- a/services/core/java/com/android/server/power/stats/processor/AmbientDisplayPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/AmbientDisplayPowerStatsProcessor.java
@@ -50,12 +50,14 @@
             return;
         }
 
-        if (mScreenPowerStatsDescriptor == null) {
-            mScreenPowerStatsDescriptor = screenStats.getPowerStatsDescriptor();
-            if (mScreenPowerStatsDescriptor == null) {
-                return;
-            }
+        PowerStats.Descriptor screenDescriptor = screenStats.getPowerStatsDescriptor();
+        if (screenDescriptor == null) {
+            return;
+        }
 
+        if (mScreenPowerStatsDescriptor == null
+                || !mScreenPowerStatsDescriptor.equals(screenDescriptor)) {
+            mScreenPowerStatsDescriptor = screenDescriptor;
             mScreenPowerStatsLayout = new ScreenPowerStatsLayout(mScreenPowerStatsDescriptor);
             mTmpScreenStats = new long[mScreenPowerStatsDescriptor.statsArrayLength];
         }
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
index c8170a1..b2442c8 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java
@@ -105,19 +105,19 @@
                     maxEndTime = spanMaxTime;
                 }
 
-                PowerStatsSpan span = mPowerStatsStore.loadPowerStatsSpan(metadata.getId(),
-                        AggregatedPowerStatsSection.TYPE);
-                if (span == null) {
-                    Slog.e(TAG, "Could not read PowerStatsStore section " + metadata);
-                    continue;
-                }
-                List<PowerStatsSpan.Section> sections = span.getSections();
-                for (int k = 0; k < sections.size(); k++) {
-                    hasStoredSpans = true;
-                    PowerStatsSpan.Section section = sections.get(k);
-                    populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder,
-                            ((AggregatedPowerStatsSection) section).getAggregatedPowerStats());
-                    // TODO(b/371614748): close the builder
+                try (PowerStatsSpan span = mPowerStatsStore.loadPowerStatsSpan(metadata.getId(),
+                        AggregatedPowerStatsSection.TYPE)) {
+                    if (span == null) {
+                        Slog.e(TAG, "Could not read PowerStatsStore section " + metadata);
+                        continue;
+                    }
+                    List<PowerStatsSpan.Section> sections = span.getSections();
+                    for (int k = 0; k < sections.size(); k++) {
+                        hasStoredSpans = true;
+                        PowerStatsSpan.Section section = sections.get(k);
+                        populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder,
+                                ((AggregatedPowerStatsSection) section).getAggregatedPowerStats());
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
index b295e30..8e7498f 100644
--- a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
@@ -89,14 +89,15 @@
             return true;
         }
 
-        mLastUsedDescriptor = descriptor;
-        mStatsLayout = new ScreenPowerStatsLayout(descriptor);
-        if (mStatsLayout.getDisplayCount() != mDisplayCount) {
-            Slog.e(TAG, "Incompatible number of displays: " + mStatsLayout.getDisplayCount()
+        ScreenPowerStatsLayout statsLayout = new ScreenPowerStatsLayout(descriptor);
+        if (statsLayout.getDisplayCount() != mDisplayCount) {
+            Slog.e(TAG, "Incompatible number of displays: " + statsLayout.getDisplayCount()
                     + ", expected: " + mDisplayCount);
             return false;
         }
 
+        mLastUsedDescriptor = descriptor;
+        mStatsLayout = statsLayout;
         mTmpDeviceStatsArray = new long[descriptor.statsArrayLength];
         mTmpUidStatsArray = new long[descriptor.uidStatsArrayLength];
         return true;
diff --git a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java b/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java
new file mode 100644
index 0000000..caca011
--- /dev/null
+++ b/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2024 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.security.forensic;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.security.forensic.ForensicEvent;
+import android.security.forensic.IBackupTransport;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class BackupTransportConnection implements ServiceConnection {
+    private static final String TAG = "BackupTransportConnection";
+    private static final long FUTURE_TIMEOUT_MILLIS = 60 * 1000; // 1 mins
+    private final Context mContext;
+    private String mForensicBackupTransportConfig;
+    volatile IBackupTransport mService;
+
+    public BackupTransportConnection(Context context) {
+        mContext = context;
+        mService = null;
+    }
+
+    /**
+     * Initialize the BackupTransport binder service.
+     * @return Whether the initialization succeed.
+     */
+    public boolean initialize() {
+        if (!bindService()) {
+            return false;
+        }
+        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        try {
+            mService.initialize(resultFuture);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception", e);
+            unbindService();
+            return false;
+        }
+        Integer result = getFutureResult(resultFuture);
+        if (result != null && result == 0) {
+            return true;
+        } else {
+            unbindService();
+            return false;
+        }
+    }
+
+    /**
+     * Add data to the BackupTransport binder service.
+     * @param data List of ForensicEvent.
+     * @return Whether the data is added to the binder service.
+     */
+    public boolean addData(List<ForensicEvent> data) {
+        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        try {
+            mService.addData(data, resultFuture);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception", e);
+            return false;
+        }
+        Integer result = getFutureResult(resultFuture);
+        return result != null && result == 0;
+    }
+
+    /**
+     * Release the BackupTransport binder service.
+     */
+    public void release() {
+        AndroidFuture<Integer> resultFuture = new AndroidFuture<>();
+        try {
+            mService.release(resultFuture);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception", e);
+        } finally {
+            unbindService();
+        }
+    }
+
+    private <T> T getFutureResult(AndroidFuture<T> future) {
+        try {
+            return future.get(FUTURE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException
+                 | CancellationException e) {
+            Slog.w(TAG, "Failed to get result from transport:", e);
+            return null;
+        }
+    }
+
+    private boolean bindService() {
+        mForensicBackupTransportConfig = mContext.getString(
+                com.android.internal.R.string.config_forensicBackupTransport);
+        if (TextUtils.isEmpty(mForensicBackupTransportConfig)) {
+            return false;
+        }
+
+        ComponentName serviceComponent =
+                ComponentName.unflattenFromString(mForensicBackupTransportConfig);
+        if (serviceComponent == null) {
+            return false;
+        }
+
+        Intent intent = new Intent().setComponent(serviceComponent);
+        boolean result = mContext.bindServiceAsUser(
+                intent, this, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+        if (!result) {
+            unbindService();
+        }
+        return result;
+    }
+
+    private void unbindService() {
+        mContext.unbindService(this);
+        mService = null;
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        mService = IBackupTransport.Stub.asInterface(service);
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        mService = null;
+    }
+}
diff --git a/services/core/java/com/android/server/security/forensic/ForensicService.java b/services/core/java/com/android/server/security/forensic/ForensicService.java
index 07639d1..20c648e 100644
--- a/services/core/java/com/android/server/security/forensic/ForensicService.java
+++ b/services/core/java/com/android/server/security/forensic/ForensicService.java
@@ -63,6 +63,7 @@
 
     private final Context mContext;
     private final Handler mHandler;
+    private final BackupTransportConnection mBackupTransportConnection;
     private final BinderService mBinderService;
 
     private final ArrayList<IForensicServiceStateCallback> mStateMonitors = new ArrayList<>();
@@ -77,6 +78,7 @@
         super(injector.getContext());
         mContext = injector.getContext();
         mHandler = new EventHandler(injector.getLooper(), this);
+        mBackupTransportConnection = injector.getBackupTransportConnection();
         mBinderService = new BinderService(this);
     }
 
@@ -221,6 +223,10 @@
     private void enable(IForensicServiceCommandCallback callback) throws RemoteException {
         switch (mState) {
             case STATE_VISIBLE:
+                if (!mBackupTransportConnection.initialize()) {
+                    callback.onFailure(ERROR_BACKUP_TRANSPORT_UNAVAILABLE);
+                    break;
+                }
                 mState = STATE_ENABLED;
                 notifyStateMonitors();
                 callback.onSuccess();
@@ -236,6 +242,7 @@
     private void disable(IForensicServiceCommandCallback callback) throws RemoteException {
         switch (mState) {
             case STATE_ENABLED:
+                mBackupTransportConnection.release();
                 mState = STATE_VISIBLE;
                 notifyStateMonitors();
                 callback.onSuccess();
@@ -266,6 +273,8 @@
         Context getContext();
 
         Looper getLooper();
+
+        BackupTransportConnection getBackupTransportConnection();
     }
 
     private static final class InjectorImpl implements Injector {
@@ -289,6 +298,11 @@
             serviceThread.start();
             return serviceThread.getLooper();
         }
+
+        @Override
+        public BackupTransportConnection getBackupTransportConnection() {
+            return new BackupTransportConnection(mContext);
+        }
     }
 }
 
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index e7735d8..54e4f8e 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -48,6 +48,9 @@
 import static android.util.MathUtils.constrain;
 import static android.view.Display.HdrCapabilities.HDR_TYPE_INVALID;
 
+import static com.android.internal.os.ProcfsMemoryUtil.getProcessCmdlines;
+import static com.android.internal.os.ProcfsMemoryUtil.readCmdlineFromProcfs;
+import static com.android.internal.os.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS__GESTURE_SHORTCUT_TYPE__TRIPLE_TAP;
 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS__HARDWARE_SHORTCUT_TYPE__VOLUME_KEY;
@@ -68,9 +71,6 @@
 import static com.android.server.stats.Flags.applyNetworkStatsPollRateLimit;
 import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
-import static com.android.server.stats.pull.ProcfsMemoryUtil.getProcessCmdlines;
-import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs;
-import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 import static com.android.server.stats.pull.netstats.NetworkStatsUtils.fromPublicNetworkStats;
 import static com.android.server.stats.pull.netstats.NetworkStatsUtils.isAddEntriesSupported;
 
@@ -209,6 +209,8 @@
 import com.android.internal.os.LooperStats;
 import com.android.internal.os.PowerProfile;
 import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.ProcfsMemoryUtil;
+import com.android.internal.os.ProcfsMemoryUtil.MemorySnapshot;
 import com.android.internal.os.SelectedProcessCpuThreadReader;
 import com.android.internal.os.StoragedUidIoStatsReader;
 import com.android.internal.util.CollectionUtils;
@@ -229,7 +231,6 @@
 import com.android.server.power.stats.KernelWakelockStats;
 import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
 import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
-import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
 import com.android.server.stats.pull.netstats.NetworkStatsAccumulator;
 import com.android.server.stats.pull.netstats.NetworkStatsExt;
 import com.android.server.stats.pull.netstats.SubInfo;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 4f71719..567eca2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2572,14 +2572,21 @@
         wpc.computeProcessActivityState();
     }
 
-    void computeProcessActivityStateBatch() {
+    boolean computeProcessActivityStateBatch() {
         if (mActivityStateChangedProcs.isEmpty()) {
-            return;
+            return false;
         }
+        boolean changed = false;
         for (int i = mActivityStateChangedProcs.size() - 1; i >= 0; i--) {
-            mActivityStateChangedProcs.get(i).computeProcessActivityState();
+            final WindowProcessController wpc = mActivityStateChangedProcs.get(i);
+            final int prevState = wpc.getActivityStateFlags();
+            wpc.computeProcessActivityState();
+            if (!changed && prevState != wpc.getActivityStateFlags()) {
+                changed = true;
+            }
         }
         mActivityStateChangedProcs.clear();
+        return changed;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index ccd5996..6cc4b1e 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -994,7 +994,9 @@
         // Ensure the final animation targets which hidden by transition could be visible.
         for (int i = 0; i < targets.size(); i++) {
             final WindowContainer wc = targets.get(i).mContainer;
-            wc.prepareSurfaces();
+            if (wc.mSurfaceControl != null) {
+                wc.prepareSurfaces();
+            }
         }
 
         // The pending builder could be cleared due to prepareSurfaces
@@ -1328,16 +1330,13 @@
             if (!allWindowDrawn) {
                 return;
             }
-            final SurfaceControl startingSurface = mOpenAnimAdaptor.mStartingSurface;
-            if (startingSurface != null && startingSurface.isValid()) {
-                startTransaction.addTransactionCommittedListener(Runnable::run, () -> {
-                    synchronized (mWindowManagerService.mGlobalLock) {
-                        if (mOpenAnimAdaptor != null) {
-                            mOpenAnimAdaptor.cleanUpWindowlessSurface(true);
-                        }
+            startTransaction.addTransactionCommittedListener(Runnable::run, () -> {
+                synchronized (mWindowManagerService.mGlobalLock) {
+                    if (mOpenAnimAdaptor != null) {
+                        mOpenAnimAdaptor.cleanUpWindowlessSurface(true);
                     }
-                });
-            }
+                }
+            });
         }
 
         void clearBackAnimateTarget(boolean cancel) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 41a5804..6707a27 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -105,6 +105,7 @@
 import android.content.pm.UserProperties;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.power.Mode;
@@ -153,6 +154,7 @@
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.utils.Slogf;
+import com.android.server.wm.utils.RegionUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -270,6 +272,8 @@
     private boolean mTaskLayersChanged = true;
     private int mTmpTaskLayerRank;
     private final RankTaskLayersRunnable mRankTaskLayersRunnable = new RankTaskLayersRunnable();
+    private Region mTmpOccludingRegion;
+    private Region mTmpTaskRegion;
 
     private String mDestroyAllActivitiesReason;
     private final Runnable mDestroyAllActivitiesRunnable = new Runnable() {
@@ -2921,6 +2925,11 @@
         });
     }
 
+    void invalidateTaskLayersAndUpdateOomAdjIfNeeded() {
+        mRankTaskLayersRunnable.mCheckUpdateOomAdj = true;
+        invalidateTaskLayers();
+    }
+
     void invalidateTaskLayers() {
         if (!mTaskLayersChanged) {
             mTaskLayersChanged = true;
@@ -2938,13 +2947,18 @@
         // Only rank for leaf tasks because the score of activity is based on immediate parent.
         forAllLeafTasks(task -> {
             final int oldRank = task.mLayerRank;
-            final ActivityRecord r = task.topRunningActivityLocked();
-            if (r != null && r.isVisibleRequested()) {
+            final int oldRatio = task.mNonOccludedFreeformAreaRatio;
+            task.mNonOccludedFreeformAreaRatio = 0;
+            if (task.isVisibleRequested()) {
                 task.mLayerRank = ++mTmpTaskLayerRank;
+                if (task.inFreeformWindowingMode()) {
+                    computeNonOccludedFreeformAreaRatio(task);
+                }
             } else {
                 task.mLayerRank = Task.LAYER_RANK_INVISIBLE;
             }
-            if (task.mLayerRank != oldRank) {
+            if (task.mLayerRank != oldRank
+                    || task.mNonOccludedFreeformAreaRatio != oldRatio) {
                 task.forAllActivities(activity -> {
                     if (activity.hasProcess()) {
                         mTaskSupervisor.onProcessActivityStateChanged(activity.app,
@@ -2953,10 +2967,40 @@
                 });
             }
         }, true /* traverseTopToBottom */);
-
-        if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
-            mTaskSupervisor.computeProcessActivityStateBatch();
+        if (mTmpOccludingRegion != null) {
+            mTmpOccludingRegion.setEmpty();
         }
+        boolean changed = false;
+        if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
+            changed = mTaskSupervisor.computeProcessActivityStateBatch();
+        }
+        if (mRankTaskLayersRunnable.mCheckUpdateOomAdj) {
+            mRankTaskLayersRunnable.mCheckUpdateOomAdj = false;
+            if (changed) {
+                mService.updateOomAdj();
+            }
+        }
+    }
+
+    /** This method is called for visible freeform task from top to bottom. */
+    private void computeNonOccludedFreeformAreaRatio(@NonNull Task task) {
+        if (!com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()) {
+            return;
+        }
+        if (mTmpOccludingRegion == null) {
+            mTmpOccludingRegion = new Region();
+            mTmpTaskRegion = new Region();
+        }
+        final Rect taskBounds = task.getBounds();
+        mTmpTaskRegion.set(taskBounds);
+        // Exclude the area outside the display.
+        mTmpTaskRegion.op(task.mDisplayContent.getBounds(), Region.Op.INTERSECT);
+        // Exclude the area covered by the above tasks.
+        mTmpTaskRegion.op(mTmpOccludingRegion, Region.Op.DIFFERENCE);
+        task.mNonOccludedFreeformAreaRatio = 100 * RegionUtils.getAreaSize(mTmpTaskRegion)
+                        / (taskBounds.width() * taskBounds.height());
+        // Accumulate the occluding region for other visible tasks behind.
+        mTmpOccludingRegion.op(taskBounds, Region.Op.UNION);
     }
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
@@ -3862,6 +3906,8 @@
     }
 
     private class RankTaskLayersRunnable implements Runnable {
+        boolean mCheckUpdateOomAdj;
+
         @Override
         public void run() {
             synchronized (mService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4861341..8a624b3 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -432,6 +432,9 @@
     // This number will be assigned when we evaluate OOM scores for all visible tasks.
     int mLayerRank = LAYER_RANK_INVISIBLE;
 
+    /** A 0~100 ratio to indicate the percentage of visible area on screen of a freeform task. */
+    int mNonOccludedFreeformAreaRatio;
+
     /* Unique identifier for this task. */
     final int mTaskId;
     /* User for which this task was created. */
@@ -1207,6 +1210,28 @@
     }
 
     @Override
+    void onResize() {
+        super.onResize();
+        updateTaskLayerForFreeform();
+    }
+
+    @Override
+    void onMovedByResize() {
+        super.onMovedByResize();
+        updateTaskLayerForFreeform();
+    }
+
+    private void updateTaskLayerForFreeform() {
+        if (!com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()) {
+            return;
+        }
+        if (!isVisibleRequested() || !inFreeformWindowingMode()) {
+            return;
+        }
+        mRootWindowContainer.invalidateTaskLayersAndUpdateOomAdjIfNeeded();
+    }
+
+    @Override
     @Nullable
     ActivityRecord getTopResumedActivity() {
         if (!isLeafTask()) {
@@ -3410,6 +3435,36 @@
         info.requestedVisibleTypes = (windowState != null && Flags.enableFullyImmersiveInDesktop())
                 ? windowState.getRequestedVisibleTypes() : WindowInsets.Type.defaultVisible();
         AppCompatUtils.fillAppCompatTaskInfo(this, info, top);
+        info.topActivityMainWindowFrame = calculateTopActivityMainWindowFrameForTaskInfo(top);
+    }
+
+    /**
+     * Returns the top activity's main window frame if it doesn't match
+     * {@link ActivityRecord#getBounds() the top activity bounds}, or {@code null}, otherwise.
+     *
+     * @param top The top running activity of the task
+     */
+    @Nullable
+    private static Rect calculateTopActivityMainWindowFrameForTaskInfo(
+            @Nullable ActivityRecord top) {
+        if (!Flags.betterSupportNonMatchParentActivity()) {
+            return null;
+        }
+        if (top == null) {
+            return null;
+        }
+        final WindowState mainWindow = top.findMainWindow();
+        if (mainWindow == null) {
+            return null;
+        }
+        if (!mainWindow.mHaveFrame) {
+            return null;
+        }
+        final Rect windowFrame = mainWindow.getFrame();
+        if (top.getBounds().equals(windowFrame)) {
+            return null;
+        }
+        return windowFrame;
     }
 
     /**
@@ -5919,6 +5974,10 @@
             pw.print(prefix); pw.print("  mLastNonFullscreenBounds=");
             pw.println(mLastNonFullscreenBounds);
         }
+        if (mNonOccludedFreeformAreaRatio != 0) {
+            pw.print(prefix); pw.print("  mNonOccludedFreeformAreaRatio=");
+            pw.println(mNonOccludedFreeformAreaRatio);
+        }
         if (isLeafTask()) {
             pw.println(prefix + "  isSleeping=" + shouldSleepActivities());
             printThisActivity(pw, getTopPausingActivity(), dumpPackage, false,
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3ffeacf..d6ba312 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -3027,7 +3027,11 @@
         // The task order may be changed by finishIfPossible() for adjusting focus if there are
         // nested tasks, so add all activities into a list to avoid missed removals.
         final ArrayList<ActivityRecord> removingActivities = new ArrayList<>();
-        forAllActivities((Consumer<ActivityRecord>) removingActivities::add);
+        forAllActivities((r) -> {
+            if (!r.finishing) {
+                removingActivities.add(r);
+            }
+        });
         for (int i = removingActivities.size() - 1; i >= 0; --i) {
             final ActivityRecord r = removingActivities.get(i);
             if (withTransition && r.isVisible()) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1a107c2..7f0c336 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -121,6 +121,11 @@
      */
     private static final int MAX_NUM_PERCEPTIBLE_FREEFORM =
             SystemProperties.getInt("persist.wm.max_num_perceptible_freeform", 1);
+    /**
+     * If the visible area percentage of a resumed freeform task is greater than or equal to this
+     * ratio, its process will have a higher priority.
+     */
+    private static final int PERCEPTIBLE_FREEFORM_VISIBLE_RATIO = 90;
 
     private static final int MAX_RAPID_ACTIVITY_LAUNCH_COUNT = 200;
     private static final long RAPID_ACTIVITY_LAUNCH_MS = 500;
@@ -1234,6 +1239,7 @@
         boolean hasResumedFreeform = false;
         int minTaskLayer = Integer.MAX_VALUE;
         int stateFlags = 0;
+        int nonOccludedRatio = 0;
         final boolean wasResumed = hasResumedActivity();
         final boolean wasAnyVisible = (mActivityStateFlags
                 & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
@@ -1261,6 +1267,8 @@
                         stateFlags |= ACTIVITY_STATE_FLAG_RESUMED_SPLIT_SCREEN;
                     } else if (windowingMode == WINDOWING_MODE_FREEFORM) {
                         hasResumedFreeform = true;
+                        nonOccludedRatio =
+                                Math.max(task.mNonOccludedFreeformAreaRatio, nonOccludedRatio);
                     }
                 }
                 if (minTaskLayer > 0) {
@@ -1298,7 +1306,8 @@
                 && com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()
                 // Exclude task layer 1 because it is already the top most.
                 && minTaskLayer > 1) {
-            if (minTaskLayer <= 1 + MAX_NUM_PERCEPTIBLE_FREEFORM) {
+            if (minTaskLayer <= 1 + MAX_NUM_PERCEPTIBLE_FREEFORM
+                    || nonOccludedRatio >= PERCEPTIBLE_FREEFORM_VISIBLE_RATIO) {
                 stateFlags |= ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM;
             } else {
                 stateFlags |= ACTIVITY_STATE_FLAG_VISIBLE_MULTI_WINDOW_MODE;
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
index ce7776f..ff23145 100644
--- a/services/core/java/com/android/server/wm/utils/RegionUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -81,4 +81,15 @@
         Collections.reverse(rects);
         rects.forEach(rectConsumer);
     }
+
+    /** Returns the area size of the region. */
+    public static int getAreaSize(Region region) {
+        final RegionIterator regionIterator = new RegionIterator(region);
+        int area = 0;
+        final Rect rect = new Rect();
+        while (regionIterator.next(rect)) {
+            area += rect.width() * rect.height();
+        }
+        return area;
+    }
 }
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index f15e533..2f00a1b 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -32,6 +32,7 @@
         "androidx.test.runner",
         "truth",
         "Harrier",
+        "bedstead-multiuser",
     ],
     platform_apis: true,
     certificate: "platform",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
index 70a2d48..48cebd7 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/CrossUserPackageVisibilityTests.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.MOVE_PACKAGE;
 import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
 
+import static com.android.bedstead.multiuser.MultiUserDeviceStateExtensionsKt.secondaryUser;
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -112,9 +113,9 @@
         final UserReference primaryUser = sDeviceState.primaryUser();
         if (primaryUser.id() == UserHandle.myUserId()) {
             mCurrentUser = primaryUser;
-            mOtherUser = sDeviceState.secondaryUser();
+            mOtherUser = secondaryUser(sDeviceState);
         } else {
-            mCurrentUser = sDeviceState.secondaryUser();
+            mCurrentUser = secondaryUser(sDeviceState);
             mOtherUser = primaryUser;
         }
 
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index 177f30a..0a1fc31 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -987,5 +987,7 @@
                         BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                 .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                 .isEqualTo(60000);
+
+        span.close();
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
index 9a64ce1..94997b2 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
@@ -41,7 +41,7 @@
     public final RavenwoodRule mRavenwood = new RavenwoodRule();
 
     @Test
-    public void testBatteryUsageStatsDataConsistency() {
+    public void testBatteryUsageStatsDataConsistency() throws Exception {
         BatteryStatsManager bsm = getContext().getSystemService(BatteryStatsManager.class);
         BatteryUsageStats stats = bsm.getBatteryUsageStats(
                 new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(
@@ -70,5 +70,7 @@
                 }
             }
         }
+
+        stats.close();
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
index 7d2bc17..813dd84 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsAtomTest.java
@@ -64,7 +64,7 @@
     private static final int UID_3 = 4000;
 
     @Test
-    public void testAtom_BatteryUsageStatsPerUid() {
+    public void testAtom_BatteryUsageStatsPerUid() throws Exception {
         final BatteryUsageStats bus = buildBatteryUsageStats();
         BatteryStatsService.FrameworkStatsLogger statsLogger =
                 mock(BatteryStatsService.FrameworkStatsLogger.class);
@@ -72,6 +72,8 @@
         List<StatsEvent> actual = new ArrayList<>();
         new BatteryStatsService.StatsPerUidLogger(statsLogger).logStats(bus, actual);
 
+        bus.close();
+
         if (DEBUG) {
             System.out.println(mockingDetails(statsLogger).printInvocations());
         }
@@ -284,7 +286,7 @@
     }
 
     @Test
-    public void testAtom_BatteryUsageStatsAtomsProto() {
+    public void testAtom_BatteryUsageStatsAtomsProto() throws Exception {
         final BatteryUsageStats bus = buildBatteryUsageStats();
         final byte[] bytes = bus.getStatsProto();
         BatteryUsageStatsAtomsProto proto;
@@ -347,6 +349,7 @@
 
         // UID_3 - Should be none, since no interesting data (done last for debugging convenience).
         assertEquals(3, proto.uidBatteryConsumers.length);
+        bus.close();
     }
 
     private void assertSameBatteryConsumer(String message, BatteryConsumer consumer,
@@ -582,7 +585,7 @@
     }
 
     @Test
-    public void testLargeAtomTruncated() {
+    public void testLargeAtomTruncated() throws Exception {
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[0], true, false, false, false, 0);
         // If not truncated, this BatteryUsageStats object would generate a proto buffer
@@ -618,6 +621,8 @@
         assertThat(bytes.length).isGreaterThan(20000);
         assertThat(bytes.length).isLessThan(50000);
 
+        batteryUsageStats.close();
+
         BatteryUsageStatsAtomsProto proto;
         try {
             proto = BatteryUsageStatsAtomsProto.parseFrom(bytes);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index e9d95fc..87a26d0 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -94,7 +94,7 @@
     }
 
     @Test
-    public void test_getBatteryUsageStats() {
+    public void test_getBatteryUsageStats() throws IOException {
         final BatteryUsageStats batteryUsageStats = prepareBatteryUsageStats(false);
 
         final List<UidBatteryConsumer> uidBatteryConsumers =
@@ -121,24 +121,27 @@
 
         assertThat(batteryUsageStats.getStatsStartTimestamp()).isEqualTo(12345);
         assertThat(batteryUsageStats.getStatsEndTimestamp()).isEqualTo(180 * MINUTE_IN_MS);
+        batteryUsageStats.close();
     }
 
     @Test
-    public void batteryLevelInfo_charging() {
+    public void batteryLevelInfo_charging() throws IOException {
         final BatteryUsageStats batteryUsageStats = prepareBatteryUsageStats(true);
         assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000.0);
         assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(1_200_000);
+        batteryUsageStats.close();
     }
 
     @Test
-    public void batteryLevelInfo_onBattery() {
+    public void batteryLevelInfo_onBattery() throws IOException {
         final BatteryUsageStats batteryUsageStats = prepareBatteryUsageStats(false);
         assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000.0);
         assertThat(batteryUsageStats.getBatteryTimeRemainingMs()).isEqualTo(600_000);
+        batteryUsageStats.close();
     }
 
     @Test
-    public void test_selectPowerComponents() {
+    public void test_selectPowerComponents() throws IOException {
         BatteryStatsImpl batteryStats = prepareBatteryStats(false);
 
         BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext,
@@ -163,6 +166,8 @@
         assertThat(
                 uidBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                 .isEqualTo(0);
+
+        batteryUsageStats.close();
     }
 
     private BatteryStatsImpl prepareBatteryStats(boolean plugInAtTheEnd) {
@@ -274,7 +279,7 @@
     }
 
     @Test
-    public void testWriteAndReadHistory() {
+    public void testWriteAndReadHistory() throws IOException {
         MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
         synchronized (batteryStats) {
             batteryStats.setRecordAllHistoryLocked(true);
@@ -306,6 +311,8 @@
 
         Parcel in = Parcel.obtain();
         batteryUsageStats.writeToParcel(in, 0);
+        batteryUsageStats.close();
+
         final byte[] bytes = in.marshall();
 
         Parcel out = Parcel.obtain();
@@ -349,10 +356,12 @@
 
         assertThat(iterator.hasNext()).isFalse();
         assertThat(iterator.next()).isNull();
+
+        unparceled.close();
     }
 
     @Test
-    public void testWriteAndReadHistoryTags() {
+    public void testWriteAndReadHistoryTags() throws IOException {
         MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
         synchronized (batteryStats) {
             batteryStats.setRecordAllHistoryLocked(true);
@@ -400,6 +409,8 @@
             assertThat(parcel.dataSize()).isAtMost(128_000);
         }
 
+        batteryUsageStats.close();
+
         parcel.setDataPosition(0);
 
         BatteryUsageStats unparceled = parcel.readParcelable(getClass().getClassLoader(),
@@ -461,7 +472,7 @@
     }
 
     @Test
-    public void testAggregateBatteryStats() {
+    public void testAggregateBatteryStats() throws IOException {
         BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
 
         setTime(5 * MINUTE_IN_MS);
@@ -563,6 +574,8 @@
                 .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT))
                 .isWithin(0.1)
                 .of(180.0);
+
+        stats.close();
     }
 
     @Test
@@ -689,6 +702,8 @@
                 .isEqualTo(60 * MINUTE_IN_MS);
 
         assertThat(count[0]).isEqualTo(expectedNumberOfUpdates);
+
+        stats.close();
     }
 
     private void setTime(long timeMs) {
@@ -733,6 +748,7 @@
                     .isWithin(PRECISION).of(8.33333);
             assertThat(uid.getConsumedPower(componentId1))
                     .isWithin(PRECISION).of(8.33333);
+            stats.close();
             return null;
         }).when(powerStatsStore).storeBatteryUsageStatsAsync(anyLong(), any());
 
@@ -750,7 +766,7 @@
     }
 
     @Test
-    public void testAggregateBatteryStats_incompatibleSnapshot() {
+    public void testAggregateBatteryStats_incompatibleSnapshot() throws IOException {
         MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
         batteryStats.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
 
@@ -776,6 +792,8 @@
         when(powerStatsStore.loadPowerStatsSpan(1, BatteryUsageStatsSection.TYPE))
                 .thenReturn(span1);
 
+        span1.close();
+
         BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext,
                 mock(PowerAttributor.class), mStatsRule.getPowerProfile(),
                 mStatsRule.getCpuScalingPolicies(), powerStatsStore, 0, mMockClock);
@@ -787,5 +805,7 @@
         assertThat(stats.getCustomPowerComponentNames())
                 .isEqualTo(batteryStats.getCustomEnergyConsumerNames());
         assertThat(stats.getStatsDuration()).isEqualTo(1234);
+
+        stats.close();
     }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 52675f6..383616e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -323,6 +323,7 @@
     }
 
     private void before() {
+        BatteryUsageStats.DEBUG_INSTANCE_COUNT = true;
         HandlerThread bgThread = new HandlerThread("bg thread");
         bgThread.setUncaughtExceptionHandler((thread, throwable)-> {
             mThrowable = throwable;
@@ -338,6 +339,10 @@
 
     private void after() throws Throwable {
         waitForBackgroundThread();
+        if (mBatteryUsageStats != null) {
+            mBatteryUsageStats.close();
+        }
+        BatteryUsageStats.assertAllInstancesClosed();
     }
 
     public void waitForBackgroundThread() throws Throwable {
@@ -409,6 +414,14 @@
     }
 
     BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) {
+        if (mBatteryUsageStats != null) {
+            try {
+                mBatteryUsageStats.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            mBatteryUsageStats = null;
+        }
         final String[] customPowerComponentNames = mBatteryStats.getCustomEnergyConsumerNames();
         final boolean includePowerModels = (query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 88624f2..1b6b8c4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
@@ -76,22 +76,25 @@
     private static final int APP_UID2 = 314;
 
     @Test
-    public void testBuilder() {
+    public void testBuilder() throws Exception {
         BatteryUsageStats batteryUsageStats = buildBatteryUsageStats1(true).build();
         assertBatteryUsageStats1(batteryUsageStats, true);
+        batteryUsageStats.close();
     }
 
     @Test
-    public void testBuilder_noProcessStateData() {
+    public void testBuilder_noProcessStateData() throws Exception {
         BatteryUsageStats batteryUsageStats = buildBatteryUsageStats1(false).build();
         assertBatteryUsageStats1(batteryUsageStats, false);
+        batteryUsageStats.close();
     }
 
     @Test
-    public void testParcelability_smallNumberOfUids() {
+    public void testParcelability_smallNumberOfUids() throws Exception {
         final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats1(true).build();
         final Parcel parcel = Parcel.obtain();
         parcel.writeParcelable(outBatteryUsageStats, 0);
+        outBatteryUsageStats.close();
 
         assertThat(parcel.dataSize()).isLessThan(100000);
 
@@ -101,10 +104,11 @@
                 parcel.readParcelable(getClass().getClassLoader());
         assertThat(inBatteryUsageStats).isNotNull();
         assertBatteryUsageStats1(inBatteryUsageStats, true);
+        inBatteryUsageStats.close();
     }
 
     @Test
-    public void testParcelability_largeNumberOfUids() {
+    public void testParcelability_largeNumberOfUids() throws Exception {
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[0]);
 
@@ -141,22 +145,27 @@
             assertThat(uidBatteryConsumer).isNotNull();
             assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(i * 100);
         }
+        inBatteryUsageStats.close();
+        outBatteryUsageStats.close();
     }
 
     @Test
-    public void testDefaultSessionDuration() {
+    public void testDefaultSessionDuration() throws Exception {
         final BatteryUsageStats stats =
                 buildBatteryUsageStats1(true).setStatsDuration(10000).build();
         assertThat(stats.getStatsDuration()).isEqualTo(10000);
+        stats.close();
     }
 
     @Test
-    public void testDump() {
+    public void testDump() throws Exception {
         final BatteryUsageStats stats = buildBatteryUsageStats1(true).build();
         final StringWriter out = new StringWriter();
         try (PrintWriter pw = new PrintWriter(out)) {
             stats.dump(pw, "  ");
         }
+        stats.close();
+
         final String dump = out.toString();
 
         assertThat(dump).contains("Capacity: 4000");
@@ -187,12 +196,14 @@
     }
 
     @Test
-    public void testDumpNoScreenOrPowerState() {
+    public void testDumpNoScreenOrPowerState() throws Exception {
         final BatteryUsageStats stats = buildBatteryUsageStats1(true, false, false).build();
         final StringWriter out = new StringWriter();
         try (PrintWriter pw = new PrintWriter(out)) {
             stats.dump(pw, "  ");
         }
+        stats.close();
+
         final String dump = out.toString();
 
         assertThat(dump).contains("Capacity: 4000");
@@ -222,7 +233,7 @@
     }
 
     @Test
-    public void testAdd() {
+    public void testAdd() throws Exception {
         final BatteryUsageStats stats1 = buildBatteryUsageStats1(false).build();
         final BatteryUsageStats stats2 = buildBatteryUsageStats2(new String[]{"FOO"}, true).build();
         final BatteryUsageStats sum =
@@ -261,24 +272,31 @@
         assertAggregateBatteryConsumer(sum,
                 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE,
                 40211, 40422, 40633, 40844);
+        stats1.close();
+        stats2.close();
+        sum.close();
     }
 
     @Test
-    public void testAdd_customComponentMismatch() {
+    public void testAdd_customComponentMismatch() throws Exception {
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"BAR"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
+        stats.close();
+        builder.discard();
     }
 
     @Test
-    public void testAdd_processStateDataMismatch() {
+    public void testAdd_processStateDataMismatch() throws Exception {
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"FOO"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
+        stats.close();
+        builder.discard();
     }
 
     @Test
@@ -290,12 +308,14 @@
         final BatteryUsageStats stats = buildBatteryUsageStats1(true).build();
         stats.writeXml(serializer);
         serializer.endDocument();
+        stats.close();
 
         ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
         TypedXmlPullParser parser = Xml.newBinaryPullParser();
         parser.setInput(in, StandardCharsets.UTF_8.name());
         final BatteryUsageStats fromXml = BatteryUsageStats.createFromXml(parser);
         assertBatteryUsageStats1(fromXml, true);
+        fromXml.close();
     }
 
     private BatteryUsageStats.Builder buildBatteryUsageStats1(boolean includeUserBatteryConsumer) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 1e4454c..b374a32 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.power.stats;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.usage.NetworkStatsManager;
@@ -80,7 +81,7 @@
             Handler handler, PowerStatsUidResolver powerStatsUidResolver) {
         super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler,
                 mock(PlatformIdleStateCallback.class), mock(EnergyStatsRetriever.class),
-                mock(UserInfoProvider.class), mock(PowerProfile.class),
+                mock(UserInfoProvider.class), mockPowerProfile(),
                 new CpuScalingPolicies(new SparseArray<>(), new SparseArray<>()),
                 powerStatsUidResolver, mock(FrameworkStatsLogger.class),
                 mock(BatteryStatsHistory.TraceDelegate.class),
@@ -96,6 +97,12 @@
         mKernelWakelockReader = null;
     }
 
+    private static PowerProfile mockPowerProfile() {
+        PowerProfile powerProfile = mock(PowerProfile.class);
+        when(powerProfile.getNumDisplays()).thenReturn(1);
+        return powerProfile;
+    }
+
     public void initMeasuredEnergyStats(String[] customBucketNames) {
         final boolean[] supportedStandardBuckets =
                 new boolean[EnergyConsumerStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
index 7aa2e0f..2b55303 100644
--- a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
+++ b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
@@ -19,6 +19,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -50,7 +53,8 @@
             IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
 
     @Mock
-    private Context mContextSpy;
+    private Context mContext;
+    private BackupTransportConnection mBackupTransportConnection;
 
     private ForensicService mForensicService;
     private TestLooper mTestLooper;
@@ -63,7 +67,7 @@
 
         mTestLooper = new TestLooper();
         mLooper = mTestLooper.getLooper();
-        mForensicService = new ForensicService(new MockInjector(mContextSpy));
+        mForensicService = new ForensicService(new MockInjector(mContext));
         mForensicService.onStart();
     }
 
@@ -253,6 +257,8 @@
         assertEquals(STATE_VISIBLE, scb1.mState);
         assertEquals(STATE_VISIBLE, scb2.mState);
 
+        doReturn(true).when(mBackupTransportConnection).initialize();
+
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().enable(ccb);
         mTestLooper.dispatchAll();
@@ -262,6 +268,29 @@
     }
 
     @Test
+    public void testEnable_FromVisible_TwoMonitors_BackupTransportUnavailable()
+            throws RemoteException {
+        mForensicService.setState(STATE_VISIBLE);
+        StateCallback scb1 = new StateCallback();
+        StateCallback scb2 = new StateCallback();
+        mForensicService.getBinderService().monitorState(scb1);
+        mForensicService.getBinderService().monitorState(scb2);
+        mTestLooper.dispatchAll();
+        assertEquals(STATE_VISIBLE, scb1.mState);
+        assertEquals(STATE_VISIBLE, scb2.mState);
+
+        doReturn(false).when(mBackupTransportConnection).initialize();
+
+        CommandCallback ccb = new CommandCallback();
+        mForensicService.getBinderService().enable(ccb);
+        mTestLooper.dispatchAll();
+        assertEquals(STATE_VISIBLE, scb1.mState);
+        assertEquals(STATE_VISIBLE, scb2.mState);
+        assertNotNull(ccb.mErrorCode);
+        assertEquals(ERROR_BACKUP_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue());
+    }
+
+    @Test
     public void testEnable_FromEnabled_TwoMonitors() throws RemoteException {
         mForensicService.setState(STATE_ENABLED);
         StateCallback scb1 = new StateCallback();
@@ -330,6 +359,8 @@
         assertEquals(STATE_ENABLED, scb1.mState);
         assertEquals(STATE_ENABLED, scb2.mState);
 
+        doNothing().when(mBackupTransportConnection).release();
+
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().disable(ccb);
         mTestLooper.dispatchAll();
@@ -356,6 +387,12 @@
             return mLooper;
         }
 
+        @Override
+        public BackupTransportConnection getBackupTransportConnection() {
+            mBackupTransportConnection = spy(new BackupTransportConnection(mContext));
+            return mBackupTransportConnection;
+        }
+
     }
 
     private static class StateCallback extends IForensicServiceStateCallback.Stub {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
index 7829fcc..8df18a8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
@@ -480,7 +480,7 @@
         if (config.getMode() == MAGNIFICATION_MODE_FULLSCREEN) {
             mFullScreenMagnificationControllerStub.resetAndStubMethods();
             mMockFullScreenMagnificationController.setScaleAndCenter(displayId, config.getScale(),
-                    config.getCenterX(), config.getCenterY(), false, SERVICE_ID);
+                    config.getCenterX(), config.getCenterY(), true, false, SERVICE_ID);
             mMagnificationManagerStub.deactivateIfNeed();
         } else if (config.getMode() == MAGNIFICATION_MODE_WINDOW) {
             mMagnificationManagerStub.resetAndStubMethods();
@@ -531,6 +531,9 @@
             };
             doAnswer(enableMagnificationStubAnswer).when(
                     mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(),
+                    anyFloat(), anyFloat(), anyBoolean(), anyBoolean(), eq(SERVICE_ID));
+            doAnswer(enableMagnificationStubAnswer).when(
+                    mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(),
                     anyFloat(), anyFloat(), anyBoolean(), eq(SERVICE_ID));
 
             Answer disableMagnificationStubAnswer = invocation -> {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index c4b4afd..5985abc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
 
+import static com.android.server.accessibility.Flags.FLAG_MAGNIFICATION_ENLARGE_POINTER;
 import static com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationInfoChangedCallback;
 import static com.android.server.accessibility.magnification.MockMagnificationConnection.TEST_DISPLAY;
 import static com.android.window.flags.Flags.FLAG_ALWAYS_DRAW_MAGNIFICATION_FULLSCREEN_BORDER;
@@ -76,6 +77,7 @@
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.Flags;
 import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.input.InputManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
 
@@ -126,6 +128,7 @@
     final Resources mMockResources = mock(Resources.class);
     final AccessibilityTraceManager mMockTraceManager = mock(AccessibilityTraceManager.class);
     final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
+    final InputManagerInternal mMockInputManager = mock(InputManagerInternal.class);
     private final MagnificationAnimationCallback mAnimationCallback = mock(
             MagnificationAnimationCallback.class);
     private final MagnificationInfoChangedCallback mRequestObserver = mock(
@@ -163,6 +166,7 @@
         when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
         when(mMockControllerCtx.getTraceManager()).thenReturn(mMockTraceManager);
         when(mMockControllerCtx.getWindowManager()).thenReturn(mMockWindowManager);
+        when(mMockControllerCtx.getInputManager()).thenReturn(mMockInputManager);
         when(mMockControllerCtx.getHandler()).thenReturn(mMessageCapturingHandler);
         when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
         mResolver = new MockContentResolver();
@@ -285,10 +289,11 @@
                 mFullScreenMagnificationController.magnificationRegionContains(displayId, 100,
                         100));
         assertFalse(mFullScreenMagnificationController.reset(displayId, true));
-        assertFalse(mFullScreenMagnificationController.setScale(displayId, 2, 100, 100, true, 0));
+        assertFalse(
+                mFullScreenMagnificationController.setScale(displayId, 2, 100, 100, true, true, 0));
         assertFalse(mFullScreenMagnificationController.setCenter(displayId, 100, 100, false, 1));
         assertFalse(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                1.5f, 100, 100, false, 2));
+                1.5f, 100, 100, true, false, 2));
         assertTrue(mFullScreenMagnificationController.getIdOfLastServiceToMagnify(displayId) < 0);
 
         mFullScreenMagnificationController.getMagnificationRegion(displayId, new Region());
@@ -313,7 +318,7 @@
         final float scale = 2.0f;
         final PointF center = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         assertFalse(mFullScreenMagnificationController
-                .setScale(TEST_DISPLAY, scale, center.x, center.y, false, SERVICE_ID_1));
+                .setScale(TEST_DISPLAY, scale, center.x, center.y, true, false, SERVICE_ID_1));
         assertFalse(mFullScreenMagnificationController.isActivated(TEST_DISPLAY));
     }
 
@@ -331,7 +336,7 @@
         final PointF center = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
         assertTrue(mFullScreenMagnificationController
-                .setScale(displayId, scale, center.x, center.y, false, SERVICE_ID_1));
+                .setScale(displayId, scale, center.x, center.y, true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets);
@@ -357,7 +362,7 @@
         float scale = 2.0f;
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mFullScreenMagnificationController
-                .setScale(displayId, scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
+                .setScale(displayId, scale, pivotPoint.x, pivotPoint.y, true, true, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         // New center should be halfway between original center and pivot
@@ -405,7 +410,7 @@
         float scale = 2.0f;
         assertTrue(mFullScreenMagnificationController.setScale(displayId, scale,
                 INITIAL_MAGNIFICATION_BOUNDS.centerX(), INITIAL_MAGNIFICATION_BOUNDS.centerY(),
-                false, SERVICE_ID_1));
+                true, false, SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
 
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
@@ -440,7 +445,7 @@
         MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
 
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, scale,
-                newCenter.x, newCenter.y, mAnimationCallback, SERVICE_ID_1));
+                newCenter.x, newCenter.y, true, mAnimationCallback, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
@@ -486,11 +491,11 @@
         final PointF center = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         final float targetScale = 2.0f;
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                targetScale, center.x, center.y, false, SERVICE_ID_1));
+                targetScale, center.x, center.y, true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertFalse(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                targetScale, center.x, center.y, mAnimationCallback, SERVICE_ID_1));
+                targetScale, center.x, center.y, true, mAnimationCallback, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         verify(mMockValueAnimator, never()).start();
@@ -516,7 +521,7 @@
 
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
                 MagnificationScaleProvider.MAX_SCALE + 1.0f,
-                newCenter.x, newCenter.y, false, SERVICE_ID_1));
+                newCenter.x, newCenter.y, true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
@@ -527,7 +532,7 @@
         // Verify that we can't zoom below 1x
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, 0.5f,
                 INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
-                false, SERVICE_ID_1));
+                true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.x,
@@ -551,7 +556,7 @@
 
         // Off the edge to the top and left
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                scale, -100f, -200f, false, SERVICE_ID_1));
+                scale, -100f, -200f, true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
@@ -565,7 +570,7 @@
         // Off the edge to the bottom and right
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId, scale,
                 INITIAL_MAGNIFICATION_BOUNDS.right + 1, INITIAL_MAGNIFICATION_BOUNDS.bottom + 1,
-                false, SERVICE_ID_1));
+                true, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
         newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
@@ -619,7 +624,7 @@
         PointF startOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, startCenter, scale);
         // First zoom in
         assertTrue(mFullScreenMagnificationController
-                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, false,
+                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
         Mockito.reset(mMockWindowManager);
@@ -673,7 +678,7 @@
         // Upper left edges
         PointF ulCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
         assertTrue(mFullScreenMagnificationController
-                .setScaleAndCenter(displayId, scale, ulCenter.x, ulCenter.y, false,
+                .setScaleAndCenter(displayId, scale, ulCenter.x, ulCenter.y, true, false,
                         SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
         MagnificationSpec ulSpec = getCurrentMagnificationSpec(displayId);
@@ -685,7 +690,7 @@
         // Lower right edges
         PointF lrCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mFullScreenMagnificationController
-                .setScaleAndCenter(displayId, scale, lrCenter.x, lrCenter.y, false,
+                .setScaleAndCenter(displayId, scale, lrCenter.x, lrCenter.y, true, false,
                         SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
         MagnificationSpec lrSpec = getCurrentMagnificationSpec(displayId);
@@ -710,7 +715,7 @@
         float scale = 2.0f;
         // First zoom in
         assertTrue(mFullScreenMagnificationController
-                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, false,
+                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
@@ -753,7 +758,7 @@
         PointF startOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, startCenter, scale);
         // First zoom in
         assertTrue(mFullScreenMagnificationController
-                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, false,
+                .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
@@ -786,12 +791,12 @@
         register(displayId);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         assertTrue(mFullScreenMagnificationController
-                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, false,
+                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_1));
         assertEquals(SERVICE_ID_1,
                 mFullScreenMagnificationController.getIdOfLastServiceToMagnify(displayId));
         assertTrue(mFullScreenMagnificationController
-                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
+                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_2));
         assertEquals(SERVICE_ID_2,
                 mFullScreenMagnificationController.getIdOfLastServiceToMagnify(displayId));
@@ -809,10 +814,10 @@
         register(displayId);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         mFullScreenMagnificationController
-                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, false,
+                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_1);
         mFullScreenMagnificationController
-                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
+                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, true, false,
                         SERVICE_ID_2);
         assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, SERVICE_ID_1));
         checkActivatedAndMagnifying(/* activated= */ true, /* magnifying= */ true, displayId);
@@ -873,7 +878,7 @@
         float scale = 2.5f;
         PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                scale, firstCenter.x, firstCenter.y, mAnimationCallback, SERVICE_ID_1));
+                scale, firstCenter.x, firstCenter.y, true, mAnimationCallback, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
         Mockito.reset(mMockValueAnimator);
         // Stubs the logic after the animation is started.
@@ -1076,7 +1081,7 @@
         float scale = 2.0f;
         // setting animate parameter to true is differ from zoomIn2xToMiddle()
         mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
-                true, SERVICE_ID_1);
+                true, true, SERVICE_ID_1);
         MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
@@ -1107,7 +1112,7 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
         mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(startSpec)));
@@ -1148,7 +1153,7 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
-                true, SERVICE_ID_1);
+                true, true, SERVICE_ID_1);
         mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         when(mMockValueAnimator.isRunning()).thenReturn(true);
@@ -1335,7 +1340,7 @@
                 scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, firstCenter, scale));
 
         assertTrue(mFullScreenMagnificationController.setScaleAndCenter(displayId,
-                scale, firstCenter.x, firstCenter.y, true, SERVICE_ID_1));
+                scale, firstCenter.x, firstCenter.y, true, true, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(firstCenter.x, mFullScreenMagnificationController.getCenterX(displayId), 0.5);
@@ -1404,7 +1409,7 @@
         register(DISPLAY_0);
         final float scale = 1.0f;
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, scale, Float.NaN, Float.NaN, true, SERVICE_ID_1);
+                DISPLAY_0, scale, Float.NaN, Float.NaN, true, true, SERVICE_ID_1);
 
         checkActivatedAndMagnifying(/* activated= */ true, /* magnifying= */ false, DISPLAY_0);
         verify(mMockWindowManager).setFullscreenMagnificationActivated(DISPLAY_0, true);
@@ -1449,7 +1454,7 @@
 
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         mFullScreenMagnificationController.setScale(TEST_DISPLAY, 1.0f, pivotPoint.x, pivotPoint.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
         mFullScreenMagnificationController.persistScale(TEST_DISPLAY);
 
         // persistScale may post a task to a background thread. Let's wait for it completes.
@@ -1464,10 +1469,10 @@
         register(DISPLAY_1);
         final PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         mFullScreenMagnificationController.setScale(DISPLAY_0, 3.0f, pivotPoint.x, pivotPoint.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
         mFullScreenMagnificationController.persistScale(DISPLAY_0);
         mFullScreenMagnificationController.setScale(DISPLAY_1, 4.0f, pivotPoint.x, pivotPoint.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
         mFullScreenMagnificationController.persistScale(DISPLAY_1);
 
         // persistScale may post a task to a background thread. Let's wait for it completes.
@@ -1479,6 +1484,101 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void persistScale_setValue_notifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScale(TEST_DISPLAY, 4.0f, pivotPoint.x, pivotPoint.y,
+                /* isScaleTransient= */ true, /* animate= */ false, SERVICE_ID_1);
+        verify(mMockInputManager, never()).setAccessibilityPointerIconScaleFactor(anyInt(),
+                anyFloat());
+
+        mFullScreenMagnificationController.persistScale(TEST_DISPLAY);
+
+        // persistScale may post a task to a background thread. Let's wait for it completes.
+        waitForBackgroundThread();
+        Assert.assertEquals(mFullScreenMagnificationController.getPersistedScale(TEST_DISPLAY),
+                4.0f);
+        verify(mMockInputManager).setAccessibilityPointerIconScaleFactor(TEST_DISPLAY, 4.0f);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void setScale_setNonTransientScale_notifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScale(TEST_DISPLAY, 4.0f, pivotPoint.x, pivotPoint.y,
+                /* isScaleTransient= */ false, /* animate= */ false, SERVICE_ID_1);
+
+        verify(mMockInputManager).setAccessibilityPointerIconScaleFactor(TEST_DISPLAY, 4.0f);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void setScaleAndCenter_setTransientScale_notNotifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF point = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, 3.0f, point.x,
+                point.y, /* isScaleTransient= */ true, /* animate= */ false, SERVICE_ID_1);
+
+        verify(mRequestObserver).onFullScreenMagnificationChanged(anyInt(), any(Region.class),
+                any(MagnificationConfig.class));
+        verify(mMockInputManager, never()).setAccessibilityPointerIconScaleFactor(anyInt(),
+                anyFloat());
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void setScaleAndCenter_setNonTransientScale_notifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF point = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, 3.0f, point.x,
+                point.y, /* isScaleTransient= */ false, /* animate= */ false, SERVICE_ID_1);
+
+        verify(mMockInputManager).setAccessibilityPointerIconScaleFactor(TEST_DISPLAY, 3.0f);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void setCenter_notNotifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF point = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScale(TEST_DISPLAY, 2.0f, point.x, point.y,
+                /* isScaleTransient= */ true, /* animate= */ false, SERVICE_ID_1);
+        mFullScreenMagnificationController.setCenter(TEST_DISPLAY, point.x, point.y, false,
+                SERVICE_ID_1);
+
+        // Note that setCenter doesn't change scale, so it's not necessary to notify the input
+        // manager, but we currently do. The input manager skips redundant computation if the
+        // notified scale is the same as the previous call.
+        verify(mMockInputManager).setAccessibilityPointerIconScaleFactor(TEST_DISPLAY,
+                2.0f);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_MAGNIFICATION_ENLARGE_POINTER)
+    public void offsetMagnifiedRegion_notNotifyInput() {
+        register(TEST_DISPLAY);
+
+        PointF point = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
+        mFullScreenMagnificationController.setScale(TEST_DISPLAY, 2.0f, point.x, point.y,
+                /* isScaleTransient= */ true, /* animate= */ false, SERVICE_ID_1);
+        mFullScreenMagnificationController.offsetMagnifiedRegion(TEST_DISPLAY, 100, 50,
+                SERVICE_ID_1);
+
+        // Note that setCenter doesn't change scale, so it's not necessary to notify the input
+        // manager, but we currently do. The input manager skips redundant computation if the
+        // notified scale is the same as the previous call.
+        verify(mMockInputManager).setAccessibilityPointerIconScaleFactor(TEST_DISPLAY,
+                2.0f);
+    }
+
+    @Test
     public void testOnContextChanged_alwaysOnFeatureDisabled_resetMagnification() {
         setScaleToMagnifying();
 
@@ -1535,7 +1635,7 @@
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
 
         mFullScreenMagnificationController.setScale(DISPLAY_0, scale, pivotPoint.x, pivotPoint.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
     }
 
     private void initMockWindowManager() {
@@ -1578,7 +1678,7 @@
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
         mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
-                false, SERVICE_ID_1);
+                true, false, SERVICE_ID_1);
         checkActivatedAndMagnifying(/* activated= */ true, /* magnifying= */ true, displayId);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index e5831b3..9f5dd93 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -90,6 +90,7 @@
 import com.android.server.accessibility.EventStreamTransformation;
 import com.android.server.accessibility.Flags;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationInfoChangedCallback;
+import com.android.server.input.InputManagerInternal;
 import com.android.server.testutils.OffsettableClock;
 import com.android.server.testutils.TestHandler;
 import com.android.server.wm.WindowManagerInternal;
@@ -227,9 +228,11 @@
         final FullScreenMagnificationController.ControllerContext mockController =
                 mock(FullScreenMagnificationController.ControllerContext.class);
         final WindowManagerInternal mockWindowManager = mock(WindowManagerInternal.class);
+        final InputManagerInternal mockInputManager = mock(InputManagerInternal.class);
         when(mockController.getContext()).thenReturn(mContext);
         when(mockController.getTraceManager()).thenReturn(mMockTraceManager);
         when(mockController.getWindowManager()).thenReturn(mockWindowManager);
+        when(mockController.getInputManager()).thenReturn(mockInputManager);
         when(mockController.getHandler()).thenReturn(new Handler(mContext.getMainLooper()));
         when(mockController.newValueAnimator()).thenReturn(new ValueAnimator());
         when(mockController.getAnimationDuration()).thenReturn(1000L);
@@ -1343,7 +1346,7 @@
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, persistedScale,
                 UserHandle.USER_SYSTEM);
         mFullScreenMagnificationController.setScale(DISPLAY_0, scale, DEFAULT_X,
-                DEFAULT_Y, /* animate= */ false,
+                DEFAULT_Y, true, /* animate= */ false,
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
 
         mMgh.transitionTo(mMgh.mPanningScalingState);
@@ -1364,7 +1367,7 @@
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, persistedScale,
                 UserHandle.USER_SYSTEM);
         mFullScreenMagnificationController.setScale(DISPLAY_0, scale, DEFAULT_X,
-                DEFAULT_Y, /* animate= */ false,
+                DEFAULT_Y, true, /* animate= */ false,
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
 
         mMgh.transitionTo(mMgh.mPanningScalingState);
@@ -1401,7 +1404,7 @@
                 mFullScreenMagnificationController.getPersistedScale(DISPLAY_0);
 
         mFullScreenMagnificationController.setScale(DISPLAY_0, persistedScale, DEFAULT_X,
-                DEFAULT_Y, /* animate= */ false,
+                DEFAULT_Y, true, /* animate= */ false,
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
         mMgh.transitionTo(mMgh.mPanningScalingState);
 
@@ -1438,7 +1441,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 5.6f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         centerX = mFullScreenMagnificationController.getCenterX(DISPLAY_0);
         centerY = mFullScreenMagnificationController.getCenterY(DISPLAY_0);
 
@@ -1530,7 +1533,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 6.2f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         MotionEvent event = mouseEvent(centerX, centerY, ACTION_HOVER_MOVE);
         send(event, InputDevice.SOURCE_MOUSE);
         fastForward(20);
@@ -1571,7 +1574,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 4.0f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
 
         // HOVER_MOVE should change magnifier viewport.
         MotionEvent event = motionEvent(centerX + 20, centerY, ACTION_HOVER_MOVE);
@@ -1615,7 +1618,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 5.3f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         MotionEvent event = motionEvent(centerX, centerY, ACTION_HOVER_MOVE);
         send(event, source);
         fastForward(20);
@@ -1649,7 +1652,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 2.7f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         MotionEvent event = motionEvent(centerX, centerY, ACTION_HOVER_MOVE);
         send(event, source);
         fastForward(20);
@@ -1685,7 +1688,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 3.8f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         centerX = mFullScreenMagnificationController.getCenterX(DISPLAY_0);
         centerY = mFullScreenMagnificationController.getCenterY(DISPLAY_0);
 
@@ -1722,7 +1725,7 @@
                 (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
         float scale = 4.0f; // value is unimportant but unique among tests to increase coverage.
         mFullScreenMagnificationController.setScaleAndCenter(
-                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
+                DISPLAY_0, centerX, centerY, scale, true, /* animate= */ false, 1);
         centerX = mFullScreenMagnificationController.getCenterX(DISPLAY_0);
         centerY = mFullScreenMagnificationController.getCenterY(DISPLAY_0);
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 2528177..8164ef9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -76,6 +76,7 @@
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.input.InputManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.window.flags.Flags;
 
@@ -154,6 +155,8 @@
     private WindowManagerInternal mWindowManagerInternal;
     @Mock
     private WindowManagerInternal.AccessibilityControllerInternal mA11yController;
+    @Mock
+    private InputManagerInternal mInputManagerInternal;
 
     @Mock
     private DisplayManagerInternal mDisplayManagerInternal;
@@ -200,6 +203,7 @@
         when(mControllerCtx.getContext()).thenReturn(mContext);
         when(mControllerCtx.getTraceManager()).thenReturn(mTraceManager);
         when(mControllerCtx.getWindowManager()).thenReturn(mWindowManagerInternal);
+        when(mControllerCtx.getInputManager()).thenReturn(mInputManagerInternal);
         when(mControllerCtx.getHandler()).thenReturn(mMessageCapturingHandler);
         when(mControllerCtx.getAnimationDuration()).thenReturn(1000L);
         when(mControllerCtx.newValueAnimator()).thenReturn(mValueAnimator);
@@ -417,7 +421,7 @@
         assertTrue(mMagnificationConnectionManager.isWindowMagnifierEnabled(TEST_DISPLAY));
         verify(mScreenMagnificationController, never()).setScaleAndCenter(TEST_DISPLAY,
                 DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
-                true, MAGNIFICATION_GESTURE_HANDLER_ID);
+                true, true, MAGNIFICATION_GESTURE_HANDLER_ID);
         verify(mTransitionCallBack).onResult(TEST_DISPLAY, false);
     }
 
@@ -467,7 +471,7 @@
         assertFalse(mMagnificationConnectionManager.isWindowMagnifierEnabled(TEST_DISPLAY));
         verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
                 eq(DEFAULT_SCALE), eq(MAGNIFIED_CENTER_X), eq(MAGNIFIED_CENTER_Y),
-                any(MagnificationAnimationCallback.class), eq(TEST_SERVICE_ID));
+                eq(false), any(MagnificationAnimationCallback.class), eq(TEST_SERVICE_ID));
     }
 
     @Test
@@ -484,7 +488,7 @@
 
         verify(mScreenMagnificationController, never()).setScaleAndCenter(anyInt(),
                 anyFloat(), anyFloat(), anyFloat(),
-                anyBoolean(), anyInt());
+                anyBoolean(), anyBoolean(), anyInt());
     }
 
     @Test
@@ -546,7 +550,7 @@
                 config, animate, TEST_SERVICE_ID);
         verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
                 /* scale= */ anyFloat(), /* centerX= */ anyFloat(), /* centerY= */ anyFloat(),
-                mCallbackArgumentCaptor.capture(), /* id= */ anyInt());
+                anyBoolean(), mCallbackArgumentCaptor.capture(), /* id= */ anyInt());
         mCallbackArgumentCaptor.getValue().onResult(true);
         mMockConnection.invokeCallbacks();
 
@@ -616,7 +620,7 @@
     @Test
     public void magnifyThroughExternalRequest_showMagnificationButton() {
         mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, DEFAULT_SCALE,
-                MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, false, TEST_SERVICE_ID);
+                MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, true, false, TEST_SERVICE_ID);
 
         // The first time is trigger when fullscreen mode is activated.
         // The second time is triggered when magnification spec is changed.
@@ -638,7 +642,7 @@
         mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale, updatePersistence);
 
         verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), eq(newScale),
-                anyFloat(), anyFloat(), anyBoolean(), anyInt());
+                anyFloat(), anyFloat(), anyBoolean(), anyBoolean(), anyInt());
         verify(mScreenMagnificationController).persistScale(eq(TEST_DISPLAY));
     }
 
@@ -681,7 +685,7 @@
         final MagnificationConfig config = obtainMagnificationConfig(MODE_FULLSCREEN);
         mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
                 config.getScale(), config.getCenterX(), config.getCenterY(),
-                true, TEST_SERVICE_ID);
+                true, true, TEST_SERVICE_ID);
 
         // The notify method is triggered when setting magnification enabled.
         // The setScaleAndCenter call should not trigger notify method due to same scale and center.
@@ -930,7 +934,7 @@
     public void onWindowModeActivated_fullScreenIsActivatedByExternal_fullScreenIsDisabled() {
         mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY,
                 DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
-                true, TEST_SERVICE_ID);
+                true, true, TEST_SERVICE_ID);
 
         mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true);
 
@@ -1317,7 +1321,8 @@
         }
         if (mode == MODE_FULLSCREEN) {
             mScreenMagnificationController.setScaleAndCenter(displayId, DEFAULT_SCALE, centerX,
-                    centerY, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+                    centerY, true, true,
+                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
         } else {
             mMagnificationConnectionManager.enableWindowMagnification(displayId, DEFAULT_SCALE,
                     centerX, centerY, null, TEST_SERVICE_ID);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index c30b4bb..c3466b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -139,7 +139,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.provider.DeviceConfig;
 import android.util.MutableBoolean;
 import android.view.DisplayInfo;
@@ -2662,8 +2661,11 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT)
     public void testSetOrientation_restrictedByTargetSdk() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT);
+        mDisplayContent.setIgnoreOrientationRequest(true);
+        makeDisplayLargeScreen(mDisplayContent);
+
         assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_SOCIAL, false);
         assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_GAME, true);
 
@@ -2673,12 +2675,13 @@
     }
 
     private void assertSetOrientation(int targetSdk, int category, boolean expectRotate) {
-        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
-        activity.mTargetSdk = targetSdk;
+        final String packageName = targetSdk <= Build.VERSION_CODES.VANILLA_ICE_CREAM
+                ? mContext.getPackageName() // WmTests uses legacy sdk.
+                : null; // Simulate CUR_DEVELOPMENT by invalid package (see PlatformCompat).
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setComponent(getUniqueComponentName(packageName)).build();
         activity.info.applicationInfo.category = category;
 
-        activity.setVisible(true);
-
         // Assert orientation is unspecified to start.
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index c8a3559..08963f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -307,6 +307,8 @@
     void createNewTaskWithBaseActivity() {
         final Task newTask = new WindowTestsBase.TaskBuilder(mSupervisor)
                 .setCreateActivity(true)
+                // Respect "@ChangeId" according to test package's target sdk.
+                .setPackage(mAtm.mContext.getPackageName())
                 .setDisplay(mDisplayContent).build();
         mTaskStack.push(newTask);
         pushActivity(newTask.getTopNonFinishingActivity());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 5c0d424..2bebcc3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1081,7 +1081,8 @@
         final DisplayRotation dr = dc.getDisplayRotation();
         spyOn(dr);
         doReturn(false).when(dr).useDefaultSettingsProvider();
-        final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setComponent(getUniqueComponentName(mContext.getPackageName())).build();
         app.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, app);
 
         assertFalse(dc.getRotationReversionController().isAnyOverrideActive());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index 35c9e3f..f4fa12e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -51,6 +51,7 @@
 import android.app.servertransaction.RefreshCallbackItem;
 import android.app.servertransaction.ResumeActivityItem;
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -592,6 +593,11 @@
                 .setTask(mTask)
                 .build();
 
+        spyOn(mActivity.info.applicationInfo);
+        // Disable for camera compat.
+        doReturn(false).when(mActivity.info.applicationInfo).isChangeEnabled(
+                ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
+
         spyOn(mActivity.mAtmService.getLifecycleManager());
         spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index cf1dcd0..7e8bd38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -285,6 +285,52 @@
     }
 
     @Test
+    public void testTaskLayerRankFreeform() {
+        mSetFlagsRule.enableFlags(com.android.window.flags.Flags
+                .FLAG_PROCESS_PRIORITY_POLICY_FOR_MULTI_WINDOW_MODE);
+        final Task[] freeformTasks = new Task[3];
+        final WindowProcessController[] processes = new WindowProcessController[3];
+        for (int i = 0; i < freeformTasks.length; i++) {
+            freeformTasks[i] = new TaskBuilder(mSupervisor)
+                    .setWindowingMode(WINDOWING_MODE_FREEFORM).setCreateActivity(true).build();
+            final ActivityRecord r = freeformTasks[i].getTopMostActivity();
+            r.setState(RESUMED, "test");
+            processes[i] = r.app;
+        }
+        resizeDisplay(mDisplayContent, 2400, 2000);
+        // ---------
+        // | 2 | 1 |
+        // ---------
+        // | 0 |   |
+        // ---------
+        freeformTasks[2].setBounds(0, 0, 1000, 1000);
+        freeformTasks[1].setBounds(1000, 0, 2000, 1000);
+        freeformTasks[0].setBounds(0, 1000, 1000, 2000);
+        mRootWindowContainer.rankTaskLayers();
+        assertEquals(1, freeformTasks[2].mLayerRank);
+        assertEquals(2, freeformTasks[1].mLayerRank);
+        assertEquals(3, freeformTasks[0].mLayerRank);
+        assertFalse("Top doesn't need perceptible hint", (processes[2].getActivityStateFlags()
+                & WindowProcessController.ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM) != 0);
+        assertTrue((processes[1].getActivityStateFlags()
+                & WindowProcessController.ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM) != 0);
+        assertTrue((processes[0].getActivityStateFlags()
+                & WindowProcessController.ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM) != 0);
+
+        // Make task2 occlude half of task0.
+        clearInvocations(mAtm);
+        freeformTasks[2].setBounds(0, 0, 1000, 1500);
+        waitHandlerIdle(mWm.mH);
+        // The process of task0 will demote from perceptible to visible.
+        final int stateFlags0 = processes[0].getActivityStateFlags();
+        assertTrue((stateFlags0
+                & WindowProcessController.ACTIVITY_STATE_FLAG_VISIBLE_MULTI_WINDOW_MODE) != 0);
+        assertFalse((stateFlags0
+                & WindowProcessController.ACTIVITY_STATE_FLAG_PERCEPTIBLE_FREEFORM) != 0);
+        verify(mAtm).updateOomAdj();
+    }
+
+    @Test
     public void testForceStopPackage() {
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         final ActivityRecord activity = task.getTopMostActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index e956e22..e66dfeb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4824,12 +4824,7 @@
         assertFalse(mActivity.isUniversalResizeable());
 
         mDisplayContent.setIgnoreOrientationRequest(true);
-        final int swDp = mDisplayContent.getConfiguration().smallestScreenWidthDp;
-        if (swDp < WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP) {
-            final int height = 100 + (int) (mDisplayContent.getDisplayMetrics().density
-                    * WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP);
-            resizeDisplay(mDisplayContent, 100 + height, height);
-        }
+        makeDisplayLargeScreen(mDisplayContent);
         assertTrue(mActivity.isUniversalResizeable());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index a215c0a..757c358 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1123,6 +1123,15 @@
         displayContent.onRequestedOverrideConfigurationChanged(c);
     }
 
+    static void makeDisplayLargeScreen(DisplayContent displayContent) {
+        final int swDp = displayContent.getConfiguration().smallestScreenWidthDp;
+        if (swDp < WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP) {
+            final int height = 100 + (int) (displayContent.getDisplayMetrics().density
+                    * WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP);
+            resizeDisplay(displayContent, 100 + height, height);
+        }
+    }
+
     /** Used for the tests that assume the display is portrait by default. */
     static void makeDisplayPortrait(DisplayContent displayContent) {
         if (displayContent.mBaseDisplayHeight <= displayContent.mBaseDisplayWidth) {
@@ -1223,7 +1232,14 @@
     }
 
     static ComponentName getUniqueComponentName() {
-        return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
+        return getUniqueComponentName(DEFAULT_COMPONENT_PACKAGE_NAME);
+    }
+
+    static ComponentName getUniqueComponentName(String packageName) {
+        if (packageName == null) {
+            packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
+        }
+        return ComponentName.createRelative(packageName,
                 DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
     }
 
@@ -1298,8 +1314,7 @@
         ActivityBuilder setActivityTheme(int theme) {
             mActivityTheme = theme;
             // Use the real package of test so it can get a valid context for theme.
-            mComponent = ComponentName.createRelative(mService.mContext.getPackageName(),
-                    DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
+            mComponent = getUniqueComponentName(mService.mContext.getPackageName());
             return this;
         }
 
@@ -1743,7 +1758,7 @@
             if (mIntent == null) {
                 mIntent = new Intent();
                 if (mComponent == null) {
-                    mComponent = getUniqueComponentName();
+                    mComponent = getUniqueComponentName(mPackage);
                 }
                 mIntent.setComponent(mComponent);
                 mIntent.setFlags(mFlags);
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 6742cbe..168141b 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -41,6 +41,7 @@
         "hamcrest-library",
         "junit-params",
         "kotlin-test",
+        "mockito-kotlin-nodeps",
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
         "platform-screenshot-diff-core",
diff --git a/tests/Input/src/com/android/server/input/PointerIconCacheTest.kt b/tests/Input/src/com/android/server/input/PointerIconCacheTest.kt
new file mode 100644
index 0000000..47e7ac7
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/PointerIconCacheTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2024 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.input
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.os.Handler
+import android.os.test.TestLooper
+import android.platform.test.annotations.Presubmit
+import android.view.Display
+import android.view.PointerIcon
+import androidx.test.platform.app.InstrumentationRegistry
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for {@link PointerIconCache}.
+ */
+@Presubmit
+class PointerIconCacheTest {
+
+    @get:Rule
+    val rule = MockitoJUnit.rule()!!
+
+    @Mock
+    private lateinit var native: NativeInputManagerService
+    @Mock
+    private lateinit var defaultDisplay: Display
+
+    private lateinit var context: Context
+    private lateinit var testLooper: TestLooper
+    private lateinit var cache: PointerIconCache
+
+    @Before
+    fun setup() {
+        whenever(defaultDisplay.displayId).thenReturn(Display.DEFAULT_DISPLAY)
+
+        context = object : ContextWrapper(InstrumentationRegistry.getInstrumentation().context) {
+            override fun getDisplay() = defaultDisplay
+        }
+
+        testLooper = TestLooper()
+        cache = PointerIconCache(context, native, Handler(testLooper.looper))
+    }
+
+    @Test
+    fun testSetPointerScale() {
+        val defaultBitmap = getDefaultIcon().bitmap
+        cache.setPointerScale(2f)
+
+        testLooper.dispatchAll()
+        verify(native).reloadPointerIcons()
+
+        val bitmap =
+            cache.getLoadedPointerIcon(Display.DEFAULT_DISPLAY, PointerIcon.TYPE_ARROW).bitmap
+
+        assertEquals(defaultBitmap.height * 2, bitmap.height)
+        assertEquals(defaultBitmap.width * 2, bitmap.width)
+    }
+
+    @Test
+    fun testSetAccessibilityScaleFactor() {
+        val defaultBitmap = getDefaultIcon().bitmap
+        cache.setAccessibilityScaleFactor(Display.DEFAULT_DISPLAY, 4f)
+
+        testLooper.dispatchAll()
+        verify(native).reloadPointerIcons()
+
+        val bitmap =
+            cache.getLoadedPointerIcon(Display.DEFAULT_DISPLAY, PointerIcon.TYPE_ARROW).bitmap
+
+        assertEquals(defaultBitmap.height * 4, bitmap.height)
+        assertEquals(defaultBitmap.width * 4, bitmap.width)
+    }
+
+    @Test
+    fun testSetAccessibilityScaleFactorOnSecondaryDisplay() {
+        val defaultBitmap = getDefaultIcon().bitmap
+        val secondaryDisplayId = Display.DEFAULT_DISPLAY + 1
+        cache.setAccessibilityScaleFactor(secondaryDisplayId, 4f)
+
+        testLooper.dispatchAll()
+        verify(native).reloadPointerIcons()
+
+        val bitmap =
+            cache.getLoadedPointerIcon(Display.DEFAULT_DISPLAY, PointerIcon.TYPE_ARROW).bitmap
+        assertEquals(defaultBitmap.height, bitmap.height)
+        assertEquals(defaultBitmap.width, bitmap.width)
+
+        val bitmapSecondary =
+            cache.getLoadedPointerIcon(secondaryDisplayId, PointerIcon.TYPE_ARROW).bitmap
+        assertEquals(defaultBitmap.height * 4, bitmapSecondary.height)
+        assertEquals(defaultBitmap.width * 4, bitmapSecondary.width)
+    }
+
+    @Test
+    fun testSetPointerScaleAndAccessibilityScaleFactor() {
+        val defaultBitmap = getDefaultIcon().bitmap
+        cache.setPointerScale(2f)
+        cache.setAccessibilityScaleFactor(Display.DEFAULT_DISPLAY, 3f)
+
+        testLooper.dispatchAll()
+        verify(native, times(2)).reloadPointerIcons()
+
+        val bitmap =
+            cache.getLoadedPointerIcon(Display.DEFAULT_DISPLAY, PointerIcon.TYPE_ARROW).bitmap
+
+        assertEquals(defaultBitmap.height * 6, bitmap.height)
+        assertEquals(defaultBitmap.width * 6, bitmap.width)
+    }
+
+    private fun getDefaultIcon() =
+        PointerIcon.getLoadedSystemIcon(context, PointerIcon.TYPE_ARROW, false, 1f)
+}