Merge "Import translations. DO NOT MERGE ANYWHERE"
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
index 971c0ca..a1383e6 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -306,10 +306,9 @@
 
             while (state.keepRunning(measuredTimeNs)) {
                 setImeListener(activity, latchStart, latchEnd);
-                latchStart.set(new CountDownLatch(show ? 1 : 2));
-                latchEnd.set(new CountDownLatch(2));
                 // For measuring hide, lets show IME first.
                 if (!show) {
+                    initLatch(latchStart, latchEnd);
                     AtomicBoolean showCalled = new AtomicBoolean();
                     getInstrumentation().runOnMainSync(() -> {
                         if (!isImeVisible(activity)) {
@@ -318,9 +317,10 @@
                         }
                     });
                     if (showCalled.get()) {
-                        PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS,
-                                () -> latchStart.get().getCount() == 1
-                                        && latchEnd.get().getCount() == 1);
+                        PollingCheck.check("IME show animation should finish ",
+                                TIMEOUT_1_S_IN_MS * 3,
+                                () -> latchStart.get().getCount() == 0
+                                        && latchEnd.get().getCount() == 0);
                     }
                 }
                 if (!mIsTraceStarted && !state.isWarmingUp()) {
@@ -330,6 +330,7 @@
 
                 AtomicLong startTime = new AtomicLong();
                 AtomicBoolean unexpectedVisibility = new AtomicBoolean();
+                initLatch(latchStart, latchEnd);
                 getInstrumentation().runOnMainSync(() -> {
                     boolean isVisible = isImeVisible(activity);
                     startTime.set(SystemClock.elapsedRealtimeNanos());
@@ -348,11 +349,15 @@
                     long timeElapsed = waitForAnimationStart(latchStart, startTime);
                     if (timeElapsed != ANIMATION_NOT_STARTED) {
                         measuredTimeNs = timeElapsed;
+                        // wait for animation to end or we may start two animations and timing
+                        // will not be measured accurately.
+                        waitForAnimationEnd(latchEnd);
                     }
                 }
 
                 // hide IME before next iteration.
                 if (show) {
+                    initLatch(latchStart, latchEnd);
                     activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime()));
                     try {
                         latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
@@ -374,6 +379,12 @@
         addResultToState(state);
     }
 
+    private void initLatch(AtomicReference<CountDownLatch> latchStart,
+            AtomicReference<CountDownLatch> latchEnd) {
+        latchStart.set(new CountDownLatch(1));
+        latchEnd.set(new CountDownLatch(1));
+    }
+
     @UiThread
     private boolean isImeVisible(@NonNull final Activity activity) {
         return activity.getWindow().getDecorView().getRootWindowInsets().isVisible(
@@ -383,7 +394,7 @@
     private long waitForAnimationStart(
             AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) {
         try {
-            latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
+            latchStart.get().await(5, TimeUnit.SECONDS);
             if (latchStart.get().getCount() != 0) {
                 return ANIMATION_NOT_STARTED;
             }
@@ -392,6 +403,12 @@
         return SystemClock.elapsedRealtimeNanos() - startTime.get();
     }
 
+    private void waitForAnimationEnd(AtomicReference<CountDownLatch> latchEnd) {
+        try {
+            latchEnd.get().await(3, TimeUnit.SECONDS);
+        } catch (InterruptedException e) { }
+    }
+
     private void addResultToState(ManualBenchmarkState state) {
         mTraceMethods.forAllSlices((key, slices) -> {
             for (TraceMarkSlice slice : slices) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index 0b5ff1b..f08dd24 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -311,6 +311,8 @@
                     case AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK:
                         return "ALARM_CLOCK";
                 }
+                break;
+
             case POLICY_JS:
                 switch (eventId) {
                     case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START:
@@ -336,6 +338,7 @@
                     case JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT:
                         return "JOB_TIMEOUT";
                 }
+                break;
         }
         return "UNKNOWN_ACTION:" + Integer.toHexString(eventId);
     }
diff --git a/core/api/current.txt b/core/api/current.txt
index 894a894..69c9439 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -30831,7 +30831,7 @@
     field public static final int Q = 29; // 0x1d
     field public static final int R = 30; // 0x1e
     field public static final int S = 31; // 0x1f
-    field public static final int T = 10000; // 0x2710
+    field public static final int TIRAMISU = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
old mode 100644
new mode 100755
index 0d15a03..78e899f
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -924,6 +924,7 @@
   }
 
   public class DevicePolicyManager {
+    method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -972,6 +973,7 @@
     field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
     field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
     field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4
+    field public static final int PROVISIONING_TRIGGER_NFC = 5; // 0x5
     field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
     field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
     field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e00c16d..fb481eb 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3272,8 +3272,8 @@
 
   public class WindowOrganizer {
     ctor public WindowOrganizer();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
+    method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback);
+    method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction);
   }
 
   @UiContext public abstract class WindowProviderService extends android.app.Service {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e5b5a677..2c38688 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -56,6 +56,7 @@
 import android.net.PrivateDnsConnectivityChecker;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.nfc.NfcAdapter;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -1216,7 +1217,8 @@
             PROVISIONING_TRIGGER_CLOUD_ENROLLMENT,
             PROVISIONING_TRIGGER_QR_CODE,
             PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER,
-            PROVISIONING_TRIGGER_MANAGED_ACCOUNT
+            PROVISIONING_TRIGGER_MANAGED_ACCOUNT,
+            PROVISIONING_TRIGGER_NFC
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProvisioningTrigger {}
@@ -1254,6 +1256,7 @@
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_QR_CODE
      * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
+     * @see #PROVISIONING_TRIGGER_NFC
      * @hide
      */
     @SystemApi
@@ -1265,6 +1268,7 @@
      * @see #PROVISIONING_TRIGGER_QR_CODE
      * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @see #PROVISIONING_TRIGGER_NFC
      * @hide
      */
     @SystemApi
@@ -1276,6 +1280,7 @@
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @see #PROVISIONING_TRIGGER_NFC
      * @hide
      */
     @SystemApi
@@ -1295,6 +1300,7 @@
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_QR_CODE
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @see #PROVISIONING_TRIGGER_NFC
      * @hide
      */
     @SystemApi
@@ -1308,12 +1314,25 @@
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_QR_CODE
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @see #PROVISIONING_TRIGGER_NFC
      * @hide
      */
     @SystemApi
     public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4;
 
     /**
+     * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning is
+     * triggered by tapping an NFC tag.
+     * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+     * @see #PROVISIONING_TRIGGER_QR_CODE
+     * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
+     * @hide
+     */
+    @SystemApi
+    public static final int PROVISIONING_TRIGGER_NFC = 5;
+
+    /**
      * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
      * organization-owned.
      *
@@ -14009,4 +14028,33 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Creates a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent
+     * from the provided {@code nfcIntent}.
+     *
+     * <p>Prerequisites to create the provisioning intent:
+     *
+     * <ul>
+     * <li>{@code nfcIntent}'s action is {@link NfcAdapter#ACTION_NDEF_DISCOVERED}</li>
+     * <li>{@code nfcIntent}'s NFC properties contain either
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} or
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} </li>
+     * </ul>
+     *
+     * This method returns {@code null} if the prerequisites are not met or if an error occurs
+     * when reading the NFC properties.
+     *
+     * @param nfcIntent the nfc intent generated from scanning a NFC tag
+     * @return a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent with
+     * intent extras as read by {@code nfcIntent}'s NFC properties or {@code null} if the
+     * prerequisites are not met or if an error occurs when reading the NFC properties.
+     *
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) {
+        return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent);
+    }
 }
diff --git a/core/java/android/app/admin/ProvisioningIntentHelper.java b/core/java/android/app/admin/ProvisioningIntentHelper.java
new file mode 100644
index 0000000..fbad90c
--- /dev/null
+++ b/core/java/android/app/admin/ProvisioningIntentHelper.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2021 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.app.admin;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
+import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC;
+import static android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Utility class that provides functionality to create provisioning intents from nfc intents.
+ */
+final class ProvisioningIntentHelper {
+
+    private static final String TAG = "ProvisioningIntentHelper";
+
+    /**
+     * This class is never instantiated
+     */
+    private ProvisioningIntentHelper() { }
+
+    @Nullable
+    public static Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) {
+        requireNonNull(nfcIntent);
+
+        if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(nfcIntent.getAction())) {
+            Log.e(TAG, "Wrong Nfc action: " + nfcIntent.getAction());
+            return null;
+        }
+
+        NdefRecord firstRecord = getFirstNdefRecord(nfcIntent);
+
+        if (firstRecord != null) {
+            return createProvisioningIntentFromNdefRecord(firstRecord);
+        }
+
+        return null;
+    }
+
+
+    private static Intent createProvisioningIntentFromNdefRecord(NdefRecord firstRecord) {
+        requireNonNull(firstRecord);
+
+        Properties properties = loadPropertiesFromPayload(firstRecord.getPayload());
+
+        if (properties == null) {
+            Log.e(TAG, "Failed to load NdefRecord properties.");
+            return null;
+        }
+
+        Bundle bundle = createBundleFromProperties(properties);
+
+        if (!containsRequiredProvisioningExtras(bundle)) {
+            Log.e(TAG, "Bundle does not contain the required provisioning extras.");
+            return null;
+        }
+
+        return createProvisioningIntentFromBundle(bundle);
+    }
+
+    private static Properties loadPropertiesFromPayload(byte[] payload) {
+        Properties properties = new Properties();
+
+        try {
+            properties.load(new StringReader(new String(payload, UTF_8)));
+        } catch (IOException e) {
+            Log.e(TAG, "NFC Intent properties loading failed.");
+            return null;
+        }
+
+        return properties;
+    }
+
+    private static Bundle createBundleFromProperties(Properties properties) {
+        Enumeration propertyNames = properties.propertyNames();
+        Bundle bundle = new Bundle();
+
+        while (propertyNames.hasMoreElements()) {
+            String propertyName = (String) propertyNames.nextElement();
+            addPropertyToBundle(propertyName, properties, bundle);
+        }
+        return bundle;
+    }
+
+    private static void addPropertyToBundle(
+            String propertyName, Properties properties, Bundle bundle) {
+        if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(propertyName)) {
+            ComponentName componentName = ComponentName.unflattenFromString(
+                    properties.getProperty(propertyName));
+            bundle.putParcelable(propertyName, componentName);
+        }
+        else {
+            bundle.putString(propertyName, properties.getProperty(propertyName));
+        }
+    }
+
+    private static Intent createProvisioningIntentFromBundle(Bundle bundle) {
+        requireNonNull(bundle);
+
+        Intent provisioningIntent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
+
+        provisioningIntent.putExtras(bundle);
+
+        provisioningIntent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC);
+
+        return provisioningIntent;
+    }
+
+    private static boolean containsRequiredProvisioningExtras(Bundle bundle) {
+        return bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME) ||
+                bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME);
+    }
+
+    /**
+     * Returns the first {@link NdefRecord} found with a recognized MIME-type
+     */
+    private static NdefRecord getFirstNdefRecord(Intent nfcIntent) {
+        Parcelable[] ndefMessages = nfcIntent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES);
+        if (ndefMessages == null) {
+            Log.i(TAG, "No EXTRA_NDEF_MESSAGES from nfcIntent");
+            return null;
+        }
+
+        for (Parcelable rawMsg : ndefMessages) {
+            NdefMessage msg = (NdefMessage) rawMsg;
+            for (NdefRecord record : msg.getRecords()) {
+                String mimeType = new String(record.getType(), UTF_8);
+
+                // Only one first message with NFC_MIME_TYPE is used.
+                if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType)) {
+                    return record;
+                }
+
+                // Assume only first record of message is used.
+                break;
+            }
+        }
+
+        Log.i(TAG, "No compatible records found on nfcIntent");
+        return null;
+    }
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 9af0e09..3184c71 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -931,6 +931,9 @@
      * on the provided PendingIntent, then the client will be automatically unregistered by the
      * service.
      *
+     * Note that the {@link PendingIntent} supplied to this API must be mutable for Intent
+     * notifications to work.
+     *
      * @param context       the context of the application. If a PendingIntent client is recreated,
      * the latest state in the context will be used and old state will be discarded
      * @param hubInfo       the hub to attach this client to
@@ -938,7 +941,8 @@
      * @param nanoAppId     the ID of the nanoapp that Intent events will be generated for
      * @return the registered client object
      *
-     * @throws IllegalArgumentException if hubInfo does not represent a valid hub
+     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or an immutable
+     *                                  PendingIntent was supplied
      * @throws IllegalStateException    if there were too many registered clients at the service
      * @throws NullPointerException     if pendingIntent or hubInfo is null
      */
@@ -951,6 +955,9 @@
             @NonNull PendingIntent pendingIntent, long nanoAppId) {
         Objects.requireNonNull(pendingIntent);
         Objects.requireNonNull(hubInfo);
+        if (pendingIntent.isImmutable()) {
+            throw new IllegalArgumentException("PendingIntent must be mutable");
+        }
 
         ContextHubClient client = new ContextHubClient(hubInfo, true /* persistent */);
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index f7b1525..394d270 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1132,9 +1132,9 @@
         public static final int S = 31;
 
         /**
-         * T.
+         * Tiramisu.
          */
-        public static final int T = CUR_DEVELOPMENT;
+        public static final int TIRAMISU = CUR_DEVELOPMENT;
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1793eaf..f3ebe5b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10079,9 +10079,11 @@
                 }
                 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
-                ViewStructure child = structure.newChild(i);
-                populateVirtualStructure(child, provider, cinfo, forAutofill);
-                cinfo.recycle();
+                if (cinfo != null) {
+                    ViewStructure child = structure.newChild(i);
+                    populateVirtualStructure(child, provider, cinfo, forAutofill);
+                    cinfo.recycle();
+                }
             }
         }
     }
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index e674655..6758a3b 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -265,6 +265,7 @@
         }
     };
 
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
     private IDisplayAreaOrganizerController getController() {
         try {
             return getWindowOrganizerController().getDisplayAreaOrganizerController();
@@ -272,5 +273,4 @@
             return null;
         }
     }
-
 }
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 3b4d4e5..b252df7 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -120,6 +120,19 @@
     public void onTaskFragmentError(
             @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {}
 
+    @Override
+    public void applyTransaction(@NonNull WindowContainerTransaction t) {
+        t.setTaskFragmentOrganizer(mInterface);
+        super.applyTransaction(t);
+    }
+
+    @Override
+    public int applySyncTransaction(@NonNull WindowContainerTransaction t,
+            @NonNull WindowContainerTransactionCallback callback) {
+        t.setTaskFragmentOrganizer(mInterface);
+        return super.applySyncTransaction(t, callback);
+    }
+
     private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
         @Override
         public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) {
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 8fa0110..6f250fc 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -290,6 +290,7 @@
         }
     };
 
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
     private ITaskOrganizerController getController() {
         try {
             return getWindowOrganizerController().getTaskOrganizerController();
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 9c512ad..8735ed8 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -35,6 +35,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Represents a collection of operations on some WindowContainers that should be applied all at
@@ -52,12 +53,16 @@
     @Nullable
     private IBinder mErrorCallbackToken;
 
+    @Nullable
+    private ITaskFragmentOrganizer mTaskFragmentOrganizer;
+
     public WindowContainerTransaction() {}
 
     private WindowContainerTransaction(Parcel in) {
         in.readMap(mChanges, null /* loader */);
         in.readList(mHierarchyOps, null /* loader */);
         mErrorCallbackToken = in.readStrongBinder();
+        mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder());
     }
 
     private Change getOrCreateChange(IBinder token) {
@@ -473,7 +478,7 @@
         final HierarchyOp hierarchyOp =
                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN)
                         .setContainer(oldParent.asBinder())
-                        .setReparentContainer(newParent.asBinder())
+                        .setReparentContainer(newParent != null ? newParent.asBinder() : null)
                         .build();
         mHierarchyOps.add(hierarchyOp);
         return this;
@@ -497,6 +502,23 @@
     }
 
     /**
+     * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}.
+     * When this is set, the server side will not check for the permission of
+     * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only
+     * contains operations that are allowed for this organizer, such as modifying TaskFragments that
+     * are organized by this organizer.
+     * @hide
+     */
+    @NonNull
+    WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
+        if (mTaskFragmentOrganizer != null) {
+            throw new IllegalStateException("Can't set multiple organizers for one transaction.");
+        }
+        mTaskFragmentOrganizer = organizer;
+        return this;
+    }
+
+    /**
      * Merges another WCT into this one.
      * @param transfer When true, this will transfer everything from other potentially leaving
      *                 other in an unusable state. When false, other is left alone, but
@@ -519,7 +541,17 @@
         }
         if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken
                 != other.mErrorCallbackToken) {
-            throw new IllegalArgumentException("Can't merge two WCT with different error token");
+            throw new IllegalArgumentException("Can't merge two WCTs with different error token");
+        }
+        final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null
+                ? mTaskFragmentOrganizer.asBinder()
+                : null;
+        final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null
+                ? other.mTaskFragmentOrganizer.asBinder()
+                : null;
+        if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) {
+            throw new IllegalArgumentException(
+                    "Can't merge two WCTs from different TaskFragmentOrganizers");
         }
         mErrorCallbackToken = mErrorCallbackToken != null
                 ? mErrorCallbackToken
@@ -547,11 +579,21 @@
         return mErrorCallbackToken;
     }
 
+    /** @hide */
+    @Nullable
+    public ITaskFragmentOrganizer getTaskFragmentOrganizer() {
+        return mTaskFragmentOrganizer;
+    }
+
     @Override
     @NonNull
     public String toString() {
-        return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
-                + " errorCallbackToken=" + mErrorCallbackToken + " }";
+        return "WindowContainerTransaction {"
+                + " changes = " + mChanges
+                + " hops = " + mHierarchyOps
+                + " errorCallbackToken=" + mErrorCallbackToken
+                + " taskFragmentOrganizer=" + mTaskFragmentOrganizer
+                + " }";
     }
 
     @Override
@@ -560,6 +602,7 @@
         dest.writeMap(mChanges);
         dest.writeList(mHierarchyOps);
         dest.writeStrongBinder(mErrorCallbackToken);
+        dest.writeStrongInterface(mTaskFragmentOrganizer);
     }
 
     @Override
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 544d422..78dbeba 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -36,9 +36,16 @@
 
     /**
      * Apply multiple WindowContainer operations at once.
+     *
+     * Note that using this API requires the caller to hold
+     * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using
+     * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is
+     * created by itself.
+     *
      * @param t The transaction to apply.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            conditional = true)
     public void applyTransaction(@NonNull WindowContainerTransaction t) {
         try {
             if (!t.isEmpty()) {
@@ -51,6 +58,12 @@
 
     /**
      * Apply multiple WindowContainer operations at once.
+     *
+     * Note that using this API requires the caller to hold
+     * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using
+     * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is
+     * created by itself.
+     *
      * @param t The transaction to apply.
      * @param callback This transaction will use the synchronization scheme described in
      *        BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this
@@ -58,7 +71,8 @@
      * @return An ID for the sync operation which will later be passed to transactionReady callback.
      *         This lets the caller differentiate overlapping sync operations.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            conditional = true)
     public int applySyncTransaction(@NonNull WindowContainerTransaction t,
             @NonNull WindowContainerTransactionCallback callback) {
         try {
@@ -123,7 +137,6 @@
         }
     }
 
-    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
     IWindowOrganizerController getWindowOrganizerController() {
         return IWindowOrganizerControllerSingleton.get();
     }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1d07c26..e274595 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -311,6 +311,7 @@
             header_libs: [
                 "bionic_libc_platform_headers",
                 "dnsproxyd_protocol_headers",
+                "libandroid_runtime_vm_headers",
             ],
         },
         host: {
@@ -386,3 +387,29 @@
         never: true,
     },
 }
+
+cc_library_headers {
+    name: "libandroid_runtime_vm_headers",
+    host_supported: true,
+    vendor_available: true,
+    // TODO(b/153609531): remove when libbinder is not native_bridge_supported
+    native_bridge_supported: true,
+    // Allow only modules from the following list to create threads that can be
+    // attached to the JVM. This list should be a subset of the dependencies of
+    // libandroid_runtime.
+    visibility: [
+        "//frameworks/native/libs/binder",
+    ],
+    export_include_dirs: ["include_vm"],
+    header_libs: [
+        "jni_headers",
+    ],
+    export_header_lib_headers: [
+        "jni_headers",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 406ccde..09d7ef0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -22,6 +22,7 @@
 #include <android-base/properties.h>
 #include <android/graphics/jni_runtime.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/vm.h>
 #include <assert.h>
 #include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
@@ -1331,6 +1332,10 @@
     return AndroidRuntime::mJavaVM;
 }
 
+extern "C" JavaVM* AndroidRuntimeGetJavaVM() {
+    return AndroidRuntime::getJavaVM();
+}
+
 /*
  * Get the JNIEnv pointer for this thread.
  *
diff --git a/core/jni/include_vm/android_runtime/vm.h b/core/jni/include_vm/android_runtime/vm.h
new file mode 100644
index 0000000..a6e7c16
--- /dev/null
+++ b/core/jni/include_vm/android_runtime/vm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <jni.h>
+
+// Get the Java VM. If the symbol doesn't exist at runtime, it means libandroid_runtime
+// is not loaded in the current process. If the symbol exists but it returns nullptr, it
+// means JavaVM is not yet started.
+extern "C" JavaVM* AndroidRuntimeGetJavaVM();
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index 2faff41..eec49fe 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -27,7 +27,6 @@
         android:id="@+id/conversation_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
         android:textSize="16sp"
         android:singleLine="true"
@@ -40,7 +39,6 @@
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
         android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
-        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
         android:text="@string/notification_header_divider_symbol"
         android:singleLine="true"
         android:visibility="gone"
@@ -53,7 +51,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
-        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
         android:singleLine="true"
         android:visibility="gone"
         />
@@ -64,7 +61,6 @@
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
         android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
-        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
         android:text="@string/notification_header_divider_symbol"
         android:singleLine="true"
         android:visibility="gone"
@@ -96,7 +92,6 @@
         android:layout_height="wrap_content"
         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
         android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
-        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
         android:text="@string/notification_header_divider_symbol"
         android:singleLine="true"
         android:visibility="gone"
@@ -106,7 +101,7 @@
         android:id="@+id/verification_icon"
         android:layout_width="@dimen/notification_verification_icon_size"
         android:layout_height="@dimen/notification_verification_icon_size"
-        android:layout_marginStart="4dp"
+        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
         android:baseline="10dp"
         android:scaleType="fitCenter"
         android:src="@drawable/ic_notifications_alerted"
@@ -142,7 +137,7 @@
         android:id="@+id/phishing_alert"
         android:layout_width="@dimen/notification_phishing_alert_size"
         android:layout_height="@dimen/notification_phishing_alert_size"
-        android:layout_marginStart="4dp"
+        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
         android:baseline="10dp"
         android:scaleType="fitCenter"
         android:src="@drawable/ic_dialog_alert_material"
@@ -154,7 +149,7 @@
         android:id="@+id/profile_badge"
         android:layout_width="@dimen/notification_badge_size"
         android:layout_height="@dimen/notification_badge_size"
-        android:layout_marginStart="4dp"
+        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
         android:baseline="10dp"
         android:scaleType="fitCenter"
         android:visibility="gone"
@@ -165,7 +160,7 @@
         android:id="@+id/alerted_icon"
         android:layout_width="@dimen/notification_alerted_size"
         android:layout_height="@dimen/notification_alerted_size"
-        android:layout_marginStart="4dp"
+        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
         android:baseline="10dp"
         android:contentDescription="@string/notification_alerted_content_description"
         android:scaleType="fitCenter"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b50ff80..9433a71 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4408,14 +4408,14 @@
         M9,10l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z
     </string>
 
-    <!-- X path for SignalDrawable as defined on a 24x24 canvas. -->
-    <string name="config_signalXPath" translatable="false">
-        M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09-2.08L20.59,22L22,20.59l-2.08-2.09   L22,16.41z
+    <!-- Attribution path for SignalDrawable as defined on a 24x24 canvas. -->
+    <string name="config_signalAttributionPath" translatable="false">
+        M20,10h2v8h-2z M20,20h2v2h-2z
     </string>
     <!-- config_signalCutout{Height,Width}Fraction define fraction of the 24x24 canvas that
-         should be cut out to display config_signalXPath.-->
-    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">11</item>
-    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">11</item>
+         should be cut out to display config_signalAttributionPath. -->
+    <item name="config_signalCutoutWidthFraction" format="float" type="dimen">7</item>
+    <item name="config_signalCutoutHeightFraction" format="float" type="dimen">17</item>
 
     <!-- A dual tone battery meter draws the perimeter path twice - once to define the shape
      and a second time clipped to the fill level to indicate charge -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a940ef3..70bbc35 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3370,7 +3370,7 @@
   <java-symbol type="string" name="config_batterymeterBoltPath" />
   <java-symbol type="string" name="config_batterymeterPowersavePath" />
   <java-symbol type="bool" name="config_batterymeterDualTone" />
-  <java-symbol type="string" name="config_signalXPath" />
+  <java-symbol type="string" name="config_signalAttributionPath" />
   <java-symbol type="dimen" name="config_signalCutoutWidthFraction" />
   <java-symbol type="dimen" name="config_signalCutoutHeightFraction" />
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index f3f66dc..28e2f7dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -906,8 +906,7 @@
      * Fills the overflow bubbles by loading them from disk.
      */
     void loadOverflowBubblesFromDisk() {
-        if (!mBubbleData.getOverflowBubbles().isEmpty() && !mOverflowDataLoadNeeded) {
-            // we don't need to load overflow bubbles from disk if it is already in memory
+        if (!mOverflowDataLoadNeeded) {
             return;
         }
         mOverflowDataLoadNeeded = false;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index f701491..9e8a1e1 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -579,7 +579,9 @@
         std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
         mQueueWaitIdle(mGraphicsQueue);
     }
-    destroy_semaphore(mDestroySemaphoreContext);
+    if (mDestroySemaphoreContext) {
+        destroy_semaphore(mDestroySemaphoreContext);
+    }
 
     surface->presentCurrentBuffer(dirtyRect, fenceFd);
     mSwapSemaphore = VK_NULL_HANDLE;
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index 472e0a4..03dd707 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -77,7 +77,18 @@
              const uirenderer::DrawGlInfo& draw_gl_params,
              const uirenderer::WebViewOverlayData& overlay_params) {
   float gabcdef[7];
-  draw_gl_params.color_space_ptr->transferFn(gabcdef);
+  if (draw_gl_params.color_space_ptr) {
+      draw_gl_params.color_space_ptr->transferFn(gabcdef);
+  } else {
+      // Assume sRGB.
+      gabcdef[0] = SkNamedTransferFn::kSRGB.g;
+      gabcdef[1] = SkNamedTransferFn::kSRGB.a;
+      gabcdef[2] = SkNamedTransferFn::kSRGB.b;
+      gabcdef[3] = SkNamedTransferFn::kSRGB.c;
+      gabcdef[4] = SkNamedTransferFn::kSRGB.d;
+      gabcdef[5] = SkNamedTransferFn::kSRGB.e;
+      gabcdef[6] = SkNamedTransferFn::kSRGB.f;
+  }
   AwDrawFn_DrawGLParams params = {
       .version = kAwDrawFnVersion,
       .clip_left = draw_gl_params.clipLeft,
@@ -147,7 +158,18 @@
             const uirenderer::WebViewOverlayData& overlay_params) {
   SupportData* support = static_cast<SupportData*>(data);
   float gabcdef[7];
-  draw_vk_params.color_space_ptr->transferFn(gabcdef);
+  if (draw_vk_params.color_space_ptr) {
+      draw_vk_params.color_space_ptr->transferFn(gabcdef);
+  } else {
+      // Assume sRGB.
+      gabcdef[0] = SkNamedTransferFn::kSRGB.g;
+      gabcdef[1] = SkNamedTransferFn::kSRGB.a;
+      gabcdef[2] = SkNamedTransferFn::kSRGB.b;
+      gabcdef[3] = SkNamedTransferFn::kSRGB.c;
+      gabcdef[4] = SkNamedTransferFn::kSRGB.d;
+      gabcdef[5] = SkNamedTransferFn::kSRGB.e;
+      gabcdef[6] = SkNamedTransferFn::kSRGB.f;
+  }
   AwDrawFn_DrawVkParams params{
       .version = kAwDrawFnVersion,
       .width = draw_vk_params.width,
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 3814ed5..f2ab2f8 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -452,7 +452,7 @@
     <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"ថេប្លេត​អាចនឹង​បិទក្នុង​ពេលបន្តិច​ទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"ឧបករណ៍​អាចនឹង​បិទក្នុង​ពេលបន្តិច​ទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"នៅសល់ <xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
+    <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានដាក់កម្រិត​ការសាកថ្ម​ជាបណ្ដោះអាសន្ន"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index ea67165..864f177 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -452,13 +452,13 @@
     <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"टॅबलेट लवकरच बंद होऊ शकतो (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"डिव्हाइस लवकरच बंद होऊ शकते (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहे"</string>
+    <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहेत"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%2$s</xliff:g> शिल्लक आहे"</string>
     <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • चार्जिंग तात्पुरते मर्यादित आहे"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
-    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळूहळू चार्ज होत आहे"</string>
+    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळू चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट केले, चार्ज होत नाही"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 0397eb8..bb94c24 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -458,7 +458,7 @@
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
-    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"बिस्तारै चार्ज गरिँदै"</string>
+    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ढिलो चार्ज हुँदै छ"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट गरिएको छ, चार्ज भइरहेको छैन"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index aecfd62..cf6013f 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -458,7 +458,7 @@
     <string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
-    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہا ہے"</string>
+    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہی ہے"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"وائرلیس طریقے سے چارج ہو رہی ہے"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"چارج نہیں ہو رہا ہے"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"منسلک ہے، چارج نہیں ہو رہی ہے"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 970efa6..400973b 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -170,7 +170,7 @@
     <item msgid="3691785423374588514">"1M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="409235464399258501">"关闭"</item>
+    <item msgid="409235464399258501">"已关闭"</item>
     <item msgid="4195153527464162486">"每个日志缓冲区 64K"</item>
     <item msgid="7464037639415220106">"每个日志缓冲区 256K"</item>
     <item msgid="8539423820514360724">"每个日志缓冲区 1M"</item>
@@ -184,7 +184,7 @@
     <item msgid="7300881231043255746">"仅限内核"</item>
   </string-array>
   <string-array name="select_logpersist_summaries">
-    <item msgid="97587758561106269">"关闭"</item>
+    <item msgid="97587758561106269">"已关闭"</item>
     <item msgid="7126170197336963369">"所有日志缓冲区"</item>
     <item msgid="7167543126036181392">"所有非无线电日志缓冲区"</item>
     <item msgid="5135340178556563979">"仅限内核日志缓冲区"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index ac49b99..e991451 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -276,7 +276,7 @@
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"正在流式传输:<xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"私人 DNS"</string>
     <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"选择私人 DNS 模式"</string>
-    <string name="private_dns_mode_off" msgid="7065962499349997041">"关闭"</string>
+    <string name="private_dns_mode_off" msgid="7065962499349997041">"已关闭"</string>
     <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"自动"</string>
     <string name="private_dns_mode_provider" msgid="3619040641762557028">"私人 DNS 提供商主机名"</string>
     <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"输入 DNS 提供商的主机名"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index c3caa6d..6d8a0b0 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -458,7 +458,7 @@
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
-    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"正在慢速充電"</string>
+    <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,非充電中"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 3b41fa9..4d0804e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -72,9 +72,9 @@
     private final int mLightModeFillColor;
     private final Path mCutoutPath = new Path();
     private final Path mForegroundPath = new Path();
-    private final Path mXPath = new Path();
-    private final Matrix mXScaleMatrix = new Matrix();
-    private final Path mScaledXPath = new Path();
+    private final Path mAttributionPath = new Path();
+    private final Matrix mAttributionScaleMatrix = new Matrix();
+    private final Path mScaledAttributionPath = new Path();
     private final Handler mHandler;
     private final float mCutoutWidthFraction;
     private final float mCutoutHeightFraction;
@@ -85,10 +85,10 @@
 
     public SignalDrawable(Context context) {
         super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular));
-        final String xPathString = context.getString(
-                com.android.internal.R.string.config_signalXPath);
-        mXPath.set(PathParser.createPathFromPathData(xPathString));
-        updateScaledXPath();
+        final String attributionPathString = context.getString(
+                com.android.internal.R.string.config_signalAttributionPath);
+        mAttributionPath.set(PathParser.createPathFromPathData(attributionPathString));
+        updateScaledAttributionPath();
         mCutoutWidthFraction = context.getResources().getFloat(
                 com.android.internal.R.dimen.config_signalCutoutWidthFraction);
         mCutoutHeightFraction = context.getResources().getFloat(
@@ -104,13 +104,14 @@
         setDarkIntensity(0);
     }
 
-    private void updateScaledXPath() {
+    private void updateScaledAttributionPath() {
         if (getBounds().isEmpty()) {
-            mXScaleMatrix.setScale(1f, 1f);
+            mAttributionScaleMatrix.setScale(1f, 1f);
         } else {
-            mXScaleMatrix.setScale(getBounds().width() / VIEWPORT, getBounds().height() / VIEWPORT);
+            mAttributionScaleMatrix.setScale(
+                    getBounds().width() / VIEWPORT, getBounds().height() / VIEWPORT);
         }
-        mXPath.transform(mXScaleMatrix, mScaledXPath);
+        mAttributionPath.transform(mAttributionScaleMatrix, mScaledAttributionPath);
     }
 
     @Override
@@ -177,7 +178,7 @@
     @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
-        updateScaledXPath();
+        updateScaledAttributionPath();
         invalidateSelf();
     }
 
@@ -221,7 +222,7 @@
             mCutoutPath.rLineTo(cutX, 0);
             mCutoutPath.rLineTo(0, cutY);
             canvas.drawPath(mCutoutPath, mTransparentPaint);
-            canvas.drawPath(mScaledXPath, mForegroundPaint);
+            canvas.drawPath(mScaledAttributionPath, mForegroundPaint);
         }
         if (isRtl) {
             canvas.restore();
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 34bf28a..ee0e4b3 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -32,11 +32,11 @@
     -->
     <dimen name="qs_customize_header_min_height">48dp</dimen>
 
+    <!--  In landscape the security footer is actually part of the header,
+    and needs to be as short as the header  -->
     <dimen name="qs_security_footer_single_line_height">@*android:dimen/quick_qs_offset_height</dimen>
     <dimen name="qs_footer_padding">14dp</dimen>
-    <dimen name="qs_footers_margin_bottom">0dp</dimen>
     <dimen name="qs_security_footer_background_inset">12dp</dimen>
-    <dimen name="qs_security_footer_corner_radius">28dp</dimen>
 
     <dimen name="battery_detail_graph_space_top">9dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index e2b2e25..369e45c 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,6 +18,10 @@
     <!-- Max number of columns for quick controls area -->
     <integer name="controls_max_columns">2</integer>
 
+    <integer name="quick_settings_num_columns">2</integer>
+    <integer name="quick_qs_panel_max_rows">4</integer>
+    <integer name="quick_qs_panel_max_tiles">8</integer>
+
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 2f5e8ea..942cb2b 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -38,4 +38,6 @@
     <!-- Max number of columns for quick controls area -->
     <integer name="controls_max_columns">4</integer>
 
+    <!-- How many lines to show in the security footer -->
+    <integer name="qs_security_footer_maxLines">1</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index da80b85..527537b 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -95,4 +95,9 @@
     <dimen name="controls_top_margin">24dp</dimen>
 
     <dimen name="global_actions_grid_item_layout_height">80dp</dimen>
+
+    <!--  For large screens the security footer appears below the footer,
+    same as phones in portrait  -->
+    <dimen name="qs_security_footer_single_line_height">48dp</dimen>
+    <dimen name="qs_security_footer_background_inset">0dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d722866..bf29cf4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -86,7 +86,10 @@
     <bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">true</bool>
 
     <!-- The maximum number of tiles in the QuickQSPanel -->
-    <integer name="quick_qs_panel_max_columns">4</integer>
+    <integer name="quick_qs_panel_max_tiles">4</integer>
+
+    <!-- The maximum number of rows in the QuickQSPanel -->
+    <integer name="quick_qs_panel_max_rows">2</integer>
 
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">2</integer>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 933a919..92f8454 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -27,6 +27,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
+import android.view.WindowInsets;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -227,12 +228,16 @@
                 super.onPause();
             });
         }
-        mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
+        if (mPasswordEntry.isAttachedToWindow()) {
+            mPasswordEntry.getWindowInsetsController().hide(WindowInsets.Type.ime());
+        }
     }
 
     @Override
     public void onStartingToHide() {
-        mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
+        if (mPasswordEntry.isAttachedToWindow()) {
+            mPasswordEntry.getWindowInsetsController().hide(WindowInsets.Type.ime());
+        }
     }
 
     private void updateSwitchImeButton() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 672e2e6..e315e11 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1428,32 +1428,42 @@
     final FaceManager.AuthenticationCallback mFaceAuthenticationCallback
             = new FaceManager.AuthenticationCallback() {
 
-        @Override
-        public void onAuthenticationFailed() {
-            handleFaceAuthFailed();
-        }
+                @Override
+                public void onAuthenticationFailed() {
+                    handleFaceAuthFailed();
+                    if (mKeyguardBypassController != null) {
+                        mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
+                    }
+                }
 
-        @Override
-        public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
-            Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
-            handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
-            Trace.endSection();
-        }
+                @Override
+                public void onAuthenticationSucceeded(FaceManager.AuthenticationResult result) {
+                    Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationSucceeded");
+                    handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
+                    Trace.endSection();
 
-        @Override
-        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
-            handleFaceHelp(helpMsgId, helpString.toString());
-        }
+                    if (mKeyguardBypassController != null) {
+                        mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
+                    }
+                }
 
-        @Override
-        public void onAuthenticationError(int errMsgId, CharSequence errString) {
-            handleFaceError(errMsgId, errString.toString());
-        }
+                @Override
+                public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                    handleFaceHelp(helpMsgId, helpString.toString());
+                }
 
-        @Override
-        public void onAuthenticationAcquired(int acquireInfo) {
-            handleFaceAcquired(acquireInfo);
-        }
+                @Override
+                public void onAuthenticationError(int errMsgId, CharSequence errString) {
+                    handleFaceError(errMsgId, errString.toString());
+                    if (mKeyguardBypassController != null) {
+                        mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
+                    }
+                }
+
+                @Override
+                public void onAuthenticationAcquired(int acquireInfo) {
+                    handleFaceAcquired(acquireInfo);
+                }
     };
 
     private CancellationSignal mFingerprintCancelSignal;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 373d4df..5957be3 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -93,6 +93,7 @@
     @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon;
     @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon;
     @NonNull private final Drawable mLockIcon;
+    @NonNull private final Drawable mUnlockIcon;
     @NonNull private final CharSequence mUnlockedLabel;
     @NonNull private final CharSequence mLockedLabel;
     @Nullable private final Vibrator mVibrator;
@@ -148,6 +149,10 @@
         mVibrator = vibrator;
 
         final Context context = view.getContext();
+        mUnlockIcon = mView.getContext().getResources().getDrawable(
+            R.anim.lock_to_unlock,
+            mView.getContext().getTheme());
+        ((AnimatedVectorDrawable) mUnlockIcon).start();
         mLockIcon = mView.getContext().getResources().getDrawable(
                 R.anim.lock_to_unlock,
                 mView.getContext().getTheme());
@@ -227,8 +232,9 @@
             return;
         }
 
-        boolean wasShowingFpIcon = mHasUdfps && !mShowUnlockIcon && !mShowLockIcon;
+        boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon;
         boolean wasShowingLockIcon = mShowLockIcon;
+        boolean wasShowingUnlockIcon = mShowUnlockIcon;
         mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
             && (!mUdfpsEnrolled || !mRunningFPS);
         mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
@@ -239,14 +245,18 @@
             mView.setVisibility(View.VISIBLE);
             mView.setContentDescription(mLockedLabel);
         } else if (mShowUnlockIcon) {
-            if (wasShowingFpIcon) {
-                mView.setImageDrawable(mFpToUnlockIcon);
-                mFpToUnlockIcon.forceAnimationOnUI();
-                mFpToUnlockIcon.start();
-            } else if (wasShowingLockIcon) {
-                mView.setImageDrawable(mLockToUnlockIcon);
-                mLockToUnlockIcon.forceAnimationOnUI();
-                mLockToUnlockIcon.start();
+            if (!wasShowingUnlockIcon) {
+                if (wasShowingFpIcon) {
+                    mView.setImageDrawable(mFpToUnlockIcon);
+                    mFpToUnlockIcon.forceAnimationOnUI();
+                    mFpToUnlockIcon.start();
+                } else if (wasShowingLockIcon) {
+                    mView.setImageDrawable(mLockToUnlockIcon);
+                    mLockToUnlockIcon.forceAnimationOnUI();
+                    mLockToUnlockIcon.start();
+                } else {
+                    mView.setImageDrawable(mUnlockIcon);
+                }
             }
             mView.setVisibility(View.VISIBLE);
             mView.setContentDescription(mUnlockedLabel);
@@ -300,6 +310,7 @@
         mFpToUnlockIcon.setTint(color);
         mLockToUnlockIcon.setTint(color);
         mLockIcon.setTint(color);
+        mUnlockIcon.setTint(color);
     }
 
     private void updateConfiguration() {
@@ -427,7 +438,16 @@
 
         @Override
         public void onKeyguardShowingChanged() {
+            // Reset values in case biometrics were removed (ie: pin/pattern/password => swipe).
+            // If biometrics were removed, local vars mCanDismissLockScreen and
+            // mUserUnlockedWithBiometric may not be updated.
+            mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
             updateKeyguardShowing();
+            if (mIsKeyguardShowing) {
+                mUserUnlockedWithBiometric =
+                    mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
+                        KeyguardUpdateMonitor.getCurrentUser());
+            }
             mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
             updateVisibility();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 65c3847..cf3c31a 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -140,6 +140,7 @@
 
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.inject.Provider;
 
 import dagger.Lazy;
 
@@ -199,6 +200,12 @@
     public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress";
 
     /**
+     * A provider of {@link EdgeBackGestureHandler}.
+     */
+    public static final String EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME =
+            "edge_back_gesture_handler_provider";
+
+    /**
      * Key for getting a background Looper for background work.
      */
     public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME);
@@ -233,6 +240,12 @@
      */
     public static final DependencyKey<String> LEAK_REPORT_EMAIL =
             new DependencyKey<>(LEAK_REPORT_EMAIL_NAME);
+    /**
+     * Key for retrieving an Provider<EdgeBackGestureHandler>.
+     */
+    public static final DependencyKey<Provider<EdgeBackGestureHandler>>
+            EDGE_BACK_GESTURE_HANDLER_PROVIDER =
+            new DependencyKey<>(EDGE_BACK_GESTURE_HANDLER_PROVIDER_NAME);
 
     private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
     private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();
@@ -358,7 +371,7 @@
     @Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
     @Inject Lazy<SystemStatusAnimationScheduler> mSystemStatusAnimationSchedulerLazy;
     @Inject Lazy<PrivacyDotViewController> mPrivacyDotViewControllerLazy;
-    @Inject Lazy<EdgeBackGestureHandler> mEdgeBackGestureHandler;
+    @Inject Provider<EdgeBackGestureHandler> mEdgeBackGestureHandlerProvider;
     @Inject Lazy<UiEventLogger> mUiEventLogger;
     @Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
     @Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
@@ -573,8 +586,8 @@
         mProviders.put(SystemStatusAnimationScheduler.class,
                 mSystemStatusAnimationSchedulerLazy::get);
         mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
-        mProviders.put(EdgeBackGestureHandler.class, mEdgeBackGestureHandler::get);
         mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get);
+        mProviders.put(EDGE_BACK_GESTURE_HANDLER_PROVIDER, () -> mEdgeBackGestureHandlerProvider);
         mProviders.put(UiEventLogger.class, mUiEventLogger::get);
         mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 59d8cd0..aafacd6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -68,6 +68,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -120,6 +121,7 @@
     @NonNull private final AccessibilityManager mAccessibilityManager;
     @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Nullable private final UdfpsHbmProvider mHbmProvider;
+    @NonNull private final KeyguardBypassController mKeyguardBypassController;
     @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
@@ -397,7 +399,10 @@
                     handled = true;
                 }
                 if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
-                    Log.v(TAG, "onTouch | dismiss keyguard from ACTION_DOWN");
+                    Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN");
+                    if (!mOnFingerDown) {
+                        playStartHaptic();
+                    }
                     mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
                     mAttemptedToDismissKeyguard = true;
                 }
@@ -414,6 +419,16 @@
                     boolean actionMoveWithinSensorArea =
                             isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
                                 fromUdfpsView);
+                    if ((fromUdfpsView || actionMoveWithinSensorArea)
+                            && shouldTryToDismissKeyguard()) {
+                        Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE");
+                        if (!mOnFingerDown) {
+                            playStartHaptic();
+                        }
+                        mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+                        mAttemptedToDismissKeyguard = true;
+                        break;
+                    }
                     if (actionMoveWithinSensorArea) {
                         if (mVelocityTracker == null) {
                             // touches could be injected, so the velocity tracker may not have
@@ -449,12 +464,6 @@
                         Log.v(TAG, "onTouch | finger outside");
                         onFingerUp();
                     }
-                    if ((fromUdfpsView || actionMoveWithinSensorArea)
-                            && shouldTryToDismissKeyguard()) {
-                        Log.v(TAG, "onTouch | dismiss keyguard from ACTION_MOVE");
-                        mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
-                        mAttemptedToDismissKeyguard = true;
-                    }
                 }
                 Trace.endSection();
                 break;
@@ -509,7 +518,8 @@
             @Nullable Vibrator vibrator,
             @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
             @NonNull Optional<UdfpsHbmProvider> hbmProvider,
-            @NonNull KeyguardStateController keyguardStateController) {
+            @NonNull KeyguardStateController keyguardStateController,
+            @NonNull KeyguardBypassController keyguardBypassController) {
         mContext = context;
         mExecution = execution;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -539,6 +549,7 @@
             onOrientationChanged();
             return Unit.INSTANCE;
         });
+        mKeyguardBypassController = keyguardBypassController;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -863,12 +874,17 @@
 
     private void onFingerDown(int x, int y, float minor, float major) {
         mExecution.assertIsMainThread();
+        mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
         if (mView == null) {
             Log.w(TAG, "Null view in onFingerDown");
             return;
         }
         if (!mOnFingerDown) {
             playStartHaptic();
+
+            if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
+                mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false);
+            }
         }
         mOnFingerDown = true;
         mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 412b776..6a918a6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -21,11 +21,8 @@
 import android.content.Context;
 import android.graphics.PointF;
 import android.hardware.fingerprint.IUdfpsOverlayController;
-import android.media.AudioAttributes;
 import android.os.Build;
 import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.TypedValue;
@@ -50,12 +47,6 @@
     // Enroll with two center touches before going to guided enrollment
     private static final int NUM_CENTER_TOUCHES = 2;
 
-    private static final AudioAttributes VIBRATION_SONFICATION_ATTRIBUTES =
-            new AudioAttributes.Builder()
-                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                    .build();
-
     interface Listener {
         void onEnrollmentProgress(int remaining, int totalSteps);
         void onLastStepAcquired();
@@ -66,9 +57,6 @@
     private final int mEnrollReason;
     private final boolean mAccessibilityEnabled;
     @NonNull private final List<PointF> mGuidedEnrollmentPoints;
-    @NonNull private final Vibrator mVibrator;
-    @NonNull private final VibrationEffect mEffectClick =
-            VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
 
     private int mTotalSteps = -1;
     private int mRemainingSteps = -1;
@@ -82,7 +70,6 @@
     public UdfpsEnrollHelper(@NonNull Context context, int reason) {
         mContext = context;
         mEnrollReason = reason;
-        mVibrator = context.getSystemService(Vibrator.class);
 
         final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
         mAccessibilityEnabled = am.isEnabled();
@@ -141,7 +128,6 @@
 
         if (remaining != mRemainingSteps) {
             mLocationsEnrolled++;
-            vibrateSuccess();
         }
 
         mRemainingSteps = remaining;
@@ -202,11 +188,6 @@
 
         if (mRemainingSteps <= 2 && mRemainingSteps >= 0) {
             mListener.onLastStepAcquired();
-            vibrateSuccess();
         }
     }
-
-    private void vibrateSuccess() {
-        mVibrator.vibrate(mEffectClick, VIBRATION_SONFICATION_ATTRIBUTES);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 23c066a..0d91f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -18,6 +18,7 @@
 
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -352,7 +353,7 @@
 
         mNavColorSampleMargin = getResources()
                         .getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
-        mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.class);
+        mEdgeBackGestureHandler = Dependency.get(EDGE_BACK_GESTURE_HANDLER_PROVIDER).get();
         mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates);
         mRegionSamplingHelper = new RegionSamplingHelper(this,
                 new RegionSamplingHelper.SamplingCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index ff5d0b1..48d2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -58,7 +58,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarView;
@@ -92,7 +91,6 @@
 /**
  * Utility class to handle edge swipes for back gesture
  */
-@SysUISingleton
 public class EdgeBackGestureHandler extends CurrentUserTracker
         implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> {
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7c7f566..f20a2db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -42,7 +42,6 @@
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.animation.UniqueObjectHostView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -316,7 +315,6 @@
         super.onConfigurationChanged(newConfig);
         mOnConfigurationChangedListeners.forEach(
                 listener -> listener.onConfigurationChange(newConfig));
-        switchSecurityFooter();
     }
 
     @Override
@@ -359,25 +357,21 @@
             switchToParent(mFooter, parent, index);
             index++;
         }
-
-        // The security footer is switched on orientation changes
     }
 
-    private void switchSecurityFooter() {
-        if (mSecurityFooter != null) {
-            if (mContext.getResources().getConfiguration().orientation
-                    == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null) {
-                // Adding the security view to the header, that enables us to avoid scrolling
-                switchToParent(mSecurityFooter, mHeaderContainer, 0);
-            } else {
-                // Where should this go? If there's media, right before it. Otherwise, at the end.
-                View mediaView = findViewByPredicate(v -> v instanceof UniqueObjectHostView);
-                int index = -1;
-                if (mediaView != null) {
-                    index = indexOfChild(mediaView);
-                }
-                switchToParent(mSecurityFooter, this, index);
-            }
+    /** Switch the security footer between top and bottom of QS depending on orientation. */
+    public void switchSecurityFooter(boolean shouldUseSplitNotificationShade) {
+        if (mSecurityFooter == null) return;
+
+        if (!shouldUseSplitNotificationShade
+                && mContext.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE && mHeaderContainer != null) {
+            // Adding the security view to the header, that enables us to avoid scrolling
+            switchToParent(mSecurityFooter, mHeaderContainer, 0);
+        } else {
+            // Add after the footer
+            int index = indexOfChild(mFooter);
+            switchToParent(mSecurityFooter, this, index + 1);
         }
     }
 
@@ -652,9 +646,14 @@
         return mListening;
     }
 
-    public void setSecurityFooter(View view) {
+    /**
+     * Set the security footer view and switch it into the right place
+     * @param view the view in question
+     * @param shouldUseSplitNotificationShade if QS is in split shade mode
+     */
+    public void setSecurityFooter(View view, boolean shouldUseSplitNotificationShade) {
         mSecurityFooter = view;
-        switchSecurityFooter();
+        switchSecurityFooter(shouldUseSplitNotificationShade);
     }
 
     protected void setPageMargin(int pageMargin) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index ae0f510..7cbd45b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -77,6 +77,7 @@
                 refreshAllTiles();
             }
             updateBrightnessMirror();
+            mView.switchSecurityFooter(mShouldUseSplitNotificationShade);
         }
     };
 
@@ -141,7 +142,7 @@
             refreshAllTiles();
         }
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
-        mView.setSecurityFooter(mQsSecurityFooter.getView());
+        mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
         switchTileLayout(true);
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 4739a3f..64ef5cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -69,7 +69,7 @@
     private final DumpManager mDumpManager;
     private final FeatureFlags mFeatureFlags;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
-    private boolean mShouldUseSplitNotificationShade;
+    protected boolean mShouldUseSplitNotificationShade;
 
     @Nullable
     private Consumer<Boolean> mMediaVisibilityChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 4cd4048..e3c241c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -33,18 +33,16 @@
  */
 public class QuickQSPanel extends QSPanel {
 
-    public static final String NUM_QUICK_TILES = "sysui_qqs_count";
     private static final String TAG = "QuickQSPanel";
-    // A default value so that we never return 0.
-    public static final int DEFAULT_MAX_TILES = 6;
+    // A fallback value for max tiles number when setting via Tuner (parseNumTiles)
+    public static final int TUNER_MAX_TILES_FALLBACK = 6;
 
     private boolean mDisabledByPolicy;
     private int mMaxTiles;
 
     public QuickQSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mMaxTiles = Math.min(DEFAULT_MAX_TILES,
-                getResources().getInteger(R.integer.quick_qs_panel_max_columns));
+        mMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles);
     }
 
     @Override
@@ -101,7 +99,7 @@
     }
 
     public void setMaxTiles(int maxTiles) {
-        mMaxTiles = Math.min(maxTiles, DEFAULT_MAX_TILES);
+        mMaxTiles = maxTiles;
     }
 
     @Override
@@ -117,17 +115,18 @@
     }
 
     /**
-     * Parses the String setting into the number of tiles. Defaults to {@code mDefaultMaxTiles}
+     * Parses the String setting into the number of tiles. Defaults to
+     * {@link #TUNER_MAX_TILES_FALLBACK}
      *
      * @param numTilesValue value of the setting to parse
-     * @return parsed value of numTilesValue OR {@code mDefaultMaxTiles} on error
+     * @return parsed value of numTilesValue OR {@link #TUNER_MAX_TILES_FALLBACK} on error
      */
     public static int parseNumTiles(String numTilesValue) {
         try {
             return Integer.parseInt(numTilesValue);
         } catch (NumberFormatException e) {
             // Couldn't read an int from the new setting value. Use default.
-            return DEFAULT_MAX_TILES;
+            return TUNER_MAX_TILES_FALLBACK;
         }
     }
 
@@ -187,7 +186,7 @@
         public boolean updateResources() {
             mCellHeightResId = R.dimen.qs_quick_tile_size;
             boolean b = super.updateResources();
-            mMaxAllowedRows = 2;
+            mMaxAllowedRows = getResources().getInteger(R.integer.quick_qs_panel_max_rows);
             return b;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index fee56b9..d75b0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -43,7 +43,7 @@
 
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             newConfig -> {
-                int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+                int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles);
                 if (newMaxTiles != mView.getNumQuickTiles()) {
                     setMaxTiles(newMaxTiles);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 6d5c536..6e201048 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -564,8 +564,8 @@
         boolean unlockingAllowed =
                 mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
         boolean deviceDreaming = mUpdateMonitor.isDreaming();
-        boolean bypass = mKeyguardBypassController.getBypassEnabled();
-
+        boolean bypass = mKeyguardBypassController.getBypassEnabled()
+                || mKeyguardBypassController.getUserHasDeviceEntryIntent();
         if (!mUpdateMonitor.isDeviceInteractive()) {
             if (!mKeyguardViewController.isShowing()) {
                 return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 99df3f1..6caeba2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -44,6 +44,7 @@
     private var hasFaceFeature: Boolean
     private var pendingUnlock: PendingUnlock? = null
     private val listeners = mutableListOf<OnBypassStateChangedListener>()
+    var userHasDeviceEntryIntent: Boolean = false // ie: attempted udfps auth
 
     private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
         override fun onFaceAuthEnabledChanged() = notifyListeners()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index cdb5212..8d6e1d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -59,6 +59,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -136,6 +137,8 @@
     private UdfpsHapticsSimulator mUdfpsHapticsSimulator;
     @Mock
     private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
 
     private FakeExecutor mFgExecutor;
 
@@ -204,7 +207,8 @@
                 mVibrator,
                 mUdfpsHapticsSimulator,
                 Optional.of(mHbmProvider),
-                mKeyguardStateController);
+                mKeyguardStateController,
+                mKeyguardBypassController);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
index 0eeb955..d25b3e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
@@ -16,8 +16,11 @@
 
 package com.android.systemui.navigationbar;
 
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
+
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
 import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
@@ -68,7 +71,8 @@
         mDependency.injectMockDependency(OverviewProxyService.class);
         mDependency.injectMockDependency(KeyguardStateController.class);
         mDependency.injectMockDependency(NavigationBarController.class);
-        mDependency.injectMockDependency(EdgeBackGestureHandler.class);
+        mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
+                () -> mock(EdgeBackGestureHandler.class));
         mNavBar = new NavigationBarView(context, null);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 92cd244..df502f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -24,6 +24,7 @@
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
 import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
 
 import static org.junit.Assert.assertEquals;
@@ -135,7 +136,8 @@
         mDependency.injectMockDependency(StatusBarStateController.class);
         mDependency.injectMockDependency(NavigationBarController.class);
         mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class);
-        mDependency.injectMockDependency(EdgeBackGestureHandler.class);
+        mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
+                () -> mock(EdgeBackGestureHandler.class));
         TestableLooper.get(this).runWithLooper(() -> {
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index e4d32f4..62871dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.navigationbar;
 
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -58,7 +60,8 @@
         mDependency.injectMockDependency(StatusBarStateController.class);
         mDependency.injectMockDependency(KeyguardStateController.class);
         mDependency.injectMockDependency(NavigationBarController.class);
-        mDependency.injectMockDependency(EdgeBackGestureHandler.class);
+        mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
+                () -> mock(EdgeBackGestureHandler.class));
         doReturn(mContext)
                 .when(mDependency.injectMockDependency(NavigationModeController.class))
                 .getCurrentUserContext();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
index d56aa77..671b1be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.navigationbar.buttons;
 
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -38,6 +40,7 @@
 import com.android.systemui.navigationbar.buttons.ContextualButton;
 import com.android.systemui.navigationbar.buttons.ContextualButtonGroup;
 import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -65,6 +68,8 @@
     @Before
     public void setup() {
         mDependency.injectMockDependency(AssistManager.class);
+        mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
+                () -> mock(EdgeBackGestureHandler.class));
 
         mGroup = new ContextualButtonGroup(GROUP_ID);
         mBtn0 = new ContextualButton(BUTTON_0_ID, mContext, ICON_RES_ID);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
index c8f223b..2ab2c94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
@@ -16,10 +16,13 @@
 
 package com.android.systemui.navigationbar.buttons;
 
+import static com.android.systemui.Dependency.EDGE_BACK_GESTURE_HANDLER_PROVIDER;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -36,6 +39,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.navigationbar.buttons.NearestTouchFrame;
+import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -52,6 +56,8 @@
 
     @Before
     public void setup() {
+        mDependency.injectTestDependency(EDGE_BACK_GESTURE_HANDLER_PROVIDER,
+                () -> mock(EdgeBackGestureHandler.class));
         Configuration c = new Configuration(mContext.getResources().getConfiguration());
         c.smallestScreenWidthDp = 500;
         mNearestTouchFrame = new NearestTouchFrame(mContext, null, c);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
deleted file mode 100644
index 4f88599..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.qs;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Collections;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class QSPanelTest extends SysuiTestCase {
-
-    private TestableLooper mTestableLooper;
-    private QSPanel mQsPanel;
-    @Mock
-    private QSTileHost mHost;
-    @Mock
-    private QSTileImpl dndTile;
-    @Mock
-    private QSPanelControllerBase.TileRecord mDndTileRecord;
-    @Mock
-    private QSLogger mQSLogger;
-    private ViewGroup mParentView;
-    @Mock
-    private QSDetail.Callback mCallback;
-    @Mock
-    private QSTileView mQSTileView;
-    @Mock
-    private ActivityStarter mActivityStarter;
-
-    @Before
-    public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mTestableLooper = TestableLooper.get(this);
-
-//        // Dependencies for QSSecurityFooter
-//        mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
-//        mDependency.injectMockDependency(SecurityController.class);
-//        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
-//        mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class));
-        mDndTileRecord.tile = dndTile;
-        mDndTileRecord.tileView = mQSTileView;
-
-        mTestableLooper.runWithLooper(() -> {
-            mQsPanel = new QSPanel(mContext, null);
-            mQsPanel.initialize();
-            mQsPanel.onFinishInflate();
-            // Provides a parent with non-zero size for QSPanel
-            mParentView = new FrameLayout(mContext);
-            mParentView.addView(mQsPanel);
-
-            when(dndTile.getTileSpec()).thenReturn("dnd");
-            when(mHost.getTiles()).thenReturn(Collections.emptyList());
-            when(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView);
-            mQsPanel.addTile(mDndTileRecord);
-            mQsPanel.setCallback(mCallback);
-        });
-    }
-
-    @Test
-    public void testOpenDetailsWithExistingTile_NoException() {
-        mTestableLooper.processAllMessages();
-        mQsPanel.openDetails(dndTile);
-        mTestableLooper.processAllMessages();
-
-        verify(mCallback).onShowingDetail(any(), anyInt(), anyInt());
-    }
-
-    @Test
-    public void testOpenDetailsWithNullParameter_NoException() {
-        mTestableLooper.processAllMessages();
-        mQsPanel.openDetails(null);
-        mTestableLooper.processAllMessages();
-
-        verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt());
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
new file mode 100644
index 0000000..a83a5e1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2021 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.qs
+
+import android.content.res.Configuration
+import android.content.res.Configuration.ORIENTATION_LANDSCAPE
+import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTileView
+import com.android.systemui.qs.QSPanelControllerBase.TileRecord
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+@SmallTest
+class QSPanelTest : SysuiTestCase() {
+    private lateinit var mTestableLooper: TestableLooper
+    private lateinit var mQsPanel: QSPanel
+
+    @Mock
+    private lateinit var mHost: QSTileHost
+
+    @Mock
+    private lateinit var dndTile: QSTileImpl<*>
+
+    @Mock
+    private lateinit var mDndTileRecord: TileRecord
+
+    @Mock
+    private lateinit var mQSLogger: QSLogger
+    private lateinit var mParentView: ViewGroup
+
+    @Mock
+    private lateinit var mCallback: QSDetail.Callback
+
+    @Mock
+    private lateinit var mQSTileView: QSTileView
+
+    @Before
+    @Throws(Exception::class)
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        mTestableLooper = TestableLooper.get(this)
+
+        mDndTileRecord.tile = dndTile
+        mDndTileRecord.tileView = mQSTileView
+        mTestableLooper.runWithLooper {
+            mQsPanel = QSPanel(mContext, null)
+            mQsPanel.initialize()
+            // QSPanel inflates a footer inside of it, mocking it here
+            mQsPanel.addView(LinearLayout(mContext).apply { id = R.id.qs_footer })
+            mQsPanel.onFinishInflate()
+            mQsPanel.setSecurityFooter(View(mContext), false)
+            mQsPanel.setHeaderContainer(LinearLayout(mContext))
+            // Provides a parent with non-zero size for QSPanel
+            mParentView = FrameLayout(mContext).apply {
+                addView(mQsPanel)
+            }
+
+            whenever(dndTile.tileSpec).thenReturn("dnd")
+            whenever(mHost.tiles).thenReturn(emptyList())
+            whenever(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView)
+            mQsPanel.addTile(mDndTileRecord)
+            mQsPanel.setCallback(mCallback)
+        }
+    }
+
+    @Test
+    fun testOpenDetailsWithExistingTile_NoException() {
+        mTestableLooper.runWithLooper {
+            mQsPanel.openDetails(dndTile)
+        }
+
+        verify(mCallback).onShowingDetail(any(), anyInt(), anyInt())
+    }
+
+    @Test
+    fun testOpenDetailsWithNullParameter_NoException() {
+        mTestableLooper.runWithLooper {
+            mQsPanel.openDetails(null)
+        }
+
+        verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt())
+    }
+
+    @Test
+    fun testSecurityFooter_appearsOnBottomOnSplitShade() {
+        mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_LANDSCAPE))
+        mQsPanel.switchSecurityFooter(true)
+
+        mTestableLooper.runWithLooper {
+            mQsPanel.isExpanded = true
+        }
+
+        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+    }
+
+    @Test
+    fun testSecurityFooter_appearsOnBottomIfPortrait() {
+        mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_PORTRAIT))
+        mQsPanel.switchSecurityFooter(false)
+
+        mTestableLooper.runWithLooper {
+            mQsPanel.isExpanded = true
+        }
+
+        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+    }
+
+    @Test
+    fun testSecurityFooter_appearsOnTopIfSmallScreenAndLandscape() {
+        mQsPanel.onConfigurationChanged(getNewOrientationConfig(ORIENTATION_LANDSCAPE))
+        mQsPanel.switchSecurityFooter(false)
+
+        mTestableLooper.runWithLooper {
+            mQsPanel.isExpanded = true
+        }
+
+        // -1 means that it is part of the mHeaderContainer
+        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(-1)
+    }
+
+    private fun getNewOrientationConfig(@Configuration.Orientation newOrientation: Int) =
+            context.resources.configuration.apply { orientation = newOrientation }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index d6492c6..a0b93ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -24,6 +24,7 @@
 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NOTIF_CANCEL;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -441,7 +442,7 @@
                 mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
 
         mBubbleController.removeBubble(
-                mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
+                mRow.getKey(), DISMISS_NOTIF_CANCEL);
         verify(mNotificationEntryManager, times(1)).performRemoveNotification(
                 eq(mRow.getSbn()), any(), anyInt());
         assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
@@ -1146,6 +1147,28 @@
         // Verify these are in the overflow
         assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntryUser11.getKey())).isNotNull();
         assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2User11.getKey())).isNotNull();
+
+        // Would have loaded bubbles twice because of user switch
+        verify(mDataRepository, times(2)).loadBubbles(anyInt(), any());
+    }
+
+    /**
+     * Verifies we only load the overflow data once.
+     */
+    @Test
+    public void testOverflowLoadedOnce() {
+        mBubbleController.updateBubble(mBubbleEntry);
+        mBubbleController.updateBubble(mBubbleEntry2);
+        mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
+        assertThat(mBubbleData.getOverflowBubbles().isEmpty()).isFalse();
+
+        mBubbleController.updateBubble(mBubbleEntry);
+        mBubbleController.updateBubble(mBubbleEntry2);
+        mBubbleController.removeBubble(mBubbleEntry.getKey(), DISMISS_NOTIF_CANCEL);
+        mBubbleController.removeBubble(mBubbleEntry2.getKey(), DISMISS_NOTIF_CANCEL);
+        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
+
+        verify(mDataRepository, times(1)).loadBubbles(anyInt(), any());
     }
 
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index db8a08c..b0dd73a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.wmshell;
 
 import static android.app.Notification.FLAG_BUBBLE;
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -47,6 +48,7 @@
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.os.UserHandle;
 import android.service.dreams.IDreamManager;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
@@ -172,6 +174,10 @@
     private ExpandableNotificationRow mNonBubbleNotifRow;
     private BubbleEntry mBubbleEntry;
     private BubbleEntry mBubbleEntry2;
+
+    private BubbleEntry mBubbleEntryUser11;
+    private BubbleEntry mBubbleEntry2User11;
+
     @Mock
     private Bubbles.BubbleExpandListener mBubbleExpandListener;
     @Mock
@@ -241,6 +247,13 @@
         mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow);
         mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2);
 
+        UserHandle handle = mock(UserHandle.class);
+        when(handle.getIdentifier()).thenReturn(11);
+        mBubbleEntryUser11 = BubblesManager.notifToBubbleEntry(
+                mNotificationTestHelper.createBubble(handle));
+        mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
+                mNotificationTestHelper.createBubble(handle));
+
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
@@ -908,6 +921,65 @@
                 groupSummary.getEntry().getSbn().getGroupKey()));
     }
 
+
+    /**
+     * Verifies that when the user changes, the bubbles in the overflow list is cleared. Doesn't
+     * test the loading from the repository which would be a nice thing to add.
+     */
+    @Test
+    public void testOnUserChanged_overflowState() {
+        int firstUserId = mBubbleEntry.getStatusBarNotification().getUser().getIdentifier();
+        int secondUserId = mBubbleEntryUser11.getStatusBarNotification().getUser().getIdentifier();
+
+        mBubbleController.updateBubble(mBubbleEntry);
+        mBubbleController.updateBubble(mBubbleEntry2);
+        assertTrue(mBubbleController.hasBubbles());
+        mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
+
+        // Verify these are in the overflow
+        assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry.getKey())).isNotNull();
+        assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2.getKey())).isNotNull();
+
+        // Switch users
+        mBubbleController.onUserChanged(secondUserId);
+        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
+
+        // Give this user some bubbles
+        mBubbleController.updateBubble(mBubbleEntryUser11);
+        mBubbleController.updateBubble(mBubbleEntry2User11);
+        assertTrue(mBubbleController.hasBubbles());
+        mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
+
+        // Verify these are in the overflow
+        assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntryUser11.getKey())).isNotNull();
+        assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2User11.getKey())).isNotNull();
+
+        // Would have loaded bubbles twice because of user switch
+        verify(mDataRepository, times(2)).loadBubbles(anyInt(), any());
+    }
+
+    /**
+     * Verifies we only load the overflow data once.
+     */
+    @Test
+    public void testOverflowLoadedOnce() {
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey()))
+                .thenReturn(mRow);
+        when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getKey()))
+                .thenReturn(mRow2);
+
+        mEntryListener.onEntryAdded(mRow);
+        mEntryListener.onEntryAdded(mRow2);
+        mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
+        assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty();
+
+        mEntryListener.onEntryRemoved(mRow, REASON_APP_CANCEL);
+        mEntryListener.onEntryRemoved(mRow2, REASON_APP_CANCEL);
+        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
+
+        verify(mDataRepository, times(1)).loadBubbles(anyInt(), any());
+    }
+
     /**
      * Sets the bubble metadata flags for this entry. These flags are normally set by
      * NotificationManagerService when the notification is sent, however, these tests do not
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index f9fd108..207a5e3 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -24,6 +24,7 @@
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.isValidSubscriptionId;
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -435,6 +436,15 @@
         }
     }
 
+    private boolean isActiveSubGroup(
+            @NonNull ParcelUuid subGrp, @NonNull TelephonySubscriptionSnapshot snapshot) {
+        if (subGrp == null || snapshot == null) {
+            return false;
+        }
+
+        return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup());
+    }
+
     private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback {
         /**
          * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker}
@@ -452,28 +462,49 @@
 
                 // Start any VCN instances as necessary
                 for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+                    final ParcelUuid subGrp = entry.getKey();
+
+                    // TODO(b/193687515): Support multiple VCNs active at the same time
                     if (snapshot.packageHasPermissionsForSubscriptionGroup(
-                            entry.getKey(), entry.getValue().getProvisioningPackageName())) {
-                        if (!mVcns.containsKey(entry.getKey())) {
-                            startVcnLocked(entry.getKey(), entry.getValue());
+                                    subGrp, entry.getValue().getProvisioningPackageName())
+                            && isActiveSubGroup(subGrp, snapshot)) {
+                        if (!mVcns.containsKey(subGrp)) {
+                            startVcnLocked(subGrp, entry.getValue());
                         }
 
                         // Cancel any scheduled teardowns for active subscriptions
-                        mHandler.removeCallbacksAndMessages(mVcns.get(entry.getKey()));
+                        mHandler.removeCallbacksAndMessages(mVcns.get(subGrp));
                     }
                 }
 
                 // Schedule teardown of any VCN instances that have lost carrier privileges (after a
                 // delay)
                 for (Entry<ParcelUuid, Vcn> entry : mVcns.entrySet()) {
-                    final VcnConfig config = mConfigs.get(entry.getKey());
+                    final ParcelUuid subGrp = entry.getKey();
+                    final VcnConfig config = mConfigs.get(subGrp);
 
+                    final boolean isActiveSubGrp = isActiveSubGroup(subGrp, snapshot);
+                    final boolean isValidActiveDataSubIdNotInVcnSubGrp =
+                            isValidSubscriptionId(snapshot.getActiveDataSubscriptionId())
+                                    && !isActiveSubGroup(subGrp, snapshot);
+
+                    // TODO(b/193687515): Support multiple VCNs active at the same time
                     if (config == null
                             || !snapshot.packageHasPermissionsForSubscriptionGroup(
-                                    entry.getKey(), config.getProvisioningPackageName())) {
-                        final ParcelUuid uuidToTeardown = entry.getKey();
+                                    subGrp, config.getProvisioningPackageName())
+                            || !isActiveSubGrp) {
+                        final ParcelUuid uuidToTeardown = subGrp;
                         final Vcn instanceToTeardown = entry.getValue();
 
+                        // TODO(b/193687515): Support multiple VCNs active at the same time
+                        // If directly switching to a subscription not in the current group,
+                        // teardown immediately to prevent other subscription's network from being
+                        // outscored by the VCN. Otherwise, teardown after a delay to ensure that
+                        // SIM profile switches do not trigger the VCN to cycle.
+                        final long teardownDelayMs =
+                                isValidActiveDataSubIdNotInVcnSubGrp
+                                        ? 0
+                                        : CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS;
                         mHandler.postDelayed(() -> {
                             synchronized (mLock) {
                                 // Guard against case where this is run after a old instance was
@@ -489,7 +520,7 @@
                                             uuidToTeardown, VCN_STATUS_CODE_INACTIVE);
                                 }
                             }
-                        }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+                        }, instanceToTeardown, teardownDelayMs);
                     } else {
                         // If this VCN's status has not changed, update it with the new snapshot
                         entry.getValue().updateSubscriptionSnapshot(mLastSnapshot);
@@ -553,8 +584,13 @@
     private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
         logDbg("Starting VCN config for subGrp: " + subscriptionGroup);
 
-        // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
-        //                    VCN.
+        // TODO(b/193687515): Support multiple VCNs active at the same time
+        if (!mVcns.isEmpty()) {
+            // Only one VCN supported at a time; teardown all others before starting new one
+            for (ParcelUuid uuidToTeardown : mVcns.keySet()) {
+                stopVcnLocked(uuidToTeardown);
+            }
+        }
 
         final VcnCallbackImpl vcnCallback = new VcnCallbackImpl(subscriptionGroup);
 
@@ -582,7 +618,10 @@
             final Vcn vcn = mVcns.get(subscriptionGroup);
             vcn.updateConfig(config);
         } else {
-            startVcnLocked(subscriptionGroup, config);
+            // TODO(b/193687515): Support multiple VCNs active at the same time
+            if (isActiveSubGroup(subscriptionGroup, mLastSnapshot)) {
+                startVcnLocked(subscriptionGroup, config);
+            }
         }
     }
 
@@ -1007,6 +1046,11 @@
         }
     }
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setLastSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot) {
+        mLastSnapshot = Objects.requireNonNull(snapshot);
+    }
+
     private void logVdbg(String msg) {
         if (VDBG) {
             Slog.v(TAG, msg);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index b5ead20..795d3d6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3334,7 +3334,13 @@
         }
     }
 
-    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
+    /**
+     * Bump the given service record into executing state.
+     * @param oomAdjReason The caller requests it to perform the oomAdjUpdate if it's not null.
+     * @return {@code true} if it performed oomAdjUpdate.
+     */
+    private boolean bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why,
+            @Nullable String oomAdjReason) {
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
                 + why + " of " + r + " in app " + r.app);
         else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
@@ -3383,9 +3389,19 @@
                 }
             }
         }
+        boolean oomAdjusted = false;
+        if (oomAdjReason != null && r.app != null
+                && r.app.mState.getCurProcState() > ActivityManager.PROCESS_STATE_SERVICE) {
+            // Force an immediate oomAdjUpdate, so the client app could be in the correct process
+            // state before doing any service related transactions
+            mAm.enqueueOomAdjTargetLocked(r.app);
+            mAm.updateOomAdjPendingTargetsLocked(oomAdjReason);
+            oomAdjusted = true;
+        }
         r.executeFg |= fg;
         r.executeNesting++;
         r.executingStart = now;
+        return oomAdjusted;
     }
 
     private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
@@ -3398,8 +3414,8 @@
                 + " rebind=" + rebind);
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
-                bumpServiceExecutingLocked(r, execInFg, "bind");
-                r.app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
+                bumpServiceExecutingLocked(r, execInFg, "bind",
+                        OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
                 r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind,
                         r.app.mState.getReportedProcState());
                 if (!rebind) {
@@ -3867,14 +3883,13 @@
 
         final ProcessServiceRecord psr = app.mServices;
         final boolean newService = psr.startService(r);
-        bumpServiceExecutingLocked(r, execInFg, "create");
+        bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
         mAm.updateLruProcessLocked(app, false, null);
         updateServiceForegroundLocked(psr, /* oomAdj= */ false);
-        if (enqueueOomAdj) {
-            mAm.enqueueOomAdjTargetLocked(app);
-        } else {
-            mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
-        }
+        // Force an immediate oomAdjUpdate, so the client app could be in the correct process state
+        // before doing any service related transactions
+        mAm.enqueueOomAdjTargetLocked(app);
+        mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
 
         boolean created = false;
         try {
@@ -3895,7 +3910,6 @@
             mAm.mBatteryStatsService.noteServiceStartLaunch(uid, packageName, serviceName);
             mAm.notifyPackageUse(r.serviceInfo.packageName,
                                  PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
-            app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
             thread.scheduleCreateService(r, r.serviceInfo,
                     mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                     app.mState.getReportedProcState());
@@ -3995,11 +4009,7 @@
             mAm.grantImplicitAccess(r.userId, si.intent, si.callingId,
                     UserHandle.getAppId(r.appInfo.uid)
             );
-            bumpServiceExecutingLocked(r, execInFg, "start");
-            if (!oomAdjusted) {
-                oomAdjusted = true;
-                mAm.updateOomAdjLocked(r.app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
-            }
+            bumpServiceExecutingLocked(r, execInFg, "start", null /* oomAdjReason */);
             if (r.fgRequired && !r.fgWaiting) {
                 if (!r.isForeground) {
                     if (DEBUG_BACKGROUND_CHECK) {
@@ -4023,6 +4033,10 @@
             args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
         }
 
+        if (!oomAdjusted) {
+            mAm.enqueueOomAdjTargetLocked(r.app);
+            mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
+        }
         ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
         slice.setInlineCountLimit(4);
         Exception caughtException = null;
@@ -4117,7 +4131,7 @@
             }
         }
 
-        boolean needOomAdj = false;
+        boolean oomAdjusted = false;
         // Tell the service that it has been unbound.
         if (r.app != null && r.app.getThread() != null) {
             for (int i = r.bindings.size() - 1; i >= 0; i--) {
@@ -4126,8 +4140,8 @@
                         + ": hasBound=" + ibr.hasBound);
                 if (ibr.hasBound) {
                     try {
-                        bumpServiceExecutingLocked(r, false, "bring down unbind");
-                        needOomAdj = true;
+                        oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind",
+                                OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.getThread().scheduleUnbindService(r,
@@ -4135,7 +4149,6 @@
                     } catch (Exception e) {
                         Slog.w(TAG, "Exception when unbinding service "
                                 + r.shortInstanceName, e);
-                        needOomAdj = false;
                         serviceProcessGoneLocked(r, enqueueOomAdj);
                         break;
                     }
@@ -4247,10 +4260,10 @@
                 mAm.updateLruProcessLocked(r.app, false, null);
                 updateServiceForegroundLocked(r.app.mServices, false);
                 try {
-                    bumpServiceExecutingLocked(r, false, "destroy");
+                    oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy",
+                            oomAdjusted ? null : OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                     mDestroyingServices.add(r);
                     r.destroying = true;
-                    needOomAdj = true;
                     r.app.getThread().scheduleStopService(r);
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when destroying service "
@@ -4266,11 +4279,10 @@
                 TAG_SERVICE, "Removed service that is not running: " + r);
         }
 
-        if (needOomAdj) {
-            if (enqueueOomAdj) {
-                mAm.enqueueOomAdjTargetLocked(r.app);
-            } else {
-                mAm.updateOomAdjLocked(r.app, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
+        if (!oomAdjusted) {
+            mAm.enqueueOomAdjTargetLocked(r.app);
+            if (!enqueueOomAdj) {
+                mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
             }
         }
         if (r.bindings.size() > 0) {
@@ -4387,7 +4399,8 @@
             if (s.app != null && s.app.getThread() != null && b.intent.apps.size() == 0
                     && b.intent.hasBound) {
                 try {
-                    bumpServiceExecutingLocked(s, false, "unbind");
+                    bumpServiceExecutingLocked(s, false, "unbind",
+                            OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                     if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                             && s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) {
                         // If this service's process is not already in the cached list,
@@ -4395,11 +4408,6 @@
                         // it to go down there and we want it to start out near the top.
                         mAm.updateLruProcessLocked(s.app, false, null);
                     }
-                    if (enqueueOomAdj) {
-                        mAm.enqueueOomAdjTargetLocked(s.app);
-                    } else {
-                        mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
-                    }
                     b.intent.hasBound = false;
                     // Assume the client doesn't want to know about a rebind;
                     // we will deal with that later if it asks for one.
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index c702d78..a8d0582 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -43,6 +43,7 @@
     private static final int LOW_MEM_AND_THRASHING = 4;
     private static final int DIRECT_RECL_AND_THRASHING = 5;
     private static final int LOW_MEM_AND_SWAP_UTIL = 6;
+    private static final int LOW_FILECACHE_AFTER_THRASHING = 7;
 
     /**
      * Processes the LMK_KILL_OCCURRED packet data
@@ -100,6 +101,8 @@
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING;
             case LOW_MEM_AND_SWAP_UTIL:
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL;
+            case LOW_FILECACHE_AFTER_THRASHING:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_FILECACHE_AFTER_THRASHING;
             default:
                 return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
         }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 33bc212..24edc01 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -202,6 +202,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Scanner;
 import java.util.Set;
@@ -775,7 +776,11 @@
 
         /** Clean up event */
         public void finish() {
-            mClientId.unlinkToDeath(this, 0);
+            try {
+                mClientId.unlinkToDeath(this, 0);
+            } catch (NoSuchElementException e) {
+                // Either not linked, or already unlinked. Either way, nothing to do.
+            }
         }
 
         @Override
@@ -5099,13 +5104,15 @@
                     String lastPkg = null;
                     for (int i=0; i<allOps.size(); i++) {
                         AppOpsManager.PackageOps pkg = allOps.get(i);
-                        if (!pkg.getPackageName().equals(lastPkg)) {
+                        if (!Objects.equals(pkg.getPackageName(), lastPkg)) {
                             if (lastPkg != null) {
                                 out.endTag(null, "pkg");
                             }
                             lastPkg = pkg.getPackageName();
-                            out.startTag(null, "pkg");
-                            out.attribute(null, "n", lastPkg);
+                            if (lastPkg != null) {
+                                out.startTag(null, "pkg");
+                                out.attribute(null, "n", lastPkg);
+                            }
                         }
                         out.startTag(null, "uid");
                         out.attributeInt(null, "n", pkg.getUid());
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index f11fe8a..c2eb062 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -22,6 +22,7 @@
 import android.media.AudioAttributes;
 import android.os.IBinder;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
@@ -49,6 +50,8 @@
             VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
 
     private final PowerManager mPowerManager;
+    // If haptics should occur when auth result (success/reject) is known
+    protected final boolean mShouldVibrate;
     private boolean mShouldSendErrorToClient = true;
     private boolean mAlreadyCancelled;
 
@@ -59,11 +62,12 @@
 
     public AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
-            @NonNull String owner, int cookie, int sensorId, int statsModality,
-            int statsAction, int statsClient) {
+            @NonNull String owner, int cookie, int sensorId, boolean shouldVibrate,
+            int statsModality, int statsAction, int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
                 statsAction, statsClient);
         mPowerManager = context.getSystemService(PowerManager.class);
+        mShouldVibrate = shouldVibrate;
     }
 
     @Override
@@ -191,14 +195,22 @@
     protected final void vibrateSuccess() {
         Vibrator vibrator = getContext().getSystemService(Vibrator.class);
         if (vibrator != null) {
-            vibrator.vibrate(SUCCESS_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
+            vibrator.vibrate(Process.myUid(),
+                    getContext().getOpPackageName(),
+                    SUCCESS_VIBRATION_EFFECT,
+                    getClass().getSimpleName() + "::success",
+                    VIBRATION_SONIFICATION_ATTRIBUTES);
         }
     }
 
     protected final void vibrateError() {
         Vibrator vibrator = getContext().getSystemService(Vibrator.class);
         if (vibrator != null) {
-            vibrator.vibrate(ERROR_VIBRATION_EFFECT, VIBRATION_SONIFICATION_ATTRIBUTES);
+            vibrator.vibrate(Process.myUid(),
+                    getContext().getOpPackageName(),
+                    ERROR_VIBRATION_EFFECT,
+                    getClass().getSimpleName() + "::error",
+                    VIBRATION_SONIFICATION_ATTRIBUTES);
         }
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 80e60e6..3e6602e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -68,9 +68,11 @@
             int targetUserId, long operationId, boolean restricted, @NonNull String owner,
             int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
             int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
-            @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication) {
+            @NonNull LockoutTracker lockoutTracker, boolean allowBackgroundAuthentication,
+            boolean shouldVibrate) {
         super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
-                statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+                shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE,
+                statsClient);
         mIsStrongBiometric = isStrongBiometric;
         mOperationId = operationId;
         mRequireConfirmation = requireConfirmation;
@@ -204,7 +206,7 @@
 
                 mAlreadyDone = true;
 
-                if (listener != null) {
+                if (listener != null && mShouldVibrate) {
                     vibrateSuccess();
                 }
 
@@ -250,7 +252,7 @@
                     Slog.w(TAG, "Client not listening");
                 }
             } else {
-                if (listener != null) {
+                if (listener != null && mShouldVibrate) {
                     vibrateError();
                 }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index e1320d8e..a15e14b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -38,7 +38,6 @@
     protected final byte[] mHardwareAuthToken;
     protected final int mTimeoutSec;
     protected final BiometricUtils mBiometricUtils;
-    private final boolean mShouldVibrate;
 
     private long mEnrollmentStartTimeMs;
 
@@ -50,15 +49,13 @@
     public EnrollClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
             @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
-            int timeoutSec, int statsModality, int sensorId,
-            boolean shouldVibrate) {
+            int timeoutSec, int statsModality, int sensorId, boolean shouldVibrate) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
-                statsModality, BiometricsProtoEnums.ACTION_ENROLL,
+                shouldVibrate, statsModality, BiometricsProtoEnums.ACTION_ENROLL,
                 BiometricsProtoEnums.CLIENT_UNKNOWN);
         mBiometricUtils = utils;
         mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
         mTimeoutSec = timeoutSec;
-        mShouldVibrate = shouldVibrate;
     }
 
     public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 3757404..0525d2d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -73,7 +73,7 @@
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
-                lockoutCache, allowBackgroundAuthentication);
+                lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
         mUsageStats = usageStats;
         mLockoutCache = lockoutCache;
         mNotificationManager = context.getSystemService(NotificationManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index cb966e7..1e73ac5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -46,8 +46,8 @@
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
             @NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
-                BiometricsProtoEnums.MODALITY_FACE, BiometricsProtoEnums.ACTION_AUTHENTICATE,
-                statsClient);
+                true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE,
+                BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
         mIsStrongBiometric = isStrongBiometric;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index c3de7aa..5731d73 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -65,7 +65,7 @@
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
-                lockoutTracker, allowBackgroundAuthentication);
+                lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
         mUsageStats = usageStats;
 
         final Resources resources = getContext().getResources();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 19134e4..8681ad7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -26,6 +26,7 @@
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.common.ICancellationSignal;
 import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -62,11 +63,12 @@
             int sensorId, boolean isStrongBiometric, int statsClient,
             @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
             @Nullable IUdfpsOverlayController udfpsOverlayController,
-            boolean allowBackgroundAuthentication) {
+            boolean allowBackgroundAuthentication,
+            @NonNull FingerprintSensorPropertiesInternal sensorProps) {
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
                 cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
-                lockoutCache, allowBackgroundAuthentication);
+                lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */);
         mLockoutCache = lockoutCache;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 5e1a245..c5dc449 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -52,8 +52,8 @@
             @Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric,
             int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
-                BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
-                statsClient);
+                true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
+                BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
         mIsStrongBiometric = isStrongBiometric;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 646b988..a211bb5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -65,7 +65,7 @@
             @Nullable IUdfpsOverlayController udfpsOvelayController,
             @Nullable ISidefpsController sidefpsController,
             int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
-        // UDFPS enroll vibrations are handled in SystemUI
+        // UDFPS haptics occur when an image is acquired (instead of when the result is known)
         super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
                 0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
                 !sensorProps.isAnyUdfpsType() /* shouldVibrate */);
@@ -104,6 +104,7 @@
         // See AcquiredInfo#GOOD and AcquiredInfo#RETRYING_CAPTURE
         if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD
                 && mSensorProps.isAnyUdfpsType()) {
+            vibrateSuccess();
             UdfpsHelper.onAcquiredGood(getSensorId(), mUdfpsOverlayController);
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 096c311..cfc4674 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -395,7 +395,8 @@
                     operationId, restricted, opPackageName, cookie,
                     false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
                     mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
-                    mUdfpsOverlayController, allowBackgroundAuthentication);
+                    mUdfpsOverlayController, allowBackgroundAuthentication,
+                    mSensors.get(sensorId).getSensorProperties());
             scheduleForSensor(sensorId, client, fingerprintStateCallback);
         });
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index bf77757..40e3bc3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -65,7 +65,7 @@
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
                 BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
-                lockoutTracker, allowBackgroundAuthentication);
+                lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */);
         mLockoutFrameworkImpl = lockoutTracker;
         mUdfpsOverlayController = udfpsOverlayController;
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 8d777e1..af1e49d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -56,8 +56,8 @@
             int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController,
             boolean isStrongBiometric, int statsClient) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
-                BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
-                statsClient);
+                true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
+                BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
         mUdfpsOverlayController = udfpsOverlayController;
         mIsStrongBiometric = isStrongBiometric;
     }
diff --git a/services/core/java/com/android/server/location/injector/AlarmHelper.java b/services/core/java/com/android/server/location/injector/AlarmHelper.java
index f3fb9c8..91a1042 100644
--- a/services/core/java/com/android/server/location/injector/AlarmHelper.java
+++ b/services/core/java/com/android/server/location/injector/AlarmHelper.java
@@ -33,7 +33,6 @@
             WorkSource workSource) {
         // helps ensure that we're not wasting system resources by setting alarms in the past/now
         Preconditions.checkArgument(delayMs > 0);
-        Preconditions.checkArgument(workSource != null);
         setDelayedAlarmInternal(delayMs, listener, workSource);
     }
 
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 8c9068d..8955c28 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -735,8 +735,12 @@
             if (mExpirationRealtimeMs <= registerTimeMs) {
                 onAlarm();
             } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                // Set WorkSource to null in order to ensure the alarm wakes up the device even when
+                // it is idle. Do this when the cost of waking up the device is less than the power
+                // cost of not performing the actions set off by the alarm, such as unregistering a
+                // location request.
                 mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
-                        getRequest().getWorkSource());
+                        null);
             }
 
             // start listening for provider enabled/disabled events
@@ -1122,8 +1126,12 @@
             if (mExpirationRealtimeMs <= registerTimeMs) {
                 onAlarm();
             } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+                // Set WorkSource to null in order to ensure the alarm wakes up the device even when
+                // it is idle. Do this when the cost of waking up the device is less than the power
+                // cost of not performing the actions set off by the alarm, such as unregistering a
+                // location request.
                 mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
-                        getRequest().getWorkSource());
+                        null);
             }
         }
 
@@ -1995,7 +2003,11 @@
                     }
                 }
             };
-            mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, newRequest.getWorkSource());
+            // Set WorkSource to null in order to ensure the alarm wakes up the device even when it
+            // is idle. Do this when the cost of waking up the device is less than the power cost of
+            // not performing the actions set off by the alarm, such as unregistering a location
+            // request.
+            mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, null);
         }
 
         return true;
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index f7950aa..f13f406 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -141,7 +141,8 @@
                                         throws RemoteException {
                             attributionSource.enforceCallingUid();
                             if (!attributionSource.isTrusted(mMaster.getContext())) {
-                                mMaster.getContext().getSystemService(PermissionManager.class)
+                                attributionSource = mMaster.getContext()
+                                        .getSystemService(PermissionManager.class)
                                         .registerAttributionSource(attributionSource);
                             }
                             service.startListening(recognizerIntent, listener, attributionSource);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index fca706b..a31c56a 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -36,6 +36,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -85,6 +86,8 @@
     @NonNull private final SubscriptionManager mSubscriptionManager;
     @NonNull private final CarrierConfigManager mCarrierConfigManager;
 
+    @NonNull private final ActiveDataSubscriptionIdListener mActiveDataSubIdListener;
+
     // TODO (Android T+): Add ability to handle multiple subIds per slot.
     @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
     @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
@@ -112,6 +115,7 @@
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+        mActiveDataSubIdListener = new ActiveDataSubscriptionIdListener();
 
         mSubscriptionChangedListener =
                 new OnSubscriptionsChangedListener() {
@@ -124,16 +128,20 @@
 
     /** Registers the receivers, and starts tracking subscriptions. */
     public void register() {
+        final HandlerExecutor executor = new HandlerExecutor(mHandler);
+
         mContext.registerReceiver(
                 this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
         mSubscriptionManager.addOnSubscriptionsChangedListener(
-                new HandlerExecutor(mHandler), mSubscriptionChangedListener);
+                executor, mSubscriptionChangedListener);
+        mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
     }
 
     /** Unregisters the receivers, and stops tracking subscriptions. */
     public void unregister() {
         mContext.unregisterReceiver(this);
         mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+        mTelephonyManager.unregisterTelephonyCallback(mActiveDataSubIdListener);
     }
 
     /**
@@ -185,7 +193,8 @@
         }
 
         final TelephonySubscriptionSnapshot newSnapshot =
-                new TelephonySubscriptionSnapshot(newSubIdToInfoMap, privilegedPackages);
+                new TelephonySubscriptionSnapshot(
+                        mDeps.getActiveDataSubscriptionId(), newSubIdToInfoMap, privilegedPackages);
 
         // If snapshot was meaningfully updated, fire the callback
         if (!newSnapshot.equals(mCurrentSnapshot)) {
@@ -242,16 +251,20 @@
 
     /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
     public static class TelephonySubscriptionSnapshot {
+        private final int mActiveDataSubId;
         private final Map<Integer, SubscriptionInfo> mSubIdToInfoMap;
         private final Map<ParcelUuid, Set<String>> mPrivilegedPackages;
 
         public static final TelephonySubscriptionSnapshot EMPTY_SNAPSHOT =
-                new TelephonySubscriptionSnapshot(Collections.emptyMap(), Collections.emptyMap());
+                new TelephonySubscriptionSnapshot(
+                        INVALID_SUBSCRIPTION_ID, Collections.emptyMap(), Collections.emptyMap());
 
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         TelephonySubscriptionSnapshot(
+                int activeDataSubId,
                 @NonNull Map<Integer, SubscriptionInfo> subIdToInfoMap,
                 @NonNull Map<ParcelUuid, Set<String>> privilegedPackages) {
+            mActiveDataSubId = activeDataSubId;
             Objects.requireNonNull(subIdToInfoMap, "subIdToInfoMap was null");
             Objects.requireNonNull(privilegedPackages, "privilegedPackages was null");
 
@@ -265,6 +278,22 @@
             mPrivilegedPackages = Collections.unmodifiableMap(unmodifiableInnerSets);
         }
 
+        /** Returns the active subscription ID. May be INVALID_SUBSCRIPTION_ID */
+        public int getActiveDataSubscriptionId() {
+            return mActiveDataSubId;
+        }
+
+        /** Returns the active subscription group */
+        @Nullable
+        public ParcelUuid getActiveDataSubscriptionGroup() {
+            final SubscriptionInfo info = mSubIdToInfoMap.get(getActiveDataSubscriptionId());
+            if (info == null) {
+                return null;
+            }
+
+            return info.getGroupUuid();
+        }
+
         /** Returns the active subscription groups */
         @NonNull
         public Set<ParcelUuid> getActiveSubscriptionGroups() {
@@ -313,7 +342,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(mSubIdToInfoMap, mPrivilegedPackages);
+            return Objects.hash(mActiveDataSubId, mSubIdToInfoMap, mPrivilegedPackages);
         }
 
         @Override
@@ -324,7 +353,8 @@
 
             final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
 
-            return mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
+            return mActiveDataSubId == other.mActiveDataSubId
+                    && mSubIdToInfoMap.equals(other.mSubIdToInfoMap)
                     && mPrivilegedPackages.equals(other.mPrivilegedPackages);
         }
 
@@ -333,6 +363,7 @@
             pw.println("TelephonySubscriptionSnapshot:");
             pw.increaseIndent();
 
+            pw.println("mActiveDataSubId: " + mActiveDataSubId);
             pw.println("mSubIdToInfoMap: " + mSubIdToInfoMap);
             pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
 
@@ -342,7 +373,8 @@
         @Override
         public String toString() {
             return "TelephonySubscriptionSnapshot{ "
-                    + "mSubIdToInfoMap=" + mSubIdToInfoMap
+                    + "mActiveDataSubId=" + mActiveDataSubId
+                    + ", mSubIdToInfoMap=" + mSubIdToInfoMap
                     + ", mPrivilegedPackages=" + mPrivilegedPackages
                     + " }";
         }
@@ -362,6 +394,14 @@
         void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot);
     }
 
+    private class ActiveDataSubscriptionIdListener extends TelephonyCallback
+            implements TelephonyCallback.ActiveDataSubscriptionIdListener {
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            handleSubscriptionsChanged();
+        }
+    }
+
     /** External static dependencies for test injection */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public static class Dependencies {
@@ -369,5 +409,10 @@
         public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
             return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle);
         }
+
+        /** Gets the active Subscription ID */
+        public int getActiveDataSubscriptionId() {
+            return SubscriptionManager.getActiveDataSubscriptionId();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index eba3e85..b3aa057 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -731,6 +731,7 @@
 
     WindowOrganizerController mWindowOrganizerController;
     TaskOrganizerController mTaskOrganizerController;
+    TaskFragmentOrganizerController mTaskFragmentOrganizerController;
 
     @Nullable
     private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
@@ -804,6 +805,8 @@
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
         mWindowOrganizerController = new WindowOrganizerController(this);
         mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
+        mTaskFragmentOrganizerController =
+                mWindowOrganizerController.mTaskFragmentOrganizerController;
     }
 
     public void onSystemReady() {
@@ -3441,7 +3444,6 @@
 
     @Override
     public IWindowOrganizerController getWindowOrganizerController() {
-        enforceTaskPermission("getWindowOrganizerController()");
         return mWindowOrganizerController;
     }
 
@@ -5657,7 +5659,8 @@
         @Override
         public ActivityTokens getTopActivityForTask(int taskId) {
             synchronized (mGlobalLock) {
-                final Task task = mRootWindowContainer.anyTaskForId(taskId);
+                final Task task = mRootWindowContainer.anyTaskForId(taskId,
+                        MATCH_ATTACHED_TASK_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
                             + " Requested task not found");
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 35add12..75abd17 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -26,6 +26,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.DisplayAreaAppearedInfo;
 import android.window.IDisplayAreaOrganizer;
@@ -49,7 +50,8 @@
 
     final ActivityTaskManagerService mService;
     private final WindowManagerGlobalLock mGlobalLock;
-    private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
+    private final HashMap<Integer, DisplayAreaOrganizerState> mOrganizersByFeatureIds =
+            new HashMap();
 
     private class DeathRecipient implements IBinder.DeathRecipient {
         int mFeature;
@@ -63,12 +65,41 @@
         @Override
         public void binderDied() {
             synchronized (mGlobalLock) {
-                mOrganizersByFeatureIds.remove(mFeature);
-                removeOrganizer(mOrganizer);
+                mOrganizersByFeatureIds.remove(mFeature).destroy();
             }
         }
     }
 
+    private class DisplayAreaOrganizerState {
+        private final IDisplayAreaOrganizer mOrganizer;
+        private final DeathRecipient mDeathRecipient;
+
+        DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature) {
+            mOrganizer = organizer;
+            mDeathRecipient = new DeathRecipient(organizer, feature);
+            try {
+                organizer.asBinder().linkToDeath(mDeathRecipient, 0);
+            } catch (RemoteException e) {
+                // Oh well...
+            }
+        }
+
+        void destroy() {
+            IBinder organizerBinder = mOrganizer.asBinder();
+            mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
+                if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
+                    if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
+                        // Delete the organizer created TDA when unregister.
+                        deleteTaskDisplayArea(da.asTaskDisplayArea());
+                    } else {
+                        da.setOrganizer(null);
+                    }
+                }
+            });
+            organizerBinder.unlinkToDeath(mDeathRecipient, 0);
+        }
+    }
+
     DisplayAreaOrganizerController(ActivityTaskManagerService atm) {
         mService = atm;
         mGlobalLock = atm.mGlobalLock;
@@ -80,7 +111,8 @@
 
     @Nullable
     IDisplayAreaOrganizer getOrganizerByFeature(int featureId) {
-        return mOrganizersByFeatureIds.get(featureId);
+        final DisplayAreaOrganizerState state = mOrganizersByFeatureIds.get(featureId);
+        return state != null ? state.mOrganizer : null;
     }
 
     @Override
@@ -94,17 +126,18 @@
                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
                         organizer.asBinder(), uid);
                 if (mOrganizersByFeatureIds.get(feature) != null) {
-                    throw new IllegalStateException(
-                            "Replacing existing organizer currently unsupported");
+                    if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder()
+                            .isBinderAlive()) {
+                        throw new IllegalStateException(
+                                "Replacing existing organizer currently unsupported");
+                    }
+
+                    mOrganizersByFeatureIds.remove(feature).destroy();
+                    Slog.d(TAG, "Replacing dead organizer for feature=" + feature);
                 }
 
-                final DeathRecipient dr = new DeathRecipient(organizer, feature);
-                try {
-                    organizer.asBinder().linkToDeath(dr, 0);
-                } catch (RemoteException e) {
-                    // Oh well...
-                }
-
+                final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
+                        feature);
                 final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
                 mService.mRootWindowContainer.forAllDisplays(dc -> {
                     if (!dc.isTrusted()) {
@@ -120,7 +153,7 @@
                     });
                 });
 
-                mOrganizersByFeatureIds.put(feature, organizer);
+                mOrganizersByFeatureIds.put(feature, state);
                 return new ParceledListSlice<>(displayAreaInfos);
             }
         } finally {
@@ -137,9 +170,11 @@
             synchronized (mGlobalLock) {
                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
                         organizer.asBinder(), uid);
-                mOrganizersByFeatureIds.entrySet().removeIf(
-                        entry -> entry.getValue().asBinder() == organizer.asBinder());
-                removeOrganizer(organizer);
+                mOrganizersByFeatureIds.values().forEach((state) -> {
+                    if (state.mOrganizer.asBinder() == organizer.asBinder()) {
+                        state.destroy();
+                    }
+                });
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -190,19 +225,15 @@
                 }
 
                 final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
-                final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
-                try {
-                    organizer.asBinder().linkToDeath(dr, 0);
-                } catch (RemoteException e) {
-                    // Oh well...
-                }
+                final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
+                        taskDisplayAreaFeatureId);
 
                 final TaskDisplayArea tda = parentRoot != null
                         ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId)
                         : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId);
                 final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda,
                         "DisplayAreaOrganizerController.createTaskDisplayArea");
-                mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer);
+                mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, state);
                 return tdaInfo;
             }
         } finally {
@@ -230,8 +261,7 @@
                                     + "TaskDisplayArea=" + taskDisplayArea);
                 }
 
-                mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId);
-                deleteTaskDisplayArea(taskDisplayArea);
+                mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId).destroy();
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -251,6 +281,10 @@
 
     void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
+        if (!organizer.asBinder().isBinderAlive()) {
+            Slog.d(TAG, "Organizer died before sending onDisplayAreaVanished");
+            return;
+        }
         try {
             organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
         } catch (RemoteException e) {
@@ -267,20 +301,6 @@
         }
     }
 
-    private void removeOrganizer(IDisplayAreaOrganizer organizer) {
-        IBinder organizerBinder = organizer.asBinder();
-        mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
-            if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
-                if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
-                    // Delete the organizer created TDA when unregister.
-                    deleteTaskDisplayArea(da.asTaskDisplayArea());
-                } else {
-                    da.setOrganizer(null);
-                }
-            }
-        });
-    }
-
     private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
             DisplayArea displayArea, String callsite) {
         displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 212f50b..7f78bdd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1917,7 +1917,7 @@
                 mStatusBarColorWindows.add(win);
                 mStatusBarColorCheckedBounds.union(sTmpRect);
             }
-            if (isOverlappingWithNavBar && mNavigationBar == null) {
+            if (isOverlappingWithNavBar && mNavBarColorWindowCandidate == null) {
                 mNavBarColorWindowCandidate = win;
             }
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bd00751..8235095 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -858,6 +858,7 @@
 
         // Send any pending task-info changes that were queued-up during a layout deferment
         mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+        mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents();
         mWmService.mSyncEngine.onSurfacePlacement();
         mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 12ad634..59c3ffe 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -82,6 +82,7 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
+import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
 import android.window.TaskFragmentInfo;
 
@@ -161,6 +162,11 @@
     private TaskFragment mAdjacentTaskFragment;
 
     /**
+     * Prevents duplicate calls to onTaskAppeared.
+     */
+    boolean mTaskFragmentAppearedSent;
+
+    /**
      * When we are in the process of pausing an activity, before starting the
      * next one, this variable holds the activity that is currently being paused.
      *
@@ -283,6 +289,12 @@
         mTaskFragmentOrganizerPid = pid;
     }
 
+    /** Whether this TaskFragment is organized by the given {@code organizer}. */
+    boolean hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) {
+        return organizer != null && mTaskFragmentOrganizer != null
+                && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder());
+    }
+
     TaskFragment getAdjacentTaskFragment() {
         return mAdjacentTaskFragment;
     }
@@ -1970,18 +1982,24 @@
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         super.onConfigurationChanged(newParentConfig);
+        sendTaskFragmentInfoChanged();
+    }
 
+    @Override
+    void setSurfaceControl(SurfaceControl sc) {
+        super.setSurfaceControl(sc);
+        // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
+        // emit the callbacks now.
+        sendTaskFragmentAppeared();
+    }
+
+    void sendTaskFragmentInfoChanged() {
         if (mTaskFragmentOrganizer != null) {
-            // Parent config may have changed. The controller will check if there is any important
-            // config change for the organizer.
-            mTaskFragmentOrganizerController
-                    .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, this);
             mTaskFragmentOrganizerController
                     .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
         }
     }
 
-    // TODO(b/190433129) call when TaskFragment is created from WCT#createTaskFragment
     private void sendTaskFragmentAppeared() {
         if (mTaskFragmentOrganizer != null) {
             mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 56d29de..496ecde 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -19,6 +19,8 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
 import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.IBinder;
@@ -33,6 +35,8 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -45,16 +49,17 @@
 
     private final ActivityTaskManagerService mAtmService;
     private final WindowManagerGlobalLock mGlobalLock;
-    private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
-            new WeakHashMap<>();
-    private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
-            new WeakHashMap<>();
     /**
      * A Map which manages the relationship between
      * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState}
      */
-    private final ArrayMap<IBinder, TaskFragmentController> mTaskFragmentOrganizerControllers =
+    private final ArrayMap<IBinder, TaskFragmentOrganizerState> mTaskFragmentOrganizerState =
             new ArrayMap<>();
+    /**
+     * A List which manages the TaskFragment pending event {@link PendingTaskFragmentEvent}
+     */
+    private final ArrayList<PendingTaskFragmentEvent> mPendingTaskFragmentEvents =
+            new ArrayList<>();
 
     TaskFragmentOrganizerController(ActivityTaskManagerService atm) {
         mAtmService = atm;
@@ -65,11 +70,15 @@
      * A class to manage {@link ITaskFragmentOrganizer} and its organized
      * {@link TaskFragment TaskFragments}.
      */
-    private class TaskFragmentController implements IBinder.DeathRecipient {
+    private class TaskFragmentOrganizerState implements IBinder.DeathRecipient {
         private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>();
         private final ITaskFragmentOrganizer mOrganizer;
+        private final Map<TaskFragment, TaskFragmentInfo> mLastSentTaskFragmentInfos =
+                new WeakHashMap<>();
+        private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
+                new WeakHashMap<>();
 
-        TaskFragmentController(ITaskFragmentOrganizer organizer) {
+        TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) {
             mOrganizer = organizer;
             try {
                 mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/);
@@ -85,10 +94,18 @@
             }
         }
 
-        void addTaskFragment(TaskFragment taskFragment) {
-            if (!mOrganizedTaskFragments.contains(taskFragment)) {
-                mOrganizedTaskFragments.add(taskFragment);
+        /**
+         * @return {@code true} if taskFragment is organized and not sent the appeared event before.
+         */
+        boolean addTaskFragment(TaskFragment taskFragment) {
+            if (taskFragment.mTaskFragmentAppearedSent) {
+                return false;
             }
+            if (mOrganizedTaskFragments.contains(taskFragment)) {
+                return false;
+            }
+            mOrganizedTaskFragments.add(taskFragment);
+            return true;
         }
 
         void removeTaskFragment(TaskFragment taskFragment) {
@@ -100,6 +117,79 @@
             mOrganizedTaskFragments.clear();
             mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
         }
+
+        void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
+            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
+            final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
+                    "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
+            try {
+                organizer.onTaskFragmentAppeared(
+                        new TaskFragmentAppearedInfo(info, outSurfaceControl));
+                mLastSentTaskFragmentInfos.put(tf, info);
+                tf.mTaskFragmentAppearedSent = true;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
+            }
+            onTaskFragmentParentInfoChanged(organizer, tf);
+        }
+
+        void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
+            try {
+                organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
+            }
+            tf.mTaskFragmentAppearedSent = false;
+            mLastSentTaskFragmentInfos.remove(tf);
+            mLastSentTaskFragmentParentConfigs.remove(tf);
+        }
+
+        void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+            // Parent config may have changed. The controller will check if there is any important
+            // config change for the organizer.
+            onTaskFragmentParentInfoChanged(organizer, tf);
+
+            // Check if the info is different from the last reported info.
+            final TaskFragmentInfo info = tf.getTaskFragmentInfo();
+            final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
+            if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
+                    info.getConfiguration(), lastInfo.getConfiguration())) {
+                return;
+            }
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s",
+                    tf.getName());
+            try {
+                organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
+                mLastSentTaskFragmentInfos.put(tf, info);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
+            }
+        }
+
+        void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
+            // Check if the parent info is different from the last reported parent info.
+            if (tf.getParent() == null || tf.getParent().asTask() == null) {
+                mLastSentTaskFragmentParentConfigs.remove(tf);
+                return;
+            }
+            final Task parent = tf.getParent().asTask();
+            final Configuration parentConfig = parent.getConfiguration();
+            final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
+            if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
+                return;
+            }
+            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                    "TaskFragment parent info changed name=%s parentTaskId=%d",
+                    tf.getName(), parent.mTaskId);
+            try {
+                organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
+                mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
+            }
+        }
     }
 
     @Override
@@ -110,18 +200,18 @@
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
                     "Register task fragment organizer=%s uid=%d pid=%d",
                     organizer.asBinder(), uid, pid);
-            if (mTaskFragmentOrganizerControllers.containsKey(organizer.asBinder())) {
+            if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) {
                 throw new IllegalStateException(
                         "Replacing existing organizer currently unsupported");
             }
-            mTaskFragmentOrganizerControllers.put(organizer.asBinder(),
-                    new TaskFragmentController(organizer));
+            mTaskFragmentOrganizerState.put(organizer.asBinder(),
+                    new TaskFragmentOrganizerState(organizer));
         }
     }
 
     @Override
     public void unregisterOrganizer(ITaskFragmentOrganizer organizer) {
-        validateAndGetController(organizer);
+        validateAndGetState(organizer);
         final int pid = Binder.getCallingPid();
         final long uid = Binder.getCallingUid();
         synchronized (mGlobalLock) {
@@ -132,88 +222,78 @@
         }
     }
 
-    void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment tf) {
-        final TaskFragmentController controller = validateAndGetController(organizer);
-
-        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment appeared name=%s", tf.getName());
-        final TaskFragmentInfo info = tf.getTaskFragmentInfo();
-        final SurfaceControl outSurfaceControl = new SurfaceControl(tf.getSurfaceControl(),
-                "TaskFragmentOrganizerController.onTaskFragmentInfoAppeared");
-        controller.addTaskFragment(tf);
-        try {
-            organizer.onTaskFragmentAppeared(
-                    new TaskFragmentAppearedInfo(info, outSurfaceControl));
-            mLastSentTaskFragmentInfos.put(tf, info);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
+    void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
+        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
+        if (!state.addTaskFragment(taskFragment)) {
+            return;
+        }
+        PendingTaskFragmentEvent pendingEvent = getPendingTaskFragmentEvent(taskFragment,
+                PendingTaskFragmentEvent.EVENT_APPEARED);
+        if (pendingEvent == null) {
+            pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer,
+                    PendingTaskFragmentEvent.EVENT_APPEARED);
+            mPendingTaskFragmentEvents.add(pendingEvent);
         }
     }
 
-    void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
-        validateAndGetController(organizer);
-
-        // Check if the info is different from the last reported info.
-        final TaskFragmentInfo info = tf.getTaskFragmentInfo();
-        final TaskFragmentInfo lastInfo = mLastSentTaskFragmentInfos.get(tf);
-        if (info.equalsForTaskFragmentOrganizer(lastInfo) && configurationsAreEqualForOrganizer(
-                info.getConfiguration(), lastInfo.getConfiguration())) {
-            return;
-        }
-
-        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment info changed name=%s", tf.getName());
-        try {
-            organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
-            mLastSentTaskFragmentInfos.put(tf, info);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
-        }
+    void onTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
+        handleTaskFragmentInfoChanged(organizer, taskFragment,
+                PendingTaskFragmentEvent.EVENT_INFO_CHANGED);
     }
 
-    void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment tf) {
-        final TaskFragmentController controller = validateAndGetController(organizer);
-
-        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "TaskFragment vanished name=%s", tf.getName());
-        try {
-            organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
-        }
-        mLastSentTaskFragmentInfos.remove(tf);
-        mLastSentTaskFragmentParentConfigs.remove(tf);
-        controller.removeTaskFragment(tf);
+    void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer,
+            TaskFragment taskFragment) {
+        handleTaskFragmentInfoChanged(organizer, taskFragment,
+                PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED);
     }
 
-    void onTaskFragmentParentInfoChanged(ITaskFragmentOrganizer organizer, TaskFragment tf) {
-        validateAndGetController(organizer);
-
-        // Check if the parent info is different from the last reported parent info.
-        if (tf.getParent() == null || tf.getParent().asTask() == null) {
-            mLastSentTaskFragmentParentConfigs.remove(tf);
+    private void handleTaskFragmentInfoChanged(ITaskFragmentOrganizer organizer,
+            TaskFragment taskFragment, int eventType) {
+        validateAndGetState(organizer);
+        if (!taskFragment.mTaskFragmentAppearedSent) {
+            // Skip if TaskFragment still not appeared.
             return;
         }
-        final Task parent = tf.getParent().asTask();
-        final Configuration parentConfig = parent.getConfiguration();
-        final Configuration lastParentConfig = mLastSentTaskFragmentParentConfigs.get(tf);
-        if (configurationsAreEqualForOrganizer(parentConfig, lastParentConfig)) {
+        PendingTaskFragmentEvent pendingEvent = getLastPendingLifecycleEvent(taskFragment);
+        if (pendingEvent == null) {
+            pendingEvent = new PendingTaskFragmentEvent(taskFragment, organizer, eventType);
+        } else {
+            if (pendingEvent.mEventType == PendingTaskFragmentEvent.EVENT_VANISHED) {
+                // Skipped the info changed event if vanished event is pending.
+                return;
+            }
+            // Remove and add for re-ordering.
+            mPendingTaskFragmentEvents.remove(pendingEvent);
+        }
+        mPendingTaskFragmentEvents.add(pendingEvent);
+    }
+
+    void onTaskFragmentVanished(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
+        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
+        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
+            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
+            if (taskFragment == entry.mTaskFragment) {
+                mPendingTaskFragmentEvents.remove(i);
+                if (entry.mEventType == PendingTaskFragmentEvent.EVENT_APPEARED) {
+                    // If taskFragment appeared callback is pending, ignore the vanished request.
+                    return;
+                }
+            }
+        }
+        if (!taskFragment.mTaskFragmentAppearedSent) {
             return;
         }
-
-        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
-                "TaskFragment parent info changed name=%s parentTaskId=%d",
-                tf.getName(), parent.mTaskId);
-        try {
-            organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
-            mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
-        }
+        PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(taskFragment,
+                organizer, PendingTaskFragmentEvent.EVENT_VANISHED);
+        mPendingTaskFragmentEvents.add(pendingEvent);
+        state.removeTaskFragment(taskFragment);
     }
 
     private void removeOrganizer(ITaskFragmentOrganizer organizer) {
-        final TaskFragmentController controller = validateAndGetController(organizer);
+        final TaskFragmentOrganizerState state = validateAndGetState(organizer);
         // remove all of the children of the organized TaskFragment
-        controller.dispose();
-        mTaskFragmentOrganizerControllers.remove(organizer.asBinder());
+        state.dispose();
+        mTaskFragmentOrganizerState.remove(organizer.asBinder());
     }
 
     /**
@@ -222,13 +302,113 @@
      * we wouldn't register {@link DeathRecipient} for the organizer, and might not remove the
      * {@link TaskFragment} after the organizer process died.
      */
-    private TaskFragmentController validateAndGetController(ITaskFragmentOrganizer organizer) {
-        final TaskFragmentController controller =
-                mTaskFragmentOrganizerControllers.get(organizer.asBinder());
-        if (controller == null) {
+    private TaskFragmentOrganizerState validateAndGetState(ITaskFragmentOrganizer organizer) {
+        final TaskFragmentOrganizerState state =
+                mTaskFragmentOrganizerState.get(organizer.asBinder());
+        if (state == null) {
             throw new IllegalArgumentException(
                     "TaskFragmentOrganizer has not been registered. Organizer=" + organizer);
         }
-        return controller;
+        return state;
+    }
+
+    /**
+     * A class to store {@link ITaskFragmentOrganizer} and its organized
+     * {@link TaskFragment TaskFragments} with different pending event request.
+     */
+    private static class PendingTaskFragmentEvent {
+        static final int EVENT_APPEARED = 0;
+        static final int EVENT_VANISHED = 1;
+        static final int EVENT_INFO_CHANGED = 2;
+        static final int EVENT_PARENT_INFO_CHANGED = 3;
+
+        @IntDef(prefix = "EVENT_", value = {
+                EVENT_APPEARED,
+                EVENT_VANISHED,
+                EVENT_INFO_CHANGED,
+                EVENT_PARENT_INFO_CHANGED
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface EventType {}
+
+        @EventType
+        final int mEventType;
+        final TaskFragment mTaskFragment;
+        final ITaskFragmentOrganizer mTaskFragmentOrg;
+
+        PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
+                @EventType int eventType) {
+            mTaskFragment = taskFragment;
+            mTaskFragmentOrg = taskFragmentOrg;
+            mEventType = eventType;
+        }
+
+        /**
+         * @return {@code true} if the pending event is related with taskFragment created, vanished
+         * and information changed.
+         */
+        boolean isLifecycleEvent() {
+            switch (mEventType) {
+                case EVENT_APPEARED:
+                case EVENT_VANISHED:
+                case EVENT_INFO_CHANGED:
+                case EVENT_PARENT_INFO_CHANGED:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+    }
+
+    @Nullable
+    private PendingTaskFragmentEvent getLastPendingLifecycleEvent(TaskFragment tf) {
+        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
+            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
+            if (tf == entry.mTaskFragment && entry.isLifecycleEvent()) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private PendingTaskFragmentEvent getPendingTaskFragmentEvent(TaskFragment taskFragment,
+            int type) {
+        for (int i = mPendingTaskFragmentEvents.size() - 1; i >= 0; i--) {
+            PendingTaskFragmentEvent entry = mPendingTaskFragmentEvents.get(i);
+            if (taskFragment == entry.mTaskFragment && type == entry.mEventType) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    void dispatchPendingEvents() {
+        if (mAtmService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
+                || mPendingTaskFragmentEvents.isEmpty()) {
+            return;
+        }
+        for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) {
+            PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i);
+            final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg;
+            final TaskFragment taskFragment = event.mTaskFragment;
+            final TaskFragmentOrganizerState state =
+                    mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder());
+            if (state == null) continue;
+            switch (event.mEventType) {
+                case PendingTaskFragmentEvent.EVENT_APPEARED:
+                    state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment);
+                    break;
+                case PendingTaskFragmentEvent.EVENT_VANISHED:
+                    state.onTaskFragmentVanished(taskFragmentOrg, taskFragment);
+                    break;
+                case PendingTaskFragmentEvent.EVENT_INFO_CHANGED:
+                    state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment);
+                    break;
+                case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
+                    state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
+            }
+        }
+        mPendingTaskFragmentEvents.clear();
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4fa3aab..ffd89d3 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -54,6 +54,7 @@
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.IDisplayAreaOrganizerController;
+import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskFragmentOrganizerController;
 import android.window.ITaskOrganizerController;
 import android.window.ITransitionPlayer;
@@ -110,7 +111,7 @@
     final TransitionController mTransitionController;
     /**
      * A Map which manages the relationship between
-     * {@link TaskFragmentCreationParams.mFragmentToken fragmentToken} and {@link TaskFragment}
+     * {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment}
      */
     private final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
 
@@ -139,10 +140,10 @@
 
     @Override
     public void applyTransaction(WindowContainerTransaction t) {
-        enforceTaskPermission("applyTransaction()");
         if (t == null) {
-            throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
+            throw new IllegalArgumentException("Null transaction passed to applyTransaction");
         }
+        enforceTaskPermission("applyTransaction()", t);
         final CallerInfo caller = new CallerInfo();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -157,10 +158,10 @@
     @Override
     public int applySyncTransaction(WindowContainerTransaction t,
             IWindowContainerTransactionCallback callback) {
-        enforceTaskPermission("applySyncTransaction()");
         if (t == null) {
             throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
         }
+        enforceTaskPermission("applySyncTransaction()", t);
         final CallerInfo caller = new CallerInfo();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -620,7 +621,9 @@
                 break;
             case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
                 final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
-                final WindowContainer newParent = WindowContainer.fromBinder(hop.getNewParent());
+                final WindowContainer newParent = hop.getNewParent() != null
+                        ? WindowContainer.fromBinder(hop.getNewParent())
+                        : null;
                 if (oldParent == null || !oldParent.isAttached()) {
                     Slog.e(TAG, "Attempt to operate on unknown or detached container: "
                             + oldParent);
@@ -906,6 +909,102 @@
         mService.enforceTaskPermission(func);
     }
 
+    private void enforceTaskPermission(String func, WindowContainerTransaction t) {
+        if (t == null || t.getTaskFragmentOrganizer() == null) {
+            enforceTaskPermission(func);
+            return;
+        }
+
+        // Apps may not have the permission to manage Tasks, but we are allowing apps to manage
+        // TaskFragments belonging to their own Task.
+        enforceOperationsAllowedForTaskFragmentOrganizer(func, t);
+    }
+
+    /**
+     * Makes sure that the transaction only contains operations that are allowed for the
+     * {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
+     */
+    private void enforceOperationsAllowedForTaskFragmentOrganizer(
+            String func, WindowContainerTransaction t) {
+        final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer();
+
+        // Configuration changes
+        final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
+                t.getChanges().entrySet().iterator();
+        while (entries.hasNext()) {
+            final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
+            // Only allow to apply changes to TaskFragment that is created by this organizer.
+            enforceTaskFragmentOrganized(func, WindowContainer.fromBinder(entry.getKey()),
+                    organizer);
+        }
+
+        // Hierarchy changes
+        final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
+        for (int i = hops.size() - 1; i >= 0; i--) {
+            final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
+            final int type = hop.getType();
+            // Check for each type of the operations that are allowed for TaskFragmentOrganizer.
+            switch (type) {
+                case HIERARCHY_OP_TYPE_REORDER:
+                case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
+                    enforceTaskFragmentOrganized(func,
+                            WindowContainer.fromBinder(hop.getContainer()), organizer);
+                    break;
+                case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
+                    enforceTaskFragmentOrganized(func,
+                            WindowContainer.fromBinder(hop.getContainer()), organizer);
+                    enforceTaskFragmentOrganized(func,
+                            WindowContainer.fromBinder(hop.getAdjacentRoot()),
+                            organizer);
+                    break;
+                case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
+                    // We are allowing organizer to create TaskFragment. We will check the
+                    // ownerToken in #createTaskFragment, and trigger error callback if that is not
+                    // valid.
+                case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
+                case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
+                    // We are allowing organizer to start/reparent activity to a TaskFragment it
+                    // created. Nothing to check here because the TaskFragment may not be created
+                    // yet, but will be created in the same transaction.
+                    break;
+                case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
+                    enforceTaskFragmentOrganized(func,
+                            WindowContainer.fromBinder(hop.getContainer()), organizer);
+                    if (hop.getNewParent() != null) {
+                        enforceTaskFragmentOrganized(func,
+                                WindowContainer.fromBinder(hop.getNewParent()),
+                                organizer);
+                    }
+                    break;
+                default:
+                    // Other types of hierarchy changes are not allowed.
+                    String msg = "Permission Denial: " + func + " from pid="
+                            + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                            + " trying to apply a hierarchy change that is not allowed for"
+                            + " TaskFragmentOrganizer=" + organizer;
+                    Slog.w(TAG, msg);
+                    throw new SecurityException(msg);
+            }
+        }
+    }
+
+    private void enforceTaskFragmentOrganized(String func, @Nullable WindowContainer wc,
+            ITaskFragmentOrganizer organizer) {
+        if (wc == null) {
+            Slog.e(TAG, "Attempt to operate on window that no longer exists");
+            return;
+        }
+
+        final TaskFragment tf = wc.asTaskFragment();
+        if (tf == null || !tf.hasTaskFragmentOrganizer(organizer)) {
+            String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid() + " trying to modify window container not"
+                    + " belonging to the TaskFragmentOrganizer=" + organizer;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+    }
+
     void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
         final ActivityRecord ownerActivity =
                 ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
index 46f9636..a06a782 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java
@@ -90,7 +90,8 @@
                 @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
                 @NonNull ClientMonitorCallbackConverter callback) {
             super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */,
-                    TEST_SENSOR_ID /* sensorId */, 0 /* statsModality */, 0 /* statsAction */,
+                    TEST_SENSOR_ID /* sensorId */, true /* shouldVibrate */, 0 /* statsModality */,
+                    0 /* statsAction */,
                     0 /* statsClient */);
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 4d1f241..109fb225 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -359,7 +359,7 @@
                     false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
                     TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
                     0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
-                    false /* isKeyguard */);
+                    false /* isKeyguard */, true /* shouldVibrate */);
         }
 
         @Override
@@ -382,7 +382,7 @@
                     false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
                     TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
                     0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class),
-                    false /* isKeyguard */);
+                    false /* isKeyguard */, true /* shouldVibrate */);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
index 9f0cdd5..225f5b3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -31,6 +31,8 @@
 import com.android.server.hdmi.HdmiUtils.CodecSad;
 import com.android.server.hdmi.HdmiUtils.DeviceConfig;
 
+import com.google.common.testing.EqualsTester;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -116,6 +118,22 @@
     }
 
     @Test
+    public void testEqualsCodecSad() {
+        byte[] sad = {0x0a, 0x1b, 0x2c};
+        String sadString = "0a1b2c";
+        new EqualsTester()
+                .addEqualityGroup(
+                        new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sad),
+                        new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sadString))
+                .addEqualityGroup(
+                        new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_LPCM, sadString + "01"))
+                .addEqualityGroup(new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_DD, sadString))
+                .addEqualityGroup(
+                        new HdmiUtils.CodecSad(Constants.AUDIO_CODEC_DD, sadString + "01"))
+                .testEquals();
+    }
+
+    @Test
     public void parseSampleXML() {
         List<DeviceConfig> config = new ArrayList<>();
         try {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index c4faaa3..9d351f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -57,6 +57,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 import android.view.View;
@@ -556,6 +557,7 @@
         final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(
                 mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST);
         final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
+        doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
         displayArea.mOrganizer = mockDisplayAreaOrganizer;
         spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController);
         mDisplayContent.addChild(displayArea, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 6bd8ad2..ac981cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -22,6 +22,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.testing.Assert.assertThrows;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -29,7 +31,9 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
+import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -37,8 +41,12 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizer;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
 
 import androidx.test.filters.SmallTest;
 
@@ -61,18 +69,24 @@
     private TaskFragment mTaskFragment;
     private TaskFragmentInfo mTaskFragmentInfo;
     private IBinder mFragmentToken;
+    private WindowContainerTransaction mTransaction;
+    private WindowContainerToken mFragmentWindowToken;
 
     @Before
     public void setup() {
         mController = mWm.mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
         mOrganizer = new TaskFragmentOrganizer(Runnable::run);
         mIOrganizer = mOrganizer.getIOrganizer();
-        mTaskFragment = mock(TaskFragment.class);
         mTaskFragmentInfo = mock(TaskFragmentInfo.class);
         mFragmentToken = new Binder();
+        mTaskFragment =
+                new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
+        mTransaction = new WindowContainerTransaction();
+        mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
 
         spyOn(mController);
         spyOn(mOrganizer);
+        spyOn(mTaskFragment);
         doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer();
         doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo();
         doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl();
@@ -102,6 +116,7 @@
         mController.registerOrganizer(mIOrganizer);
 
         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer).onTaskFragmentAppeared(any());
     }
@@ -110,6 +125,7 @@
     public void testOnTaskFragmentInfoChanged() {
         mController.registerOrganizer(mIOrganizer);
         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         // No callback if the info is not changed.
         doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
@@ -117,6 +133,7 @@
 
         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
                 mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
 
@@ -125,6 +142,7 @@
 
         mController.onTaskFragmentInfoChanged(mTaskFragment.getTaskFragmentOrganizer(),
                 mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo);
     }
@@ -133,7 +151,9 @@
     public void testOnTaskFragmentVanished() {
         mController.registerOrganizer(mIOrganizer);
 
+        mTaskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer).onTaskFragmentVanished(any());
     }
@@ -148,8 +168,10 @@
         doReturn(parentConfig).when(parent).getConfiguration();
         doReturn(parent).when(parent).asTask();
 
+        mTaskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentParentInfoChanged(
                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
 
@@ -158,6 +180,7 @@
 
         mController.onTaskFragmentParentInfoChanged(
                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), any());
 
@@ -166,6 +189,7 @@
 
         mController.onTaskFragmentParentInfoChanged(
                 mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
 
         verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mFragmentToken), any());
     }
@@ -180,4 +204,156 @@
 
         verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
     }
+
+    @Test
+    public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
+        mOrganizer.applyTransaction(mTransaction);
+
+        assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
+
+        mTransaction = new WindowContainerTransaction();
+        mOrganizer.applySyncTransaction(
+                mTransaction, mock(WindowContainerTransactionCallback.class));
+
+        assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
+    }
+
+    @Test
+    public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment()
+            throws RemoteException {
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Throw exception if the transaction is trying to change a window that is not organized by
+        // the organizer.
+        mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
+
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+
+        // Allow transaction to change a TaskFragment created by the organizer.
+        mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+    }
+
+    @Test
+    public void testApplyTransaction_enforceHierarchyChange_reorder() throws RemoteException {
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Throw exception if the transaction is trying to change a window that is not organized by
+        // the organizer.
+        mTransaction.reorder(mFragmentWindowToken, true /* onTop */);
+
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+
+        // Allow transaction to change a TaskFragment created by the organizer.
+        mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+    }
+
+    @Test
+    public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()
+            throws RemoteException {
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Throw exception if the transaction is trying to change a window that is not organized by
+        // the organizer.
+        mTransaction.deleteTaskFragment(mFragmentWindowToken);
+
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+
+        // Allow transaction to change a TaskFragment created by the organizer.
+        mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+    }
+
+    @Test
+    public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots()
+            throws RemoteException {
+        final TaskFragment taskFragment2 =
+                new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
+        final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Throw exception if the transaction is trying to change a window that is not organized by
+        // the organizer.
+        mTransaction.setAdjacentRoots(mFragmentWindowToken, token2);
+
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+
+        // Allow transaction to change a TaskFragment created by the organizer.
+        mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+        taskFragment2.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+    }
+
+    @Test
+    public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
+        mTransaction.createTaskFragment(mock(TaskFragmentCreationParams.class));
+        mTransaction.startActivityInTaskFragment(
+                mFragmentToken, new Intent(), null /* activityOptions */);
+        mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
+
+        // It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
+        // testing the security check here.
+        assertThrows(IllegalArgumentException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+    }
+
+    @Test
+    public void testApplyTransaction_enforceHierarchyChange_reparentChildren()
+            throws RemoteException {
+        mOrganizer.applyTransaction(mTransaction);
+
+        // Throw exception if the transaction is trying to change a window that is not organized by
+        // the organizer.
+        mTransaction.reparentChildren(mFragmentWindowToken, null /* newParent */);
+
+        assertThrows(SecurityException.class, () -> {
+            try {
+                mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+            } catch (RemoteException e) {
+                fail();
+            }
+        });
+
+        // Allow transaction to change a TaskFragment created by the organizer.
+        mTaskFragment.setTaskFragmentOrganizer(mIOrganizer, 10 /* pid */);
+
+        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+    }
 }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a427ed61..02bd001 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -139,6 +139,8 @@
      */
     private final int mTargetSdkVersion;
 
+    private final Object mLock = new Object();
+
     Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
         mInCallAdapter = adapter;
         mCallingPackage = callingPackage;
@@ -156,8 +158,12 @@
         if (call == null) {
             call = new Call(this, parcelableCall.getId(), mInCallAdapter,
                     parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
-            mCallByTelecomCallId.put(parcelableCall.getId(), call);
-            mCalls.add(call);
+
+            synchronized (mLock) {
+                mCallByTelecomCallId.put(parcelableCall.getId(), call);
+                mCalls.add(call);
+            }
+
             checkCallTree(parcelableCall);
             call.internalUpdate(parcelableCall, mCallByTelecomCallId);
             fireCallAdded(call);
@@ -169,8 +175,10 @@
     }
 
     final void internalRemoveCall(Call call) {
-        mCallByTelecomCallId.remove(call.internalGetCallId());
-        mCalls.remove(call);
+        synchronized (mLock) {
+            mCallByTelecomCallId.remove(call.internalGetCallId());
+            mCalls.remove(call);
+        }
 
         InCallService.VideoCall videoCall = call.getVideoCall();
         if (videoCall != null) {
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 1252965..3c799e0 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -26,7 +26,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.telephony.TelephonyManager;
 
@@ -74,11 +73,6 @@
         return cur == null ? Collections.emptyList() : cur;
     }
 
-    /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */
-    public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
-        throw new RuntimeException(remoteException);
-    }
-
     /**
      * Returns a {@link ComponentInfo} from the {@link ResolveInfo},
      * or throws an {@link IllegalStateException} if not available.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9954de2..f01519f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -286,6 +286,21 @@
             "call_barring_default_service_class_int";
 
     /**
+     * This carrier supports dialing USSD codes to enable/disable supplementary services such as
+     * call forwarding and call waiting over CDMA.
+     * <p>
+     * The supplementary service menu will still need to be set as visible, see
+     * {@link #KEY_CALL_FORWARDING_VISIBILITY_BOOL} and
+     * {@link #KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL}.
+     * <p>
+     * If this is set as false and the supplementary service menu is visible, the associated setting
+     * will be enabled and disabled based on the availability of supplementary services over UT. See
+     * {@link #KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL}.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_SS_OVER_CDMA_BOOL = "support_ss_over_cdma_bool";
+
+    /**
      * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
      * events from the Sim.
      * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -5120,6 +5135,7 @@
         sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
         sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
         sDefaults.putInt(KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, SERVICE_CLASS_VOICE);
+        sDefaults.putBoolean(KEY_SUPPORT_SS_OVER_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL, true);
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index b7a6d0f..7c7dc4d 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -23,6 +23,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
 
@@ -50,6 +51,7 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.annotation.NonNull;
@@ -99,6 +101,7 @@
 import org.mockito.ArgumentCaptor;
 
 import java.io.FileNotFoundException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -227,6 +230,7 @@
 
         setupMockedCarrierPrivilege(true);
         mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+        setupActiveSubscription(TEST_UUID_1);
 
         doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
         doReturn(mMockIBinder).when(mMockStatusCallback).asBinder();
@@ -300,23 +304,65 @@
     }
 
     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
-            Set<ParcelUuid> activeSubscriptionGroups) {
+            ParcelUuid activeDataSubGrp, Set<ParcelUuid> activeSubscriptionGroups) {
         return triggerSubscriptionTrackerCbAndGetSnapshot(
-                activeSubscriptionGroups, Collections.emptyMap());
+                activeDataSubGrp, activeSubscriptionGroups, Collections.emptyMap());
     }
 
     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
-            Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
+            ParcelUuid activeDataSubGrp,
+            Set<ParcelUuid> activeSubscriptionGroups,
+            Map<Integer, ParcelUuid> subIdToGroupMap) {
         return triggerSubscriptionTrackerCbAndGetSnapshot(
-                activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */);
+                activeDataSubGrp,
+                activeSubscriptionGroups,
+                subIdToGroupMap,
+                true /* hasCarrierPrivileges */);
     }
 
     private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+            ParcelUuid activeDataSubGrp,
+            Set<ParcelUuid> activeSubscriptionGroups,
+            Map<Integer, ParcelUuid> subIdToGroupMap,
+            boolean hasCarrierPrivileges) {
+        return triggerSubscriptionTrackerCbAndGetSnapshot(
+                TEST_SUBSCRIPTION_ID,
+                activeDataSubGrp,
+                activeSubscriptionGroups,
+                subIdToGroupMap,
+                hasCarrierPrivileges);
+    }
+
+    private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+            int activeDataSubId,
+            ParcelUuid activeDataSubGrp,
+            Set<ParcelUuid> activeSubscriptionGroups,
+            Map<Integer, ParcelUuid> subIdToGroupMap,
+            boolean hasCarrierPrivileges) {
+        final TelephonySubscriptionSnapshot snapshot =
+                buildSubscriptionSnapshot(
+                        activeDataSubId,
+                        activeDataSubGrp,
+                        activeSubscriptionGroups,
+                        subIdToGroupMap,
+                        hasCarrierPrivileges);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        cb.onNewSnapshot(snapshot);
+
+        return snapshot;
+    }
+
+    private TelephonySubscriptionSnapshot buildSubscriptionSnapshot(
+            int activeDataSubId,
+            ParcelUuid activeDataSubGrp,
             Set<ParcelUuid> activeSubscriptionGroups,
             Map<Integer, ParcelUuid> subIdToGroupMap,
             boolean hasCarrierPrivileges) {
         final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
         doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
+        doReturn(activeDataSubGrp).when(snapshot).getActiveDataSubscriptionGroup();
+        doReturn(activeDataSubId).when(snapshot).getActiveDataSubscriptionId();
 
         final Set<String> privilegedPackages =
                 (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
@@ -343,12 +389,19 @@
             return subIds;
         }).when(snapshot).getAllSubIdsInGroup(any());
 
-        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
-        cb.onNewSnapshot(snapshot);
-
         return snapshot;
     }
 
+    private void setupActiveSubscription(ParcelUuid activeDataSubGrp) {
+        mVcnMgmtSvc.setLastSnapshot(
+                buildSubscriptionSnapshot(
+                        TEST_SUBSCRIPTION_ID,
+                        activeDataSubGrp,
+                        Collections.emptySet(),
+                        Collections.emptyMap(),
+                        true /* hasCarrierPrivileges */));
+    }
+
     private TelephonySubscriptionTrackerCallback getTelephonySubscriptionTrackerCallback() {
         final ArgumentCaptor<TelephonySubscriptionTrackerCallback> captor =
                 ArgumentCaptor.forClass(TelephonySubscriptionTrackerCallback.class);
@@ -372,25 +425,56 @@
 
     @Test
     public void testTelephonyNetworkTrackerCallbackStartsInstances() throws Exception {
+        // Add a record for a non-active SIM
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
         TelephonySubscriptionSnapshot snapshot =
-                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        TEST_UUID_1, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
         verify(mMockDeps)
                 .newVcnContext(
                         eq(mMockContext),
                         eq(mTestLooper.getLooper()),
                         any(VcnNetworkProvider.class),
                         anyBoolean());
+
+        // Verify that only the VCN for the active data SIM was started.
         verify(mMockDeps)
                 .newVcn(eq(mVcnContext), eq(TEST_UUID_1), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+        verify(mMockDeps, never())
+                .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+    }
+
+    @Test
+    public void testTelephonyNetworkTrackerCallbackSwitchingActiveDataStartsAndStopsInstances()
+            throws Exception {
+        // Add a record for a non-active SIM
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+        TelephonySubscriptionSnapshot snapshot =
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        TEST_UUID_2, new ArraySet<>(Arrays.asList(TEST_UUID_1, TEST_UUID_2)));
+
+        // Verify that a new VCN for UUID_2 was started, and the old instance was torn down
+        // immediately
+        verify(mMockDeps)
+                .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), eq(snapshot), any());
+        verify(vcn).teardownAsynchronously();
+        assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+        assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+        assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
     }
 
     @Test
     public void testTelephonyNetworkTrackerCallbackStopsInstances() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
 
         // Verify teardown after delay
         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -400,19 +484,76 @@
     }
 
     @Test
+    public void testTelephonyNetworkTrackerCallbackSwitchToNewSubscriptionImmediatelyTearsDown()
+            throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Simulate switch to different default data subscription that does not have a VCN.
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                TEST_SUBSCRIPTION_ID,
+                null /* activeDataSubscriptionGroup */,
+                Collections.emptySet(),
+                Collections.emptyMap(),
+                false /* hasCarrierPrivileges */);
+        mTestLooper.dispatchAll();
+
+        verify(vcn).teardownAsynchronously();
+        assertEquals(0, mVcnMgmtSvc.getAllVcns().size());
+    }
+
+    /**
+     * Tests an intermediate state where carrier privileges are marked as lost before active data
+     * subId changes during a SIM ejection.
+     *
+     * <p>The expected outcome is that the VCN is torn down after a delay, as opposed to
+     * immediately.
+     */
+    @Test
+    public void testTelephonyNetworkTrackerCallbackLostCarrierPrivilegesBeforeActiveDataSubChanges()
+            throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
+        final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
+
+        // Simulate privileges lost
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                TEST_SUBSCRIPTION_ID,
+                TEST_UUID_2,
+                Collections.emptySet(),
+                Collections.emptyMap(),
+                false /* hasCarrierPrivileges */);
+
+        // Verify teardown after delay
+        mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+        mTestLooper.dispatchAll();
+        verify(vcn).teardownAsynchronously();
+    }
+
+    @Test
     public void testTelephonyNetworkTrackerCallbackSimSwitchesDoNotKillVcnInstances()
             throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         final Vcn vcn = startAndGetVcnInstance(TEST_UUID_2);
 
         // Simulate SIM unloaded
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(
+                INVALID_SUBSCRIPTION_ID,
+                null /* activeDataSubscriptionGroup */,
+                Collections.emptySet(),
+                Collections.emptyMap(),
+                false /* hasCarrierPrivileges */);
 
         // Simulate new SIM loaded right during teardown delay.
         mTestLooper.moveTimeForward(
                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
         mTestLooper.dispatchAll();
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
 
         // Verify that even after the full timeout duration, the VCN instance is not torn down
         mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
@@ -422,11 +563,13 @@
 
     @Test
     public void testTelephonyNetworkTrackerCallbackDoesNotKillNewVcnInstances() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         final TelephonySubscriptionTrackerCallback cb = getTelephonySubscriptionTrackerCallback();
         final Vcn oldInstance = startAndGetVcnInstance(TEST_UUID_2);
 
         // Simulate SIM unloaded
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.emptySet());
+        triggerSubscriptionTrackerCbAndGetSnapshot(null, Collections.emptySet());
 
         // Config cleared, SIM reloaded & config re-added right before teardown delay, staring new
         // vcnInstance.
@@ -434,6 +577,7 @@
                 VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
         mTestLooper.dispatchAll();
         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
         final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
 
         // Verify that new instance was different, and the old one was torn down
@@ -538,6 +682,31 @@
     }
 
     @Test
+    public void testSetVcnConfigNonActiveSimDoesNotStartVcn() throws Exception {
+        // Use a different UUID to simulate a new VCN config.
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+        assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+        verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+
+        verify(mMockDeps, never()).newVcn(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    public void testSetVcnConfigActiveSimTearsDownExistingVcnsImmediately() throws Exception {
+        final Vcn vcn = startAndGetVcnInstance(TEST_UUID_1);
+
+        // Use a different UUID to simulate a new VCN config.
+        setupActiveSubscription(TEST_UUID_2);
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+
+        verify(mMockDeps, times(2)).newVcn(any(), any(), any(), any(), any());
+        verify(vcn).teardownAsynchronously();
+        assertEquals(1, mVcnMgmtSvc.getAllVcns().size());
+        assertFalse(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_1));
+        assertTrue(mVcnMgmtSvc.getAllVcns().containsKey(TEST_UUID_2));
+    }
+
+    @Test
     public void testSetVcnConfigTestModeRequiresPermission() throws Exception {
         doThrow(new SecurityException("Requires MANAGE_TEST_NETWORKS"))
                 .when(mMockContext)
@@ -561,7 +730,7 @@
 
     @Test
     public void testSetVcnConfigNotifiesStatusCallback() throws Exception {
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_2, Collections.singleton(TEST_UUID_2));
 
         mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
         verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
@@ -635,7 +804,9 @@
     }
 
     @Test
-    public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception {
+    public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTearsDownVcns() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         // Use a different UUID to simulate a new VCN config.
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
@@ -646,12 +817,7 @@
 
         // Verify Vcn is started
         verify(mMockDeps)
-                .newVcn(
-                        eq(mVcnContext),
-                        eq(TEST_UUID_2),
-                        eq(TEST_VCN_CONFIG),
-                        eq(TelephonySubscriptionSnapshot.EMPTY_SNAPSHOT),
-                        any());
+                .newVcn(eq(mVcnContext), eq(TEST_UUID_2), eq(TEST_VCN_CONFIG), any(), any());
 
         // Verify Vcn is updated if it was previously started
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -693,7 +859,7 @@
 
         // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
         // privileged for.
-        triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+        triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
         final List<ParcelUuid> subGrps =
                 mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
         assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
@@ -760,6 +926,7 @@
             int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
         mVcnMgmtSvc.systemReady();
         triggerSubscriptionTrackerCbAndGetSnapshot(
+                subGrp,
                 Collections.singleton(subGrp),
                 Collections.singletonMap(subId, subGrp),
                 hasCarrierPrivileges);
@@ -927,18 +1094,23 @@
 
     @Test
     public void testSubscriptionSnapshotUpdateNotifiesVcn() {
+        setupActiveSubscription(TEST_UUID_2);
+
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
         final Map<ParcelUuid, Vcn> vcnInstances = mVcnMgmtSvc.getAllVcns();
         final Vcn vcnInstance = vcnInstances.get(TEST_UUID_2);
 
         TelephonySubscriptionSnapshot snapshot =
-                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2));
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        TEST_UUID_2, Collections.singleton(TEST_UUID_2));
 
         verify(vcnInstance).updateSubscriptionSnapshot(eq(snapshot));
     }
 
     @Test
     public void testAddNewVcnUpdatesPolicyListener() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
@@ -948,6 +1120,8 @@
 
     @Test
     public void testRemoveVcnUpdatesPolicyListener() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
@@ -958,10 +1132,13 @@
 
     @Test
     public void testVcnSubIdChangeUpdatesPolicyListener() throws Exception {
+        setupActiveSubscription(TEST_UUID_2);
+
         startAndGetVcnInstance(TEST_UUID_2);
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
         triggerSubscriptionTrackerCbAndGetSnapshot(
+                TEST_UUID_2,
                 Collections.singleton(TEST_UUID_2),
                 Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_2));
 
@@ -988,7 +1165,8 @@
     private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
             throws Exception {
         TelephonySubscriptionSnapshot snapshot =
-                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        TEST_UUID_1, Collections.singleton(TEST_UUID_1));
 
         mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
 
@@ -1014,7 +1192,8 @@
             boolean hasPermissionsforSubGroup)
             throws Exception {
         TelephonySubscriptionSnapshot snapshot =
-                triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
+                triggerSubscriptionTrackerCbAndGetSnapshot(
+                        subGroup, Collections.singleton(subGroup));
 
         setupSubscriptionAndStartVcn(
                 TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
@@ -1089,6 +1268,7 @@
         // timeout so the VCN goes inactive.
         final TelephonySubscriptionSnapshot snapshot =
                 triggerSubscriptionTrackerCbAndGetSnapshot(
+                        TEST_UUID_1,
                         Collections.singleton(TEST_UUID_1),
                         Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
                         false /* hasCarrierPrivileges */);
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index ca74638..1f0df62 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -21,6 +21,7 @@
 import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -54,6 +55,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 
@@ -178,6 +180,14 @@
         return captor.getValue();
     }
 
+    private ActiveDataSubscriptionIdListener getActiveDataSubscriptionIdListener() {
+        final ArgumentCaptor<TelephonyCallback> captor =
+                ArgumentCaptor.forClass(TelephonyCallback.class);
+        verify(mTelephonyManager).registerTelephonyCallback(any(), captor.capture());
+
+        return (ActiveDataSubscriptionIdListener) captor.getValue();
+    }
+
     private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
         Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
         intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
@@ -196,7 +206,14 @@
     private TelephonySubscriptionSnapshot buildExpectedSnapshot(
             Map<Integer, SubscriptionInfo> subIdToInfoMap,
             Map<ParcelUuid, Set<String>> privilegedPackages) {
-        return new TelephonySubscriptionSnapshot(subIdToInfoMap, privilegedPackages);
+        return new TelephonySubscriptionSnapshot(0, subIdToInfoMap, privilegedPackages);
+    }
+
+    private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+            int activeSubId,
+            Map<Integer, SubscriptionInfo> subIdToInfoMap,
+            Map<ParcelUuid, Set<String>> privilegedPackages) {
+        return new TelephonySubscriptionSnapshot(activeSubId, subIdToInfoMap, privilegedPackages);
     }
 
     private void verifyNoActiveSubscriptions() {
@@ -250,6 +267,26 @@
     }
 
     @Test
+    public void testOnSubscriptionsChangedFired_onActiveSubIdsChanged() throws Exception {
+        setupReadySubIds();
+        setPrivilegedPackagesForMock(Collections.emptyList());
+
+        doReturn(TEST_SUBSCRIPTION_ID_2).when(mDeps).getActiveDataSubscriptionId();
+        final ActiveDataSubscriptionIdListener listener = getActiveDataSubscriptionIdListener();
+        listener.onActiveDataSubscriptionIdChanged(TEST_SUBSCRIPTION_ID_2);
+        mTestLooper.dispatchAll();
+
+        ArgumentCaptor<TelephonySubscriptionSnapshot> snapshotCaptor =
+                ArgumentCaptor.forClass(TelephonySubscriptionSnapshot.class);
+        verify(mCallback).onNewSnapshot(snapshotCaptor.capture());
+
+        TelephonySubscriptionSnapshot snapshot = snapshotCaptor.getValue();
+        assertNotNull(snapshot);
+        assertEquals(TEST_SUBSCRIPTION_ID_2, snapshot.getActiveDataSubscriptionId());
+        assertEquals(TEST_PARCEL_UUID, snapshot.getActiveDataSubscriptionGroup());
+    }
+
+    @Test
     public void testOnSubscriptionsChangedFired_WithReadySubidsNoPrivilegedPackages()
             throws Exception {
         setupReadySubIds();
@@ -371,7 +408,8 @@
     @Test
     public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
         final TelephonySubscriptionSnapshot snapshot =
-                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
+                new TelephonySubscriptionSnapshot(
+                        TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
 
         assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
         assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
@@ -380,7 +418,8 @@
     @Test
     public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
         final TelephonySubscriptionSnapshot snapshot =
-                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_INFO_MAP, emptyMap());
+                new TelephonySubscriptionSnapshot(
+                        TEST_SUBSCRIPTION_ID_1, TEST_SUBID_TO_INFO_MAP, emptyMap());
 
         assertEquals(
                 new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index b97023a..a696b3a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -127,7 +127,9 @@
 
     protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
             new TelephonySubscriptionSnapshot(
-                    Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO), Collections.EMPTY_MAP);
+                    TEST_SUB_ID,
+                    Collections.singletonMap(TEST_SUB_ID, TEST_SUB_INFO),
+                    Collections.EMPTY_MAP);
 
     @NonNull protected final Context mContext;
     @NonNull protected final TestLooper mTestLooper;
diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h
index d3ca357..cabbe7e 100644
--- a/tools/aapt2/AppInfo.h
+++ b/tools/aapt2/AppInfo.h
@@ -17,11 +17,10 @@
 #ifndef AAPT_APP_INFO_H
 #define AAPT_APP_INFO_H
 
+#include <optional>
 #include <set>
 #include <string>
 
-#include "util/Maybe.h"
-
 namespace aapt {
 
 // Information relevant to building an app, parsed from the app's AndroidManifest.xml.
@@ -30,19 +29,19 @@
   std::string package;
 
   // The app's minimum SDK version, if it is defined.
-  Maybe<int> min_sdk_version;
+  std::optional<int> min_sdk_version;
 
   // The app's version code (the lower 32 bits of the long version code), if it is defined.
-  Maybe<uint32_t> version_code;
+  std::optional<uint32_t> version_code;
 
   // The app's version code major (the upper 32 bits of the long version code), if it is defined.
-  Maybe<uint32_t> version_code_major;
+  std::optional<uint32_t> version_code_major;
 
   // The app's revision code, if it is defined.
-  Maybe<uint32_t> revision_code;
+  std::optional<uint32_t> revision_code;
 
   // The app's split name, if it is a split.
-  Maybe<std::string> split_name;
+  std::optional<std::string> split_name;
 
   // The split names that this split depends on.
   std::set<std::string> split_name_dependencies;
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index ef3a62f..df444ba 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -280,8 +280,7 @@
       printer->Indent();
       for (const ResourceTableEntryView& entry : type.entries) {
         printer->Print("resource ");
-        printer->Print(ResourceId(package.id.value_or_default(0), type.id.value_or_default(0),
-                                  entry.id.value_or_default(0))
+        printer->Print(ResourceId(package.id.value_or(0), type.id.value_or(0), entry.id.value_or(0))
                            .to_string());
         printer->Print(" ");
 
@@ -362,7 +361,7 @@
       continue;
     }
 
-    Maybe<ResourceTable::SearchResult> result = table->FindResource(style_name);
+    std::optional<ResourceTable::SearchResult> result = table->FindResource(style_name);
     if (result) {
       ResourceEntry* entry = result.value().entry;
       for (const auto& value : entry->values) {
@@ -482,8 +481,7 @@
 
       if (attr.compiled_attribute) {
         printer_->Print("(");
-        printer_->Print(
-            attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
+        printer_->Print(attr.compiled_attribute.value().id.value_or(ResourceId(0)).to_string());
         printer_->Print(")");
       }
       printer_->Print("=");
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 8a43bb4..b249c6c 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -147,7 +147,7 @@
  private:
   io::FileOutputStream* out_;
   IDiagnostics* diagnostics_;
-  Maybe<std::string> trace_folder_;
+  std::optional<std::string> trace_folder_;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index f1aad29..0b49052 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -21,7 +21,6 @@
 #include <string>
 
 #include "Resource.h"
-#include "util/Maybe.h"
 
 namespace aapt {
 
@@ -44,7 +43,7 @@
  public:
   explicit NameMangler(NameManglerPolicy policy) : policy_(policy) {}
 
-  Maybe<ResourceName> MangleName(const ResourceName& name) {
+  std::optional<ResourceName> MangleName(const ResourceName& name) {
     if (policy_.target_package_name == name.package ||
         policy_.packages_to_mangle.count(name.package) == 0) {
       return {};
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index f1e2da9..f49c254 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -20,7 +20,8 @@
 #include <limits>
 #include <sstream>
 
-#include "android-base/logging.h"
+#include <android-base/logging.h>
+#include <idmap2/Policies.h>
 
 #include "ResourceTable.h"
 #include "ResourceUtils.h"
@@ -28,12 +29,10 @@
 #include "ValueVisitor.h"
 #include "text/Utf8Iterator.h"
 #include "util/ImmutableMap.h"
-#include "util/Maybe.h"
+
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 
-#include "idmap2/Policies.h"
-
 using ::aapt::ResourceUtils::StringBuilder;
 using ::aapt::text::Utf8Iterator;
 using ::android::ConfigDescription;
@@ -109,8 +108,8 @@
   Visibility::Level visibility_level = Visibility::Level::kUndefined;
   bool staged_api = false;
   bool allow_new = false;
-  Maybe<OverlayableItem> overlayable_item;
-  Maybe<StagedId> staged_alias;
+  std::optional<OverlayableItem> overlayable_item;
+  std::optional<StagedId> staged_alias;
 
   std::string comment;
   std::unique_ptr<Value> value;
@@ -252,7 +251,7 @@
   std::string current_text;
 
   // The first occurrence of a <xliff:g> tag. Nested <xliff:g> tags are illegal.
-  Maybe<size_t> untranslatable_start_depth;
+  std::optional<size_t> untranslatable_start_depth;
 
   Node root;
   std::vector<Node*> node_stack;
@@ -342,7 +341,7 @@
         }
 
         node_stack.pop_back();
-        if (untranslatable_start_depth == make_value(depth)) {
+        if (untranslatable_start_depth == depth) {
           // This is the end of an untranslatable section.
           untranslatable_start_depth = {};
         }
@@ -468,7 +467,7 @@
     }
 
     // Extract the product name if it exists.
-    if (Maybe<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) {
+    if (std::optional<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) {
       parsed_resource.product = maybe_product.value().to_string();
     }
 
@@ -560,7 +559,7 @@
     resource_format = android::ResTable_map::TYPE_ANY;
 
     // Items have their type encoded in the type attribute.
-    if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+    if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
       resource_type = maybe_type.value().to_string();
     } else {
       diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -568,7 +567,7 @@
       return false;
     }
 
-    if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) {
+    if (std::optional<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) {
       // An explicit format for this resource was specified. The resource will
       // retain its type in its name, but the accepted value for this type is
       // overridden.
@@ -584,7 +583,7 @@
     can_be_item = false;
 
     // Bags have their type encoded in the type attribute.
-    if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+    if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
       resource_type = maybe_type.value().to_string();
     } else {
       diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -595,7 +594,7 @@
 
   // Get the name of the resource. This will be checked later, because not all
   // XML elements require a name.
-  Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+  std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
 
   if (resource_type == "id") {
     if (!maybe_name) {
@@ -835,10 +834,8 @@
 bool ResourceParser::ParseString(xml::XmlPullParser* parser,
                                  ParsedResource* out_resource) {
   bool formatted = true;
-  if (Maybe<StringPiece> formatted_attr =
-          xml::FindAttribute(parser, "formatted")) {
-    Maybe<bool> maybe_formatted =
-        ResourceUtils::ParseBool(formatted_attr.value());
+  if (std::optional<StringPiece> formatted_attr = xml::FindAttribute(parser, "formatted")) {
+    std::optional<bool> maybe_formatted = ResourceUtils::ParseBool(formatted_attr.value());
     if (!maybe_formatted) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid value for 'formatted'. Must be a boolean");
@@ -848,8 +845,8 @@
   }
 
   bool translatable = options_.translatable;
-  if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
-    Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
+  if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
+    std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
     if (!maybe_translatable) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid value for 'translatable'. Must be a boolean");
@@ -929,7 +926,7 @@
                 << "ignoring configuration '" << out_resource->config << "' for <public> tag");
   }
 
-  Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+  std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
   if (!maybe_type) {
     diag_->Error(DiagMessage(out_resource->source)
                  << "<public> must have a 'type' attribute");
@@ -946,8 +943,8 @@
 
   out_resource->name.type = *parsed_type;
 
-  if (Maybe<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) {
-    Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
+  if (std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "id")) {
+    std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
     if (!maybe_id) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid resource ID '" << maybe_id_str.value() << "' in <public>");
@@ -974,7 +971,7 @@
                << "> tag");
   }
 
-  Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+  std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
   if (!maybe_type) {
     diag->Error(DiagMessage(out_resource->source)
                 << "<" << tag_name << "> must have a 'type' attribute");
@@ -988,14 +985,14 @@
     return false;
   }
 
-  Maybe<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id");
+  std::optional<StringPiece> maybe_id_str = xml::FindNonEmptyAttribute(parser, "first-id");
   if (!maybe_id_str) {
     diag->Error(DiagMessage(out_resource->source)
                 << "<" << tag_name << "> must have a 'first-id' attribute");
     return false;
   }
 
-  Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
+  std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(maybe_id_str.value());
   if (!maybe_id) {
     diag->Error(DiagMessage(out_resource->source)
                 << "invalid resource ID '" << maybe_id_str.value() << "' in <" << tag_name << ">");
@@ -1090,7 +1087,7 @@
 
 bool ResourceParser::ParseSymbolImpl(xml::XmlPullParser* parser,
                                      ParsedResource* out_resource) {
-  Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+  std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
   if (!maybe_type) {
     diag_->Error(DiagMessage(out_resource->source)
                  << "<" << parser->element_name()
@@ -1137,7 +1134,7 @@
                 << "' for <overlayable> tag");
   }
 
-  Maybe<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
+  std::optional<StringPiece> overlayable_name = xml::FindNonEmptyAttribute(parser, "name");
   if (!overlayable_name) {
     diag_->Error(DiagMessage(out_resource->source)
                   << "<overlayable> tag must have a 'name' attribute");
@@ -1146,7 +1143,7 @@
 
   const std::string kActorUriScheme =
       android::base::StringPrintf("%s://", Overlayable::kActorScheme);
-  Maybe<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
+  std::optional<StringPiece> overlayable_actor = xml::FindNonEmptyAttribute(parser, "actor");
   if (overlayable_actor && !util::StartsWith(overlayable_actor.value(), kActorUriScheme)) {
     diag_->Error(DiagMessage(out_resource->source)
                  << "specified <overlayable> tag 'actor' attribute must use the scheme '"
@@ -1194,7 +1191,7 @@
       }
 
       // Items specify the name and type of resource that should be overlayable
-      Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
+      std::optional<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
       if (!item_name) {
         diag_->Error(DiagMessage(element_source)
                      << "<item> within an <overlayable> must have a 'name' attribute");
@@ -1202,7 +1199,7 @@
         continue;
       }
 
-      Maybe<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
+      std::optional<StringPiece> item_type = xml::FindNonEmptyAttribute(parser, "type");
       if (!item_type) {
         diag_->Error(DiagMessage(element_source)
                      << "<item> within an <overlayable> must have a 'type' attribute");
@@ -1236,7 +1233,8 @@
         diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested");
         error = true;
         break;
-      } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+      } else if (std::optional<StringPiece> maybe_type =
+                     xml::FindNonEmptyAttribute(parser, "type")) {
         // Parse the polices separated by vertical bar characters to allow for specifying multiple
         // policies. Items within the policy tag will have the specified policy.
         for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) {
@@ -1302,7 +1300,7 @@
 
   uint32_t type_mask = 0;
 
-  Maybe<StringPiece> maybe_format = xml::FindAttribute(parser, "format");
+  std::optional<StringPiece> maybe_format = xml::FindAttribute(parser, "format");
   if (maybe_format) {
     type_mask = ParseFormatAttribute(maybe_format.value());
     if (type_mask == 0) {
@@ -1312,9 +1310,9 @@
     }
   }
 
-  Maybe<int32_t> maybe_min, maybe_max;
+  std::optional<int32_t> maybe_min, maybe_max;
 
-  if (Maybe<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) {
+  if (std::optional<StringPiece> maybe_min_str = xml::FindAttribute(parser, "min")) {
     StringPiece min_str = util::TrimWhitespace(maybe_min_str.value());
     if (!min_str.empty()) {
       std::u16string min_str16 = util::Utf8ToUtf16(min_str);
@@ -1331,7 +1329,7 @@
     }
   }
 
-  if (Maybe<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) {
+  if (std::optional<StringPiece> maybe_max_str = xml::FindAttribute(parser, "max")) {
     StringPiece max_str = util::TrimWhitespace(maybe_max_str.value());
     if (!max_str.empty()) {
       std::u16string max_str16 = util::Utf8ToUtf16(max_str);
@@ -1398,8 +1396,7 @@
         type_mask |= android::ResTable_map::TYPE_FLAGS;
       }
 
-      if (Maybe<Attribute::Symbol> s =
-              ParseEnumOrFlagItem(parser, element_name)) {
+      if (std::optional<Attribute::Symbol> s = ParseEnumOrFlagItem(parser, element_name)) {
         Attribute::Symbol& symbol = s.value();
         ParsedResource child_resource;
         child_resource.name = symbol.symbol.name.value();
@@ -1443,24 +1440,24 @@
       type_mask ? type_mask : uint32_t{android::ResTable_map::TYPE_ANY});
   attr->SetWeak(weak);
   attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end());
-  attr->min_int = maybe_min.value_or_default(std::numeric_limits<int32_t>::min());
-  attr->max_int = maybe_max.value_or_default(std::numeric_limits<int32_t>::max());
+  attr->min_int = maybe_min.value_or(std::numeric_limits<int32_t>::min());
+  attr->max_int = maybe_max.value_or(std::numeric_limits<int32_t>::max());
   out_resource->value = std::move(attr);
   return true;
 }
 
-Maybe<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(
-    xml::XmlPullParser* parser, const StringPiece& tag) {
+std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPullParser* parser,
+                                                                     const StringPiece& tag) {
   const Source source = source_.WithLine(parser->line_number());
 
-  Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+  std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
   if (!maybe_name) {
     diag_->Error(DiagMessage(source) << "no attribute 'name' found for tag <"
                                      << tag << ">");
     return {};
   }
 
-  Maybe<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value");
+  std::optional<StringPiece> maybe_value = xml::FindNonEmptyAttribute(parser, "value");
   if (!maybe_value) {
     diag_->Error(DiagMessage(source) << "no attribute 'value' found for tag <"
                                      << tag << ">");
@@ -1484,13 +1481,13 @@
 bool ResourceParser::ParseStyleItem(xml::XmlPullParser* parser, Style* style) {
   const Source source = source_.WithLine(parser->line_number());
 
-  Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+  std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
   if (!maybe_name) {
     diag_->Error(DiagMessage(source) << "<item> must have a 'name' attribute");
     return false;
   }
 
-  Maybe<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+  std::optional<Reference> maybe_key = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
   if (!maybe_key) {
     diag_->Error(DiagMessage(source) << "invalid attribute name '" << maybe_name.value() << "'");
     return false;
@@ -1515,7 +1512,7 @@
 
   std::unique_ptr<Style> style = util::make_unique<Style>();
 
-  Maybe<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent");
+  std::optional<StringPiece> maybe_parent = xml::FindAttribute(parser, "parent");
   if (maybe_parent) {
     // If the parent is empty, we don't have a parent, but we also don't infer either.
     if (!maybe_parent.value().empty()) {
@@ -1571,7 +1568,7 @@
 
 bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
   uint32_t resource_format = android::ResTable_map::TYPE_ANY;
-  if (Maybe<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
+  if (std::optional<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
     resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
     if (resource_format == 0u) {
       diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -1598,8 +1595,8 @@
   std::unique_ptr<Array> array = util::make_unique<Array>();
 
   bool translatable = options_.translatable;
-  if (Maybe<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
-    Maybe<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
+  if (std::optional<StringPiece> translatable_attr = xml::FindAttribute(parser, "translatable")) {
+    std::optional<bool> maybe_translatable = ResourceUtils::ParseBool(translatable_attr.value());
     if (!maybe_translatable) {
       diag_->Error(DiagMessage(out_resource->source)
                    << "invalid value for 'translatable'. Must be a boolean");
@@ -1664,8 +1661,7 @@
     const std::string& element_namespace = parser->element_namespace();
     const std::string& element_name = parser->element_name();
     if (element_namespace.empty() && element_name == "item") {
-      Maybe<StringPiece> maybe_quantity =
-          xml::FindNonEmptyAttribute(parser, "quantity");
+      std::optional<StringPiece> maybe_quantity = xml::FindNonEmptyAttribute(parser, "quantity");
       if (!maybe_quantity) {
         diag_->Error(DiagMessage(item_source)
                      << "<item> in <plurals> requires attribute "
@@ -1767,7 +1763,7 @@
     const std::string& element_namespace = parser->element_namespace();
     const std::string& element_name = parser->element_name();
     if (element_namespace.empty() && element_name == "attr") {
-      Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+      std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
       if (!maybe_name) {
         diag_->Error(DiagMessage(item_source) << "<attr> tag must have a 'name' attribute");
         error = true;
@@ -1777,7 +1773,7 @@
       // If this is a declaration, the package name may be in the name. Separate
       // these out.
       // Eg. <attr name="android:text" />
-      Maybe<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
+      std::optional<Reference> maybe_ref = ResourceUtils::ParseXmlAttributeName(maybe_name.value());
       if (!maybe_ref) {
         diag_->Error(DiagMessage(item_source) << "<attr> tag has invalid name '"
                                               << maybe_name.value() << "'");
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 2614997..548f5f9 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -18,6 +18,7 @@
 #define AAPT_RESOURCE_PARSER_H
 
 #include <memory>
+#include <optional>
 
 #include "android-base/macros.h"
 #include "androidfw/ConfigDescription.h"
@@ -27,7 +28,6 @@
 #include "ResourceTable.h"
 #include "ResourceValues.h"
 #include "StringPool.h"
-#include "util/Maybe.h"
 #include "xml/XmlPullParser.h"
 
 namespace aapt {
@@ -54,7 +54,7 @@
 
   // If visibility was forced, we need to use it when creating a new resource and also error if we
   // try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags.
-  Maybe<Visibility::Level> visibility;
+  std::optional<Visibility::Level> visibility;
 };
 
 struct FlattenedXmlSubTree {
@@ -122,8 +122,8 @@
   bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
-  Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
-                                               const android::StringPiece& tag);
+  std::optional<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
+                                                       const android::StringPiece& tag);
   bool ParseStyle(ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
   bool ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 279ebcba..556ffa22 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -567,12 +567,12 @@
   Style* style = test::GetValue<Style>(&table_, "style/foo");
   ASSERT_THAT(style, NotNull());
   ASSERT_TRUE(style->parent);
-  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu"))));
+  EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("style/fu")));
   ASSERT_THAT(style->entries, SizeIs(3));
 
-  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
-  EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
-  EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
+  EXPECT_THAT(style->entries[0].key.name, Eq(test::ParseNameOrDie("attr/bar")));
+  EXPECT_THAT(style->entries[1].key.name, Eq(test::ParseNameOrDie("attr/bat")));
+  EXPECT_THAT(style->entries[2].key.name, Eq(test::ParseNameOrDie("attr/baz")));
 }
 
 TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
@@ -581,7 +581,7 @@
   Style* style = test::GetValue<Style>(&table_, "style/foo");
   ASSERT_THAT(style, NotNull());
   ASSERT_TRUE(style->parent);
-  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme"))));
+  EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("com.app:style/Theme")));
 }
 
 TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
@@ -594,7 +594,7 @@
   ASSERT_THAT(style, NotNull());
   ASSERT_TRUE(style->parent);
   ASSERT_TRUE(style->parent.value().name);
-  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme"))));
+  EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("android:style/Theme")));
 }
 
 TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
@@ -607,7 +607,7 @@
   Style* style = test::GetValue<Style>(&table_, "style/foo");
   ASSERT_THAT(style, NotNull());
   ASSERT_THAT(style->entries, SizeIs(1));
-  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar"))));
+  EXPECT_THAT(style->entries[0].key.name, Eq(test::ParseNameOrDie("android:attr/bar")));
 }
 
 TEST_F(ResourceParserTest, ParseStyleWithRawStringItem) {
@@ -634,7 +634,7 @@
   Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
   ASSERT_THAT(style, NotNull());
   ASSERT_TRUE(style->parent);
-  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo"))));
+  EXPECT_THAT(style->parent.value().name, Eq(test::ParseNameOrDie("style/foo")));
   EXPECT_TRUE(style->parent_inferred);
 }
 
@@ -672,7 +672,7 @@
       </declare-styleable>)";
   ASSERT_TRUE(TestParse(input));
 
-  Maybe<ResourceTable::SearchResult> result =
+  std::optional<ResourceTable::SearchResult> result =
       table_.FindResource(test::ParseNameOrDie("styleable/foo"));
   ASSERT_TRUE(result);
   EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
@@ -695,9 +695,9 @@
   ASSERT_THAT(styleable, NotNull());
   ASSERT_THAT(styleable->entries, SizeIs(3));
 
-  EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
-  EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
-  EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
+  EXPECT_THAT(styleable->entries[0].name, Eq(test::ParseNameOrDie("attr/bar")));
+  EXPECT_THAT(styleable->entries[1].name, Eq(test::ParseNameOrDie("attr/bat")));
+  EXPECT_THAT(styleable->entries[2].name, Eq(test::ParseNameOrDie("attr/baz")));
 }
 
 TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) {
@@ -913,7 +913,8 @@
       </public-group>)";
   ASSERT_TRUE(TestParse(input));
 
-  Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
+  std::optional<ResourceTable::SearchResult> result =
+      table_.FindResource(test::ParseNameOrDie("attr/foo"));
   ASSERT_TRUE(result);
   ASSERT_TRUE(result.value().entry->id);
   EXPECT_THAT(result.value().entry->id.value(), Eq(ResourceId(0x01010040)));
@@ -932,7 +933,8 @@
       </staging-public-group>)";
   ASSERT_TRUE(TestParse(input));
 
-  Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
+  std::optional<ResourceTable::SearchResult> result =
+      table_.FindResource(test::ParseNameOrDie("attr/foo"));
   ASSERT_TRUE(result);
 
   ASSERT_TRUE(result.value().entry->id);
@@ -959,7 +961,7 @@
       <java-symbol type="string" name="foo" />)";
   ASSERT_TRUE(TestParse(input));
 
-  Maybe<ResourceTable::SearchResult> result =
+  std::optional<ResourceTable::SearchResult> result =
       table_.FindResource(test::ParseNameOrDie("string/foo"));
   ASSERT_TRUE(result);
 
@@ -977,7 +979,7 @@
 TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
   ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)"));
 
-  Maybe<ResourceTable::SearchResult> result =
+  std::optional<ResourceTable::SearchResult> result =
       table_.FindResource(test::ParseNameOrDie("string/bar"));
   ASSERT_TRUE(result);
   const ResourceEntry* entry = result.value().entry;
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 8ab1493..ad014a2 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -18,6 +18,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <optional>
 #include <tuple>
 
 #include "android-base/logging.h"
@@ -68,7 +69,7 @@
 
 template <typename T, typename U>
 bool less_than_struct_with_name_and_id(const T& lhs,
-                                       const std::pair<std::string_view, Maybe<U>>& rhs) {
+                                       const std::pair<std::string_view, std::optional<U>>& rhs) {
   if (lhs.id != rhs.second) {
     return lhs.id < rhs.second;
   }
@@ -341,20 +342,20 @@
 
 void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePackage* package,
                               const ResourceTableType* type, const std::string& entry_name,
-                              const Maybe<ResourceId>& id, const Visibility& visibility,
-                              const Maybe<AllowNew>& allow_new,
-                              const Maybe<OverlayableItem>& overlayable_item,
-                              const Maybe<StagedId>& staged_id,
+                              const std::optional<ResourceId>& id, const Visibility& visibility,
+                              const std::optional<AllowNew>& allow_new,
+                              const std::optional<OverlayableItem>& overlayable_item,
+                              const std::optional<StagedId>& staged_id,
                               const std::vector<std::unique_ptr<ResourceConfigValue>>& values) {
   SortedVectorInserter<ResourceTablePackageView, PackageViewComparer> package_inserter;
   SortedVectorInserter<ResourceTableTypeView, TypeViewComparer> type_inserter;
   SortedVectorInserter<ResourceTableEntryView, EntryViewComparer> entry_inserter;
 
   ResourceTablePackageView new_package{package->name,
-                                       id ? id.value().package_id() : Maybe<uint8_t>{}};
+                                       id ? id.value().package_id() : std::optional<uint8_t>{}};
   auto view_package = package_inserter.Insert(table.packages, std::move(new_package));
 
-  ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : Maybe<uint8_t>{}};
+  ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : std::optional<uint8_t>{}};
   auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
 
   if (visibility.level == Visibility::Level::kPublic) {
@@ -363,7 +364,7 @@
   }
 
   ResourceTableEntryView new_entry{.name = entry_name,
-                                   .id = id ? id.value().entry_id() : Maybe<uint16_t>{},
+                                   .id = id ? id.value().entry_id() : std::optional<uint16_t>{},
                                    .visibility = visibility,
                                    .allow_new = allow_new,
                                    .overlayable_item = overlayable_item,
@@ -585,7 +586,8 @@
   return true;
 }
 
-Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name) const {
+std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(
+    const ResourceNameRef& name) const {
   ResourceTablePackage* package = FindPackage(name.package);
   if (package == nullptr) {
     return {};
@@ -603,8 +605,8 @@
   return SearchResult{package, type, entry};
 }
 
-Maybe<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name,
-                                                               ResourceId id) const {
+std::optional<ResourceTable::SearchResult> ResourceTable::FindResource(const ResourceNameRef& name,
+                                                                       ResourceId id) const {
   ResourceTablePackage* package = FindPackage(name.package);
   if (package == nullptr) {
     return {};
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index bae1d82..2e17659 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -120,18 +120,18 @@
   const std::string name;
 
   // The entry ID for this resource (the EEEE in 0xPPTTEEEE).
-  Maybe<ResourceId> id;
+  std::optional<ResourceId> id;
 
   // Whether this resource is public (and must maintain the same entry ID across builds).
   Visibility visibility;
 
-  Maybe<AllowNew> allow_new;
+  std::optional<AllowNew> allow_new;
 
   // The declarations of this resource as overlayable for RROs
-  Maybe<OverlayableItem> overlayable_item;
+  std::optional<OverlayableItem> overlayable_item;
 
   // The staged resource id for a finalized resource.
-  Maybe<StagedId> staged_id;
+  std::optional<StagedId> staged_id;
 
   // The resource's values for each configuration.
   std::vector<std::unique_ptr<ResourceConfigValue>> values;
@@ -205,11 +205,11 @@
 
 struct ResourceTableEntryView {
   std::string name;
-  Maybe<uint16_t> id;
+  std::optional<uint16_t> id;
   Visibility visibility;
-  Maybe<AllowNew> allow_new;
-  Maybe<OverlayableItem> overlayable_item;
-  Maybe<StagedId> staged_id;
+  std::optional<AllowNew> allow_new;
+  std::optional<OverlayableItem> overlayable_item;
+  std::optional<StagedId> staged_id;
   std::vector<const ResourceConfigValue*> values;
 
   const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
@@ -218,7 +218,7 @@
 
 struct ResourceTableTypeView {
   ResourceType type;
-  Maybe<uint8_t> id;
+  std::optional<uint8_t> id;
   Visibility::Level visibility_level = Visibility::Level::kUndefined;
 
   // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are
@@ -228,7 +228,7 @@
 
 struct ResourceTablePackageView {
   std::string name;
-  Maybe<uint8_t> id;
+  std::optional<uint8_t> id;
   // Types sorted in ascending type id order. If ids have not been assigned, the types are sorted by
   // their declaration order in the ResourceType enum.
   std::vector<ResourceTableTypeView> types;
@@ -309,8 +309,8 @@
     ResourceEntry* entry;
   };
 
-  Maybe<SearchResult> FindResource(const ResourceNameRef& name) const;
-  Maybe<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const;
+  std::optional<SearchResult> FindResource(const ResourceNameRef& name) const;
+  std::optional<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const;
   bool RemoveResource(const ResourceNameRef& name, ResourceId id) const;
 
   // Returns the package struct with the given name, or nullptr if such a package does not
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 38391c9..de73d2c 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -162,7 +162,7 @@
   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "tablet"), NotNull());
   EXPECT_THAT(test::GetValueForConfigAndProduct<Id>(&table, "android:string/foo",test::ParseConfigOrDie("land"), "phone"), NotNull());
 
-  Maybe<ResourceTable::SearchResult> sr =
+  std::optional<ResourceTable::SearchResult> sr =
       table.FindResource(test::ParseNameOrDie("android:string/foo"));
   ASSERT_TRUE(sr);
   std::vector<ResourceConfigValue*> values =
@@ -187,7 +187,7 @@
                                                        const ResourceNameRef& name,
                                                        Visibility::Level level,
                                                        const StringPiece& comment) {
-  Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
+  std::optional<ResourceTable::SearchResult> result = table.FindResource(name);
   if (!result) {
     return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
   }
@@ -242,7 +242,7 @@
   const ResourceName name = test::ParseNameOrDie("android:string/foo");
 
   AllowNew allow_new;
-  Maybe<ResourceTable::SearchResult> result;
+  std::optional<ResourceTable::SearchResult> result;
 
   allow_new.comment = "first";
   ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetAllowNew(allow_new).Build(),
@@ -274,7 +274,7 @@
   const ResourceName name = test::ParseNameOrDie("android:string/foo");
   ASSERT_TRUE(table.AddResource(NewResourceBuilder(name).SetOverlayable(overlayable_item).Build(),
                                 test::GetDiagnostics()));
-  Maybe<ResourceTable::SearchResult> search_result = table.FindResource(name);
+  std::optional<ResourceTable::SearchResult> search_result = table.FindResource(name);
 
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index e0e80ac..ead06bf 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -40,8 +40,7 @@
 namespace aapt {
 namespace ResourceUtils {
 
-Maybe<ResourceName> ToResourceName(
-    const android::ResTable::resource_name& name_in) {
+std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name_in) {
   // TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
   ResourceName name_out;
   if (!name_in.package) {
@@ -78,7 +77,7 @@
   return name_out;
 }
 
-Maybe<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) {
+std::optional<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in) {
   ResourceName name_out;
   if (!name_in.package) {
     return {};
@@ -251,8 +250,7 @@
  * <[*]package>:[style/]<entry>
  * [[*]package:style/]<entry>
  */
-Maybe<Reference> ParseStyleParentReference(const StringPiece& str,
-                                           std::string* out_error) {
+std::optional<Reference> ParseStyleParentReference(const StringPiece& str, std::string* out_error) {
   if (str.empty()) {
     return {};
   }
@@ -301,7 +299,7 @@
   return result;
 }
 
-Maybe<Reference> ParseXmlAttributeName(const StringPiece& str) {
+std::optional<Reference> ParseXmlAttributeName(const StringPiece& str) {
   StringPiece trimmed_str = util::TrimWhitespace(str);
   const char* start = trimmed_str.data();
   const char* const end = start + trimmed_str.size();
@@ -326,7 +324,7 @@
   }
 
   ref.name = ResourceName(package, ResourceType::kAttr, name.empty() ? trimmed_str : name);
-  return Maybe<Reference>(std::move(ref));
+  return std::optional<Reference>(std::move(ref));
 }
 
 std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
@@ -488,18 +486,18 @@
                : util::make_unique<BinaryPrimitive>(value);
 }
 
-Maybe<bool> ParseBool(const StringPiece& str) {
+std::optional<bool> ParseBool(const StringPiece& str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
   if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") {
-    return Maybe<bool>(true);
+    return std::optional<bool>(true);
   } else if (trimmed_str == "false" || trimmed_str == "FALSE" ||
              trimmed_str == "False") {
-    return Maybe<bool>(false);
+    return std::optional<bool>(false);
   }
   return {};
 }
 
-Maybe<uint32_t> ParseInt(const StringPiece& str) {
+std::optional<uint32_t> ParseInt(const StringPiece& str) {
   std::u16string str16 = util::Utf8ToUtf16(str);
   android::Res_value value;
   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
@@ -508,7 +506,7 @@
   return {};
 }
 
-Maybe<ResourceId> ParseResourceId(const StringPiece& str) {
+std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
 
   std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
@@ -524,7 +522,7 @@
   return {};
 }
 
-Maybe<int> ParseSdkVersion(const StringPiece& str) {
+std::optional<int> ParseSdkVersion(const StringPiece& str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
 
   std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
@@ -534,7 +532,7 @@
   }
 
   // Try parsing the code name.
-  Maybe<int> entry = GetDevelopmentSdkCodeNameVersion(trimmed_str);
+  std::optional<int> entry = GetDevelopmentSdkCodeNameVersion(trimmed_str);
   if (entry) {
     return entry.value();
   }
@@ -551,7 +549,7 @@
 }
 
 std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) {
-  if (Maybe<bool> maybe_result = ParseBool(str)) {
+  if (std::optional<bool> maybe_result = ParseBool(str)) {
     const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u;
     return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data);
   }
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index be493db..fe450a8 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -75,35 +75,33 @@
 /**
  * Convert an android::ResTable::resource_name to an aapt::ResourceName struct.
  */
-Maybe<ResourceName> ToResourceName(
-    const android::ResTable::resource_name& name);
+std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name);
 
 /**
  * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct.
  */
-Maybe<ResourceName> ToResourceName(
-    const android::AssetManager2::ResourceName& name_in);
+std::optional<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in);
 
 /**
  * Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
  * false, or False.
  */
-Maybe<bool> ParseBool(const android::StringPiece& str);
+std::optional<bool> ParseBool(const android::StringPiece& str);
 
 /**
  * Returns a uint32_t if the string is an integer.
  */
-Maybe<uint32_t> ParseInt(const android::StringPiece& str);
+std::optional<uint32_t> ParseInt(const android::StringPiece& str);
 
 /**
  * Returns an ID if it the string represented a valid ID.
  */
-Maybe<ResourceId> ParseResourceId(const android::StringPiece& str);
+std::optional<ResourceId> ParseResourceId(const android::StringPiece& str);
 
 /**
  * Parses an SDK version, which can be an integer, or a letter from A-Z.
  */
-Maybe<int> ParseSdkVersion(const android::StringPiece& str);
+std::optional<int> ParseSdkVersion(const android::StringPiece& str);
 
 /*
  * Returns a Reference, or None Maybe instance if the string `str` was parsed as
@@ -116,7 +114,8 @@
  * ?[package:]style/<entry> or
  * <package>:[style/]<entry>
  */
-Maybe<Reference> ParseStyleParentReference(const android::StringPiece& str, std::string* out_error);
+std::optional<Reference> ParseStyleParentReference(const android::StringPiece& str,
+                                                   std::string* out_error);
 
 /*
  * Returns a Reference if the string `str` was parsed as a valid XML attribute
@@ -125,7 +124,7 @@
  *
  * package:entry
  */
-Maybe<Reference> ParseXmlAttributeName(const android::StringPiece& str);
+std::optional<Reference> ParseXmlAttributeName(const android::StringPiece& str);
 
 /*
  * Returns a Reference object if the string was parsed as a resource or
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index b08bf9a..1aaa34d 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -30,15 +30,15 @@
 namespace aapt {
 
 TEST(ResourceUtilsTest, ParseBool) {
-  EXPECT_THAT(ResourceUtils::ParseBool("true"), Eq(Maybe<bool>(true)));
-  EXPECT_THAT(ResourceUtils::ParseBool("TRUE"), Eq(Maybe<bool>(true)));
-  EXPECT_THAT(ResourceUtils::ParseBool("True"), Eq(Maybe<bool>(true)));
+  EXPECT_THAT(ResourceUtils::ParseBool("true"), Eq(std::optional<bool>(true)));
+  EXPECT_THAT(ResourceUtils::ParseBool("TRUE"), Eq(std::optional<bool>(true)));
+  EXPECT_THAT(ResourceUtils::ParseBool("True"), Eq(std::optional<bool>(true)));
 
-  EXPECT_THAT(ResourceUtils::ParseBool("false"), Eq(Maybe<bool>(false)));
-  EXPECT_THAT(ResourceUtils::ParseBool("FALSE"), Eq(Maybe<bool>(false)));
-  EXPECT_THAT(ResourceUtils::ParseBool("False"), Eq(Maybe<bool>(false)));
+  EXPECT_THAT(ResourceUtils::ParseBool("false"), Eq(std::optional<bool>(false)));
+  EXPECT_THAT(ResourceUtils::ParseBool("FALSE"), Eq(std::optional<bool>(false)));
+  EXPECT_THAT(ResourceUtils::ParseBool("False"), Eq(std::optional<bool>(false)));
 
-  EXPECT_THAT(ResourceUtils::ParseBool(" False\n "), Eq(Maybe<bool>(false)));
+  EXPECT_THAT(ResourceUtils::ParseBool(" False\n "), Eq(std::optional<bool>(false)));
 }
 
 TEST(ResourceUtilsTest, ParseResourceName) {
@@ -155,41 +155,42 @@
   const ResourceName kStyleFooName({}, ResourceType::kStyle, "foo");
 
   std::string err_str;
-  Maybe<Reference> ref = ResourceUtils::ParseStyleParentReference("@android:style/foo", &err_str);
+  std::optional<Reference> ref =
+      ResourceUtils::ParseStyleParentReference("@android:style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("@style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("?android:style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("?style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("android:style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("android:foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("@android:foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kStyleFooName));
 
   ref = ResourceUtils::ParseStyleParentReference("*android:style/foo", &err_str);
   ASSERT_TRUE(ref);
-  EXPECT_THAT(ref.value().name, Eq(make_value(kAndroidStyleFooName)));
+  EXPECT_THAT(ref.value().name, Eq(kAndroidStyleFooName));
   EXPECT_TRUE(ref.value().private_reference);
 }
 
@@ -228,15 +229,11 @@
 }
 
 TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
-  EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(Maybe<int>(10000)));
-  EXPECT_THAT(
-      ResourceUtils::ParseSdkVersion("Q.fingerprint"),
-      Eq(Maybe<int>(10000)));
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(std::optional<int>(10000)));
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q.fingerprint"), Eq(std::optional<int>(10000)));
 
-  EXPECT_THAT(ResourceUtils::ParseSdkVersion("R"), Eq(Maybe<int>(10000)));
-  EXPECT_THAT(
-      ResourceUtils::ParseSdkVersion("R.fingerprint"),
-      Eq(Maybe<int>(10000)));
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion("R"), Eq(std::optional<int>(10000)));
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion("R.fingerprint"), Eq(std::optional<int>(10000)));
 }
 
 TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 2a90f26..b3ab4ff 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -120,7 +120,7 @@
     return false;
   }
 
-  const ResourceId resid = id.value_or_default(ResourceId(0));
+  const ResourceId resid = id.value_or(ResourceId(0));
   const bool dynamic = resid.is_valid() && is_dynamic;
 
   if (reference_type == Reference::Type::kResource) {
@@ -1040,7 +1040,7 @@
 }
 
 bool operator<(const Reference& a, const Reference& b) {
-  int cmp = a.name.value_or_default({}).compare(b.name.value_or_default({}));
+  int cmp = a.name.value_or(ResourceName{}).compare(b.name.value_or(ResourceName{}));
   if (cmp != 0) return cmp < 0;
   return a.id < b.id;
 }
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index d903b7e..1694d6b 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -31,7 +31,6 @@
 #include "ValueTransformer.h"
 #include "io/File.h"
 #include "text/Printer.h"
-#include "util/Maybe.h"
 
 namespace aapt {
 
@@ -159,8 +158,8 @@
     kAttribute,
   };
 
-  Maybe<ResourceName> name;
-  Maybe<ResourceId> id;
+  std::optional<ResourceName> name;
+  std::optional<ResourceId> id;
   std::optional<uint32_t> type_flags;
   Reference::Type reference_type;
   bool private_reference = false;
@@ -327,7 +326,7 @@
     friend std::ostream& operator<<(std::ostream& out, const Entry& entry);
   };
 
-  Maybe<Reference> parent;
+  std::optional<Reference> parent;
 
   // If set to true, the parent was auto inferred from the style's name.
   bool parent_inferred = false;
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index ebe41da..f7a5ba1 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -77,9 +77,10 @@
   return iter->second;
 }
 
-Maybe<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) {
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) {
   return (sDevelopmentSdkCodeNames.find(code_name) == sDevelopmentSdkCodeNames.end())
-      ? Maybe<ApiVersion>() : sDevelopmentSdkLevel;
+             ? std::optional<ApiVersion>()
+             : sDevelopmentSdkLevel;
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 6bb6ddb..7518e70 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -60,7 +60,7 @@
 };
 
 ApiVersion FindAttributeSdkLevel(const ResourceId& id);
-Maybe<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name);
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
index 92934c3..4f9369a 100644
--- a/tools/aapt2/Source.h
+++ b/tools/aapt2/Source.h
@@ -17,21 +17,20 @@
 #ifndef AAPT_SOURCE_H
 #define AAPT_SOURCE_H
 
+#include <optional>
 #include <ostream>
 #include <string>
 
 #include "android-base/stringprintf.h"
 #include "androidfw/StringPiece.h"
 
-#include "util/Maybe.h"
-
 namespace aapt {
 
 // Represents a file on disk. Used for logging and showing errors.
 struct Source {
   std::string path;
-  Maybe<size_t> line;
-  Maybe<std::string> archive;
+  std::optional<size_t> line;
+  std::optional<std::string> archive;
 
   Source() = default;
 
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index 919b4c9..b1452fa 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -72,7 +72,7 @@
 }
 
 void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description,
-                              Maybe<std::string>* value, uint32_t flags) {
+                              std::optional<std::string>* value, uint32_t flags) {
   auto func = [value, flags](const StringPiece& arg) -> bool {
     *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
     return true;
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index d21571d..8678cda 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -18,6 +18,7 @@
 #define AAPT_COMMAND_H
 
 #include <functional>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <unordered_set>
@@ -25,19 +26,20 @@
 
 #include "androidfw/StringPiece.h"
 
-#include "util/Maybe.h"
-
 namespace aapt {
 
 class Command {
  public:
-  explicit Command(const android::StringPiece& name) : name_(name.to_string()),
-                                                       short_name_(""),
-                                                       full_subcommand_name_(name.to_string()) {}
+  explicit Command(const android::StringPiece& name)
+      : name_(name.to_string()), full_subcommand_name_(name.to_string()){};
 
   explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
-      : name_(name.to_string()), short_name_(short_name.to_string()),
-        full_subcommand_name_(name.to_string()) {}
+      : name_(name.to_string()),
+        short_name_(short_name.to_string()),
+        full_subcommand_name_(name.to_string()){};
+
+  Command(Command&&) = default;
+  Command& operator=(Command&&) = default;
 
   virtual ~Command() = default;
 
@@ -58,7 +60,7 @@
                            uint32_t flags = 0);
 
   void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
-                       Maybe<std::string>* value, uint32_t flags = 0);
+                       std::optional<std::string>* value, uint32_t flags = 0);
 
   void AddOptionalFlagList(const android::StringPiece& name,
                            const android::StringPiece& description, std::vector<std::string>* value,
@@ -87,8 +89,6 @@
   virtual int Action(const std::vector<std::string>& args) = 0;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(Command);
-
   struct Flag {
     explicit Flag(const android::StringPiece& name, const android::StringPiece& description,
                   const bool is_required, const size_t num_args,
@@ -104,8 +104,8 @@
     bool found = false;
   };
 
-  const std::string name_;
-  const std::string short_name_;
+  std::string name_;
+  std::string short_name_;
   std::string description_ = "";
   std::string full_subcommand_name_;
 
diff --git a/tools/aapt2/cmd/Command_test.cpp b/tools/aapt2/cmd/Command_test.cpp
index 65608fd..7aa1aa01 100644
--- a/tools/aapt2/cmd/Command_test.cpp
+++ b/tools/aapt2/cmd/Command_test.cpp
@@ -38,7 +38,7 @@
   TestCommand command;
   std::string required_flag;
   command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath);
-  Maybe<std::string> optional_flag;
+  std::optional<std::string> optional_flag;
   command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath);
   std::vector<std::string> required_flag_list;
   command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath);
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index cd5015e..fe56018 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -47,7 +47,6 @@
 #include "io/ZipArchive.h"
 #include "trace/TraceBuffer.h"
 #include "util/Files.h"
-#include "util/Maybe.h"
 #include "util/Util.h"
 #include "xml/XmlDom.h"
 #include "xml/XmlPullParser.h"
@@ -75,10 +74,10 @@
 };
 
 // Resource file paths are expected to look like: [--/res/]type[-config]/name
-static Maybe<ResourcePathData> ExtractResourcePathData(const std::string& path,
-                                                       const char dir_sep,
-                                                       std::string* out_error,
-                                                       const CompileOptions& options) {
+static std::optional<ResourcePathData> ExtractResourcePathData(const std::string& path,
+                                                               const char dir_sep,
+                                                               std::string* out_error,
+                                                               const CompileOptions& options) {
   std::vector<std::string> parts = util::Split(path, dir_sep);
   if (parts.size() < 2) {
     if (out_error) *out_error = "bad resource path";
@@ -337,7 +336,7 @@
     if (file_type == file::FileType::kDirectory) {
       context->GetDiagnostics()->Error(DiagMessage(input_path)
                                        << "resource file cannot be a directory");
-    } else if (file_type == file::FileType::kNonexistant) {
+    } else if (file_type == file::FileType::kNonExistant) {
       context->GetDiagnostics()->Error(DiagMessage(input_path) << "file not found");
     } else {
       context->GetDiagnostics()->Error(DiagMessage(input_path)
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index 1bc1f66..bd2e3d7 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -17,7 +17,10 @@
 #ifndef AAPT2_COMPILE_H
 #define AAPT2_COMPILE_H
 
-#include "androidfw/StringPiece.h"
+#include <optional>
+
+#include <androidfw/StringPiece.h>
+
 #include "format/Archive.h"
 #include "process/IResourceTableConsumer.h"
 #include "Command.h"
@@ -28,11 +31,11 @@
 
 struct CompileOptions {
   std::string output_path;
-  Maybe<std::string> source_path;
-  Maybe<std::string> res_dir;
-  Maybe<std::string> res_zip;
-  Maybe<std::string> generate_text_symbols_path;
-  Maybe<Visibility::Level> visibility;
+  std::optional<std::string> source_path;
+  std::optional<std::string> res_dir;
+  std::optional<std::string> res_zip;
+  std::optional<std::string> generate_text_symbols_path;
+  std::optional<Visibility::Level> visibility;
   bool pseudolocalize = false;
   bool no_png_crunch = false;
   bool legacy_mode = false;
@@ -80,8 +83,8 @@
  private:
   IDiagnostics* diagnostic_;
   CompileOptions options_;
-  Maybe<std::string> visibility_;
-  Maybe<std::string> trace_folder_;
+  std::optional<std::string> visibility_;
+  std::optional<std::string> trace_folder_;
 };
 
 int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer,
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 22bcd85..3b097e0 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -367,8 +367,7 @@
     return 1;
   }
 
-  Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*apk->GetManifest(),
-                                                             context.GetDiagnostics());
+  auto app_info = ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), context.GetDiagnostics());
   if (!app_info) {
     return 1;
   }
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 7e2029d..2cdb0c8 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -17,6 +17,8 @@
 #ifndef AAPT2_CONVERT_H
 #define AAPT2_CONVERT_H
 
+#include <optional>
+
 #include "Command.h"
 #include "LoadedApk.h"
 #include "format/binary/TableFlattener.h"
@@ -52,7 +54,7 @@
   TableFlattenerOptions table_flattener_options_;
   XmlFlattenerOptions xml_flattener_options_;
   std::string output_path_;
-  Maybe<std::string> output_format_;
+  std::optional<std::string> output_format_;
   bool verbose_ = false;
 };
 
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 3950f33..d9e8c92 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -87,8 +87,8 @@
 }
 
 template <typename Id>
-static bool IsIdDiff(const Visibility::Level& level_a, const Maybe<Id>& id_a,
-                     const Visibility::Level& level_b, const Maybe<Id>& id_b) {
+static bool IsIdDiff(const Visibility::Level& level_a, const std::optional<Id>& id_a,
+                     const Visibility::Level& level_b, const std::optional<Id>& id_b) {
   if (level_a == Visibility::Level::kPublic || level_b == Visibility::Level::kPublic) {
     return id_a != id_b;
   }
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 3982d12..0a1e021 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -257,12 +257,11 @@
 }
 
 int DumpPackageNameCommand::Dump(LoadedApk* apk) {
-  Maybe<std::string> package_name = GetPackageName(apk);
-  if (!package_name) {
+  auto package_name = GetPackageName(apk);
+  if (!package_name.has_value()) {
     return 1;
   }
-
-  GetPrinter()->Println(package_name.value());
+  GetPrinter()->Println(*package_name);
   return 0;
 }
 
@@ -283,12 +282,12 @@
 }
 
 int DumpStyleParentCommand::Dump(LoadedApk* apk) {
-  Maybe<std::string> package_name = GetPackageName(apk);
-  if (!package_name) {
+  auto package_name = GetPackageName(apk);
+  if (!package_name.has_value()) {
     return 1;
   }
 
-  const auto target_style = ResourceName(package_name.value(), ResourceType::kStyle, style_);
+  const auto target_style = ResourceName(*package_name, ResourceType::kStyle, style_);
   const auto table = apk->GetResourceTable();
 
   if (!table) {
@@ -296,7 +295,7 @@
     return 1;
   }
 
-  Maybe<ResourceTable::SearchResult> target = table->FindResource(target_style);
+  std::optional<ResourceTable::SearchResult> target = table->FindResource(target_style);
   if (!target) {
     GetDiagnostics()->Error(
         DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist");
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index cd51f7a..52616fa 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -43,17 +43,17 @@
     return diag_;
   }
 
-  Maybe<std::string> GetPackageName(LoadedApk* apk) {
+  std::optional<std::string> GetPackageName(LoadedApk* apk) {
     xml::Element* manifest_el = apk->GetManifest()->root.get();
     if (!manifest_el) {
       GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
-      return Maybe<std::string>();
+      return {};
     }
 
     xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
     if (!attr) {
       GetDiagnostics()->Error(DiagMessage() << "No package name.");
-      return Maybe<std::string>();
+      return {};
     }
     return attr->value;
   }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e4d0f3b..e614a75 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -299,7 +299,7 @@
   bool do_not_fail_on_missing_resources = false;
   OutputFormat output_format = OutputFormat::kApk;
   std::unordered_set<std::string> extensions_to_not_compress;
-  Maybe<std::regex> regex_to_not_compress;
+  std::optional<std::regex> regex_to_not_compress;
 };
 
 // A sampling of public framework resource IDs.
@@ -741,7 +741,7 @@
     const size_t res_id_str_len = line.size() - res_id_start_idx;
     StringPiece res_id_str = util::TrimWhitespace(line.substr(res_id_start_idx, res_id_str_len));
 
-    Maybe<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str);
+    std::optional<ResourceId> maybe_id = ResourceUtils::ParseResourceId(res_id_str);
     if (!maybe_id) {
       diag->Error(DiagMessage(Source(path, line_no)) << "invalid resource ID '" << res_id_str
                                                      << "'");
@@ -793,7 +793,7 @@
     if (!options_.manifest_fixer_options.compile_sdk_version) {
       xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
       if (attr != nullptr) {
-        Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
+        auto& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
         if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) {
           switch (prim->value.dataType) {
             case Res_value::TYPE_INT_DEC:
@@ -816,7 +816,7 @@
     if (!options_.manifest_fixer_options.compile_sdk_version_codename) {
       xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName");
       if (attr != nullptr) {
-        Maybe<std::string>& compile_sdk_version_codename =
+        std::optional<std::string>& compile_sdk_version_codename =
             options_.manifest_fixer_options.compile_sdk_version_codename;
         if (String* str = ValueCast<String>(attr->compiled_value.get())) {
           compile_sdk_version_codename = *str->value;
@@ -912,7 +912,7 @@
     return true;
   }
 
-  Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
+  std::optional<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
     TRACE_CALL();
     // Make sure the first element is <manifest> with package attribute.
     xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get());
@@ -937,7 +937,7 @@
 
     if (xml::Attribute* version_code_attr =
             manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
-      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
+      std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value);
       if (!maybe_code) {
         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
                     << "invalid android:versionCode '" << version_code_attr->value << "'");
@@ -948,7 +948,7 @@
 
     if (xml::Attribute* version_code_major_attr =
         manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
-      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
+      std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_major_attr->value);
       if (!maybe_code) {
         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
                         << "invalid android:versionCodeMajor '"
@@ -960,7 +960,7 @@
 
     if (xml::Attribute* revision_code_attr =
             manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
-      Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
+      std::optional<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value);
       if (!maybe_code) {
         diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
                     << "invalid android:revisionCode '" << revision_code_attr->value << "'");
@@ -1094,7 +1094,7 @@
 
   bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
                      const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
-                     const Maybe<std::string>& out_text_symbols_path = {}) {
+                     const std::optional<std::string>& out_text_symbols_path = {}) {
     if (!options_.generate_java_class_path && !out_text_symbols_path) {
       return true;
     }
@@ -1251,7 +1251,7 @@
     }
 
     const std::string package_utf8 =
-        options_.custom_java_package.value_or_default(context_->GetCompilationPackage());
+        options_.custom_java_package.value_or(context_->GetCompilationPackage());
 
     std::string out_path = options_.generate_java_class_path.value();
     file::AppendPath(&out_path, file::PackageToPath(package_utf8));
@@ -1283,7 +1283,7 @@
     return true;
   }
 
-  bool WriteProguardFile(const Maybe<std::string>& out, const proguard::KeepSet& keep_set) {
+  bool WriteProguardFile(const std::optional<std::string>& out, const proguard::KeepSet& keep_set) {
     TRACE_CALL();
     if (!out) {
       return true;
@@ -1374,7 +1374,7 @@
         res_name.package = context_->GetCompilationPackage();
       }
 
-      Maybe<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name);
+      std::optional<ResourceName> mangled_name = context_->GetNameMangler()->MangleName(res_name);
       if (mangled_name) {
         res_name = mangled_name.value();
       }
@@ -1550,7 +1550,7 @@
   bool CopyAssetsDirsToApk(IArchiveWriter* writer) {
     std::map<std::string, std::unique_ptr<io::RegularFile>> merged_assets;
     for (const std::string& assets_dir : options_.assets_dirs) {
-      Maybe<std::vector<std::string>> files =
+      std::optional<std::vector<std::string>> files =
           file::FindFiles(assets_dir, context_->GetDiagnostics(), nullptr);
       if (!files) {
         return false;
@@ -1783,7 +1783,7 @@
         package_to_rewrite = table->packages.back().get();
         std::string new_package_name =
             StringPrintf("%s.%s", package_to_rewrite->name.c_str(),
-                         app_info_.split_name.value_or_default("feature").c_str());
+                         app_info_.split_name.value_or("feature").c_str());
 
         if (context_->IsVerbose()) {
           context_->GetDiagnostics()->Note(
@@ -1823,7 +1823,7 @@
     }
 
     // First extract the Package name without modifying it (via --rename-manifest-package).
-    if (Maybe<AppInfo> maybe_app_info =
+    if (std::optional<AppInfo> maybe_app_info =
             ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) {
       const AppInfo& app_info = maybe_app_info.value();
       context_->SetCompilationPackage(app_info.package);
@@ -1850,14 +1850,14 @@
       return 1;
     }
 
-    Maybe<AppInfo> maybe_app_info =
+    std::optional<AppInfo> maybe_app_info =
         ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics());
     if (!maybe_app_info) {
       return 1;
     }
 
     app_info_ = maybe_app_info.value();
-    context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0));
+    context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or(0));
 
     context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
     context_->SetSplitNameDependencies(app_info_.split_name_dependencies);
@@ -2231,7 +2231,7 @@
   std::map<size_t, std::string> shared_libs_;
 
   // The package name of the base application, if it is included.
-  Maybe<std::string> included_feature_base_;
+  std::optional<std::string> included_feature_base_;
 };
 
 int LinkCommand::Action(const std::vector<std::string>& args) {
@@ -2315,7 +2315,8 @@
       return 1;
     }
 
-    const Maybe<uint32_t> maybe_package_id_int = ResourceUtils::ParseInt(package_id_.value());
+    const std::optional<uint32_t> maybe_package_id_int =
+        ResourceUtils::ParseInt(package_id_.value());
     if (!maybe_package_id_int) {
       context.GetDiagnostics()->Error(DiagMessage() << "package ID '" << package_id_.value()
                                                     << "' is not a valid integer");
@@ -2360,7 +2361,7 @@
   }
 
   if (preferred_density_) {
-    Maybe<uint16_t> density =
+    std::optional<uint16_t> density =
         ParseTargetDensityParameter(preferred_density_.value(), context.GetDiagnostics());
     if (!density) {
       return 1;
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 768b4b2..d8c76e2 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -45,21 +45,21 @@
   bool auto_add_overlay = false;
   bool override_styles_instead_of_overlaying = false;
   OutputFormat output_format = OutputFormat::kApk;
-  Maybe<std::string> rename_resources_package;
+  std::optional<std::string> rename_resources_package;
 
   // Java/Proguard options.
-  Maybe<std::string> generate_java_class_path;
-  Maybe<std::string> custom_java_package;
+  std::optional<std::string> generate_java_class_path;
+  std::optional<std::string> custom_java_package;
   std::set<std::string> extra_java_packages;
-  Maybe<std::string> generate_text_symbols_path;
-  Maybe<std::string> generate_proguard_rules_path;
-  Maybe<std::string> generate_main_dex_proguard_rules_path;
+  std::optional<std::string> generate_text_symbols_path;
+  std::optional<std::string> generate_proguard_rules_path;
+  std::optional<std::string> generate_main_dex_proguard_rules_path;
   bool generate_conditional_proguard_rules = false;
   bool generate_minimal_proguard_rules = false;
   bool generate_non_final_ids = false;
   bool no_proguard_location_reference = false;
   std::vector<std::string> javadoc_annotations;
-  Maybe<std::string> private_symbols;
+  std::optional<std::string> private_symbols;
 
   // Optimizations/features.
   bool no_auto_version = false;
@@ -70,7 +70,7 @@
   bool no_xml_namespaces = false;
   bool do_not_compress_anything = false;
   std::unordered_set<std::string> extensions_to_not_compress;
-  Maybe<std::regex> regex_to_not_compress;
+  std::optional<std::regex> regex_to_not_compress;
 
   // Static lib options.
   bool no_static_lib_packages = false;
@@ -97,7 +97,7 @@
 
   // Stable ID options.
   std::unordered_map<ResourceName, ResourceId> stable_id_map;
-  Maybe<std::string> resource_id_map_path;
+  std::optional<std::string> resource_id_map_path;
 
   // When 'true', allow reserved package IDs to be used for applications. Pre-O, the platform
   // treats negative resource IDs [those with a package ID of 0x80 or higher] as invalid.
@@ -321,20 +321,20 @@
 
   std::vector<std::string> overlay_arg_list_;
   std::vector<std::string> extra_java_packages_;
-  Maybe<std::string> package_id_;
+  std::optional<std::string> package_id_;
   std::vector<std::string> configs_;
-  Maybe<std::string> preferred_density_;
-  Maybe<std::string> product_list_;
-  Maybe<std::string> no_compress_regex;
+  std::optional<std::string> preferred_density_;
+  std::optional<std::string> product_list_;
+  std::optional<std::string> no_compress_regex;
   bool legacy_x_flag_ = false;
   bool require_localization_ = false;
   bool verbose_ = false;
   bool shared_lib_ = false;
   bool static_lib_ = false;
   bool proto_format_ = false;
-  Maybe<std::string> stable_id_file_path_;
+  std::optional<std::string> stable_id_file_path_;
   std::vector<std::string> split_args_;
-  Maybe<std::string> trace_folder_;
+  std::optional<std::string> trace_folder_;
 };
 
 }// namespace aapt
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 5b18a37..caa3e60 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -354,7 +354,7 @@
     return false;
   }
 
-  Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
+  auto app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
   if (!app_info) {
     context->GetDiagnostics()->Error(DiagMessage()
                                      << "failed to extract data from AndroidManifest.xml");
@@ -362,7 +362,7 @@
   }
 
   out_options->app_info = std::move(app_info.value());
-  context->SetMinSdkVersion(out_options->app_info.min_sdk_version.value_or_default(0));
+  context->SetMinSdkVersion(out_options->app_info.min_sdk_version.value_or(0));
   return true;
 }
 
@@ -380,7 +380,7 @@
 
   if (config_path_) {
     std::string& path = config_path_.value();
-    Maybe<ConfigurationParser> for_path = ConfigurationParser::ForPath(path);
+    std::optional<ConfigurationParser> for_path = ConfigurationParser::ForPath(path);
     if (for_path) {
       options_.apk_artifacts = for_path.value().WithDiagnostics(diag).Parse(apk_path);
       if (!options_.apk_artifacts) {
@@ -427,7 +427,7 @@
   if (target_densities_) {
     // Parse the target screen densities.
     for (const StringPiece& config_str : util::Tokenize(target_densities_.value(), ',')) {
-      Maybe<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
+      std::optional<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
       if (!target_density) {
         return 1;
       }
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 3afc46b..ff63e8d 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -29,9 +29,9 @@
   friend class OptimizeCommand;
 
   // Path to the output APK.
-  Maybe<std::string> output_path;
+  std::optional<std::string> output_path;
   // Path to the output APK directory for splits.
-  Maybe<std::string> output_dir;
+  std::optional<std::string> output_dir;
 
   // Details of the app extracted from the AndroidManifest.xml
   AppInfo app_info;
@@ -50,7 +50,7 @@
 
   TableFlattenerOptions table_flattener_options;
 
-  Maybe<std::vector<aapt::configuration::OutputArtifact>> apk_artifacts;
+  std::optional<std::vector<aapt::configuration::OutputArtifact>> apk_artifacts;
 
   // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
   // are kept and will be written as output.
@@ -60,7 +60,7 @@
   bool shorten_resource_paths = false;
 
   // Path to the output map of original resource paths to shortened paths.
-  Maybe<std::string> shortened_paths_map_path;
+  std::optional<std::string> shortened_paths_map_path;
 };
 
 class OptimizeCommand : public Command {
@@ -122,9 +122,9 @@
   bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map,
                                const std::string &file_path);
 
-  Maybe<std::string> config_path_;
-  Maybe<std::string> resources_config_path_;
-  Maybe<std::string> target_densities_;
+  std::optional<std::string> config_path_;
+  std::optional<std::string> resources_config_path_;
+  std::optional<std::string> target_densities_;
   std::vector<std::string> configs_;
   std::vector<std::string> split_args_;
   std::unordered_set<std::string> kept_artifacts_;
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 7214f1a..3244fb8 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -21,11 +21,10 @@
 #include "android-base/logging.h"
 #include "androidfw/ConfigDescription.h"
 #include "androidfw/Locale.h"
-
 #include "ResourceUtils.h"
 #include "ValueVisitor.h"
 #include "split/TableSplitter.h"
-#include "util/Maybe.h"
+
 #include "util/Util.h"
 
 using ::android::ConfigDescription;
@@ -35,7 +34,7 @@
 
 namespace aapt {
 
-Maybe<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) {
+std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg, IDiagnostics* diag) {
   ConfigDescription preferred_density_config;
   if (!ConfigDescription::Parse(arg, &preferred_density_config)) {
     diag->Error(DiagMessage() << "invalid density '" << arg << "' for --preferred-density option");
@@ -245,8 +244,8 @@
   return doc;
 }
 
-static Maybe<std::string> ExtractCompiledString(const xml::Attribute& attr,
-                                                std::string* out_error) {
+static std::optional<std::string> ExtractCompiledString(const xml::Attribute& attr,
+                                                        std::string* out_error) {
   if (attr.compiled_value != nullptr) {
     const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
     if (compiled_str != nullptr) {
@@ -269,7 +268,8 @@
   return {};
 }
 
-static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::string* out_error) {
+static std::optional<uint32_t> ExtractCompiledInt(const xml::Attribute& attr,
+                                                  std::string* out_error) {
   if (attr.compiled_value != nullptr) {
     const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
     if (compiled_prim != nullptr) {
@@ -283,7 +283,7 @@
   }
 
   // Fallback to the plain text value if there is one.
-  Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr.value);
+  std::optional<uint32_t> integer = ResourceUtils::ParseInt(attr.value);
   if (integer) {
     return integer;
   }
@@ -293,7 +293,7 @@
   return {};
 }
 
-static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) {
+static std::optional<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) {
   if (attr.compiled_value != nullptr) {
     const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
     if (compiled_prim != nullptr) {
@@ -307,7 +307,7 @@
 
     const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
     if (compiled_str != nullptr) {
-      Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value);
+      std::optional<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value);
       if (sdk_version) {
         return sdk_version;
       }
@@ -320,7 +320,7 @@
   }
 
   // Fallback to the plain text value if there is one.
-  Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
+  std::optional<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
   if (sdk_version) {
     return sdk_version;
   }
@@ -330,8 +330,8 @@
   return {};
 }
 
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
-                                                IDiagnostics* diag) {
+std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+                                                        IDiagnostics* diag) {
   // Make sure the first element is <manifest> with package attribute.
   const xml::Element* manifest_el = xml_res.root.get();
   if (manifest_el == nullptr) {
@@ -352,7 +352,7 @@
   }
 
   std::string error_msg;
-  Maybe<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
+  std::optional<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
   if (!maybe_package) {
     diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                 << "invalid package name: " << error_msg);
@@ -362,7 +362,7 @@
 
   if (const xml::Attribute* version_code_attr =
           manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
-    Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
+    std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
     if (!maybe_code) {
       diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                   << "invalid android:versionCode: " << error_msg);
@@ -373,7 +373,7 @@
 
   if (const xml::Attribute* version_code_major_attr =
       manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCodeMajor")) {
-    Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg);
+    std::optional<uint32_t> maybe_code = ExtractCompiledInt(*version_code_major_attr, &error_msg);
     if (!maybe_code) {
       diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                       << "invalid android:versionCodeMajor: " << error_msg);
@@ -384,7 +384,7 @@
 
   if (const xml::Attribute* revision_code_attr =
           manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
-    Maybe<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
+    std::optional<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
     if (!maybe_code) {
       diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                   << "invalid android:revisionCode: " << error_msg);
@@ -394,7 +394,8 @@
   }
 
   if (const xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
-    Maybe<std::string> maybe_split_name = ExtractCompiledString(*split_name_attr, &error_msg);
+    std::optional<std::string> maybe_split_name =
+        ExtractCompiledString(*split_name_attr, &error_msg);
     if (!maybe_split_name) {
       diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
                   << "invalid split name: " << error_msg);
@@ -406,7 +407,7 @@
   if (const xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
     if (const xml::Attribute* min_sdk =
             uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
-      Maybe<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
+      std::optional<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
       if (!maybe_sdk) {
         diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
                     << "invalid android:minSdkVersion: " << error_msg);
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index 2a7c62e..1b98eb4 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -26,14 +26,14 @@
 #include "SdkConstants.h"
 #include "filter/ConfigFilter.h"
 #include "split/TableSplitter.h"
-#include "util/Maybe.h"
 #include "xml/XmlDom.h"
 
 namespace aapt {
 
 // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc).
 // Returns Nothing and logs a human friendly error message if the string was not legal.
-Maybe<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg, IDiagnostics* diag);
+std::optional<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg,
+                                                    IDiagnostics* diag);
 
 // Parses a string of the form 'path/to/output.apk:<config>[,<config>...]' and fills in
 // `out_path` with the path and `out_split` with the set of ConfigDescriptions.
@@ -59,8 +59,8 @@
                                                         const SplitConstraints& constraints);
 
 // Extracts relevant info from the AndroidManifest.xml.
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
-                                                IDiagnostics* diag);
+std::optional<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+                                                        IDiagnostics* diag);
 
 // Returns a copy of 'name' which conforms to the regex '[a-zA-Z]+[a-zA-Z0-9_]*' by
 // replacing nonconforming characters with underscores.
diff --git a/tools/aapt2/compile/IdAssigner_test.cpp b/tools/aapt2/compile/IdAssigner_test.cpp
index 6637766..d357571 100644
--- a/tools/aapt2/compile/IdAssigner_test.cpp
+++ b/tools/aapt2/compile/IdAssigner_test.cpp
@@ -57,18 +57,18 @@
   ASSERT_TRUE(assigner.Consume(context.get(), table.get()));
   ASSERT_TRUE(VerifyIds(table.get()));
 
-  Maybe<ResourceTable::SearchResult> maybe_result;
+  std::optional<ResourceTable::SearchResult> maybe_result;
 
   // Expect to fill in the gaps between 0x0101XXXX and 0x0104XXXX.
 
   maybe_result = table->FindResource(test::ParseNameOrDie("android:dimen/two"));
   ASSERT_TRUE(maybe_result);
-  EXPECT_EQ(make_value<ResourceId>(0x01020000), maybe_result.value().entry->id);
+  EXPECT_EQ(0x01020000, maybe_result.value().entry->id);
 
   maybe_result =
       table->FindResource(test::ParseNameOrDie("android:integer/three"));
   ASSERT_TRUE(maybe_result);
-  EXPECT_EQ(make_value<ResourceId>(0x01030000), maybe_result.value().entry->id);
+  EXPECT_EQ(0x01030000, maybe_result.value().entry->id);
 
   // Expect to bypass the reserved 0x0104XXXX IDs and use the next 0x0105XXXX
   // IDs.
@@ -76,17 +76,17 @@
   maybe_result =
       table->FindResource(test::ParseNameOrDie("android:string/five"));
   ASSERT_TRUE(maybe_result);
-  EXPECT_EQ(make_value<ResourceId>(0x01050000), maybe_result.value().entry->id);
+  EXPECT_EQ(0x01050000, maybe_result.value().entry->id);
 
   // Expect to fill in the gaps between 0x01040000 and 0x01040006.
 
   maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/bar"));
   ASSERT_TRUE(maybe_result);
-  EXPECT_EQ(make_value<ResourceId>(0x01040001), maybe_result.value().entry->id);
+  EXPECT_EQ(0x01040001, maybe_result.value().entry->id);
 
   maybe_result = table->FindResource(test::ParseNameOrDie("android:attr/baz"));
   ASSERT_TRUE(maybe_result);
-  EXPECT_EQ(make_value<ResourceId>(0x01040002), maybe_result.value().entry->id);
+  EXPECT_EQ(0x01040002, maybe_result.value().entry->id);
 }
 
 TEST_F(IdAssignerTests, FailWhenNonUniqueIdsAssigned) {
@@ -143,7 +143,7 @@
   ASSERT_TRUE(result);
 
   const ResourceTable::SearchResult& search_result = result.value();
-  EXPECT_EQ(make_value<ResourceId>(0x01010002), search_result.entry->id);
+  EXPECT_EQ(0x01010002, search_result.entry->id);
 }
 
 TEST_F(IdAssignerTests, UseAllEntryIds) {
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index 79b0933..de1c3bb 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -56,7 +56,7 @@
       return;
     }
 
-    Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value);
+    std::optional<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value);
     if (!ref) {
       context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value
                                                          << "'");
@@ -65,7 +65,7 @@
     }
 
     const ResourceName& name = ref.value().name.value();
-    Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
+    std::optional<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package);
     if (!maybe_pkg) {
       context_->GetDiagnostics()->Error(DiagMessage(src)
                                         << "invalid namespace prefix '" << name.package << "'");
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 3f574ee..2461438 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -33,7 +33,7 @@
 // The struct that represents both Span objects and UntranslatableSections.
 struct UnifiedSpan {
   // Only present for Span objects. If not present, this was an UntranslatableSection.
-  Maybe<std::string> tag;
+  std::optional<std::string> tag;
 
   // The UTF-16 index into the string where this span starts.
   uint32_t first_char;
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index dd06b38..e7a4585 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -34,7 +34,6 @@
 #include "io/FileSystem.h"
 #include "io/StringStream.h"
 #include "util/Files.h"
-#include "util/Maybe.h"
 #include "util/Util.h"
 #include "xml/XmlActionExecutor.h"
 #include "xml/XmlDom.h"
@@ -113,7 +112,7 @@
 }
 
 /** Returns the value of the version-code-order attribute for a given element. */
-Maybe<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+std::optional<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
   const xml::Attribute* version = element->FindAttribute("", "version-code-order");
   if (version == nullptr) {
     std::string label = GetLabel(element, diag);
@@ -135,7 +134,7 @@
 
 /** Copies the values referenced in a configuration group to the target list. */
 template <typename T>
-bool CopyXmlReferences(const Maybe<std::string>& name, const Group<T>& groups,
+bool CopyXmlReferences(const std::optional<std::string>& name, const Group<T>& groups,
                        std::vector<T>* target) {
   // If there was no item configured, there is nothing to do and no error.
   if (!name) {
@@ -159,7 +158,7 @@
  * success, or false if the either the placeholder is not found in the name, or the value is not
  * present and the placeholder was.
  */
-bool ReplacePlaceholder(const StringPiece& placeholder, const Maybe<StringPiece>& value,
+bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<StringPiece>& value,
                         std::string* name, IDiagnostics* diag) {
   size_t offset = name->find(placeholder.data());
   bool found = (offset != std::string::npos);
@@ -207,17 +206,17 @@
 }
 
 /** Converts a ConfiguredArtifact into an OutputArtifact. */
-Maybe<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact,
-                                       const std::string& apk_name,
-                                       const PostProcessingConfiguration& config,
-                                       IDiagnostics* diag) {
+std::optional<OutputArtifact> ToOutputArtifact(const ConfiguredArtifact& artifact,
+                                               const std::string& apk_name,
+                                               const PostProcessingConfiguration& config,
+                                               IDiagnostics* diag) {
   if (!artifact.name && !config.artifact_format) {
     diag->Error(
         DiagMessage() << "Artifact does not have a name and no global name template defined");
     return {};
   }
 
-  Maybe<std::string> artifact_name =
+  std::optional<std::string> artifact_name =
       (artifact.name) ? artifact.Name(apk_name, diag)
                       : artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag);
 
@@ -287,9 +286,9 @@
 namespace configuration {
 
 /** Returns the binary reprasentation of the XML configuration. */
-Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
-                                                        const std::string& config_path,
-                                                        IDiagnostics* diag) {
+std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
+                                                                const std::string& config_path,
+                                                                IDiagnostics* diag) {
   StringInputStream in(contents);
   std::unique_ptr<xml::XmlResource> doc = xml::Inflate(&in, diag, Source(config_path));
   if (!doc) {
@@ -351,7 +350,8 @@
 /**
  * Returns the common artifact base name from a template string.
  */
-Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, IDiagnostics* diag) {
+std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk_name,
+                                      IDiagnostics* diag) {
   const StringPiece ext = file::GetExtension(apk_name);
   size_t end_index = apk_name.to_string().rfind(ext.to_string());
   const std::string base_name =
@@ -359,8 +359,8 @@
 
   // Base name is optional.
   if (result.find("${basename}") != std::string::npos) {
-    Maybe<StringPiece> maybe_base_name =
-        base_name.empty() ? Maybe<StringPiece>{} : Maybe<StringPiece>{base_name};
+    auto maybe_base_name = base_name.empty() ? std::nullopt
+                                             : std::optional<StringPiece>{base_name};
     if (!ReplacePlaceholder("${basename}", maybe_base_name, &result, diag)) {
       return {};
     }
@@ -383,10 +383,10 @@
   return result;
 }
 
-Maybe<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
-                                                      const StringPiece& apk_name,
-                                                      IDiagnostics* diag) const {
-  Maybe<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
+std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
+                                                              const StringPiece& apk_name,
+                                                              IDiagnostics* diag) const {
+  std::optional<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
   if (!base) {
     return {};
   }
@@ -419,7 +419,8 @@
   return result;
 }
 
-Maybe<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name, IDiagnostics* diag) const {
+std::optional<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name,
+                                                    IDiagnostics* diag) const {
   if (!name) {
     return {};
   }
@@ -430,7 +431,7 @@
 }  // namespace configuration
 
 /** Returns a ConfigurationParser for the file located at the provided path. */
-Maybe<ConfigurationParser> ConfigurationParser::ForPath(const std::string& path) {
+std::optional<ConfigurationParser> ConfigurationParser::ForPath(const std::string& path) {
   std::string contents;
   if (!ReadFileToString(path, &contents, true)) {
     return {};
@@ -442,9 +443,9 @@
     : contents_(std::move(contents)), config_path_(config_path), diag_(&noop_) {
 }
 
-Maybe<std::vector<OutputArtifact>> ConfigurationParser::Parse(
+std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
     const android::StringPiece& apk_path) {
-  Maybe<PostProcessingConfiguration> maybe_config =
+  std::optional<PostProcessingConfiguration> maybe_config =
       ExtractConfiguration(contents_, config_path_, diag_);
   if (!maybe_config) {
     return {};
@@ -460,7 +461,8 @@
   int version = 1;
 
   for (const ConfiguredArtifact& artifact : config.artifacts) {
-    Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_);
+    std::optional<OutputArtifact> output_artifact =
+        ToOutputArtifact(artifact, apk_name, config, diag_);
     if (!output_artifact) {
       // Defer return an error condition so that all errors are reported.
       valid = false;
@@ -538,7 +540,7 @@
 
   bool valid = true;
   OrderedEntry<Abi>& entry = config->abi_groups[label];
-  Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+  std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag);
   if (!order) {
     valid = false;
   } else {
@@ -589,7 +591,7 @@
 
   bool valid = true;
   OrderedEntry<ConfigDescription>& entry = config->screen_density_groups[label];
-  Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+  std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag);
   if (!order) {
     valid = false;
   } else {
@@ -656,7 +658,7 @@
 
   bool valid = true;
   OrderedEntry<ConfigDescription>& entry = config->locale_groups[label];
-  Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+  std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag);
   if (!order) {
     valid = false;
   } else {
@@ -724,19 +726,19 @@
       entry.label = attr.value;
       valid_attr = true;
     } else if (attr.name == "minSdkVersion") {
-      Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value);
+      std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value);
       if (version) {
         valid_attr = true;
         entry.min_sdk_version = version.value();
       }
     } else if (attr.name == "targetSdkVersion") {
-      Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value);
+      std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value);
       if (version) {
         valid_attr = true;
         entry.target_sdk_version = version;
       }
     } else if (attr.name == "maxSdkVersion") {
-      Maybe<int> version = ResourceUtils::ParseSdkVersion(attr.value);
+      std::optional<int> version = ResourceUtils::ParseSdkVersion(attr.value);
       if (version) {
         valid_attr = true;
         entry.max_sdk_version = version;
@@ -778,7 +780,7 @@
 
   bool valid = true;
   OrderedEntry<GlTexture>& entry = config->gl_texture_groups[label];
-  Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+  std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag);
   if (!order) {
     valid = false;
   } else {
@@ -828,7 +830,7 @@
 
   bool valid = true;
   OrderedEntry<DeviceFeature>& entry = config->device_feature_groups[label];
-  Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+  std::optional<int32_t> order = GetVersionCodeOrder(root_element, diag);
   if (!order) {
     valid = false;
   } else {
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index b9e3be9..195b4ba 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -17,6 +17,7 @@
 #ifndef AAPT2_CONFIGURATION_H
 #define AAPT2_CONFIGURATION_H
 
+#include <optional>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -25,7 +26,6 @@
 #include "androidfw/ConfigDescription.h"
 
 #include "Diagnostics.h"
-#include "util/Maybe.h"
 
 namespace aapt {
 
@@ -55,9 +55,9 @@
  */
 struct Locale {
   /** The ISO<?> standard locale language code. */
-  Maybe<std::string> lang;
+  std::optional<std::string> lang;
   /** The ISO<?> standard locale region code. */
-  Maybe<std::string> region;
+  std::optional<std::string> region;
 
   inline friend bool operator==(const Locale& lhs, const Locale& rhs) {
     return lhs.lang == rhs.lang && lhs.region == rhs.region;
@@ -74,9 +74,9 @@
 struct AndroidSdk {
   std::string label;
   int min_sdk_version;  // min_sdk_version is mandatory if splitting by SDK.
-  Maybe<int> target_sdk_version;
-  Maybe<int> max_sdk_version;
-  Maybe<AndroidManifest> manifest;
+  std::optional<int> target_sdk_version;
+  std::optional<int> max_sdk_version;
+  std::optional<AndroidManifest> manifest;
 
   static AndroidSdk ForMinSdk(int min_sdk) {
     AndroidSdk sdk;
@@ -112,7 +112,7 @@
   std::vector<Abi> abis;
   std::vector<android::ConfigDescription> screen_densities;
   std::vector<android::ConfigDescription> locales;
-  Maybe<AndroidSdk> android_sdk;
+  std::optional<AndroidSdk> android_sdk;
   std::vector<DeviceFeature> features;
   std::vector<GlTexture> textures;
 
@@ -136,7 +136,7 @@
  public:
 
   /** Returns a ConfigurationParser for the file located at the provided path. */
-  static Maybe<ConfigurationParser> ForPath(const std::string& path);
+  static std::optional<ConfigurationParser> ForPath(const std::string& path);
 
   /** Returns a ConfigurationParser for the configuration in the provided file contents. */
   static ConfigurationParser ForContents(const std::string& contents, const std::string& path) {
@@ -154,7 +154,8 @@
    * Parses the configuration file and returns the results. If the configuration could not be parsed
    * the result is empty and any errors will be displayed with the provided diagnostics context.
    */
-  Maybe<std::vector<configuration::OutputArtifact>> Parse(const android::StringPiece& apk_path);
+  std::optional<std::vector<configuration::OutputArtifact>> Parse(
+      const android::StringPiece& apk_path);
 
  protected:
   /**
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index c541688..42ef5159 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -84,8 +84,8 @@
    * have not been able to determine the sort order with the previous comparisons.
    */
   template <typename T>
-  ComparisonChain& Add(const Group<T>& groups, const Maybe<std::string>& lhs,
-                       const Maybe<std::string>& rhs) {
+  ComparisonChain& Add(const Group<T>& groups, const std::optional<std::string>& lhs,
+                       const std::optional<std::string>& rhs) {
     return Add(GetGroupOrder(groups, lhs), GetGroupOrder(groups, rhs));
   }
 
@@ -108,7 +108,7 @@
 
  private:
   template <typename T>
-  inline size_t GetGroupOrder(const Entry<T>& groups, const Maybe<std::string>& label) {
+  inline size_t GetGroupOrder(const Entry<T>& groups, const std::optional<std::string>& label) {
     if (!label) {
       return std::numeric_limits<size_t>::max();
     }
@@ -122,32 +122,33 @@
 /** Output artifact configuration options. */
 struct ConfiguredArtifact {
   /** Name to use for output of processing foo.apk -> foo.<name>.apk. */
-  Maybe<std::string> name;
+  std::optional<std::string> name;
   /** If present, uses the ABI group with this name. */
-  Maybe<std::string> abi_group;
+  std::optional<std::string> abi_group;
   /** If present, uses the screen density group with this name. */
-  Maybe<std::string> screen_density_group;
+  std::optional<std::string> screen_density_group;
   /** If present, uses the locale group with this name. */
-  Maybe<std::string> locale_group;
+  std::optional<std::string> locale_group;
   /** If present, uses the Android SDK with this name. */
-  Maybe<std::string> android_sdk;
+  std::optional<std::string> android_sdk;
   /** If present, uses the device feature group with this name. */
-  Maybe<std::string> device_feature_group;
+  std::optional<std::string> device_feature_group;
   /** If present, uses the OpenGL texture group with this name. */
-  Maybe<std::string> gl_texture_group;
+  std::optional<std::string> gl_texture_group;
 
   /** Convert an artifact name template into a name string based on configuration contents. */
-  Maybe<std::string> ToArtifactName(const android::StringPiece& format,
-                                    const android::StringPiece& apk_name, IDiagnostics* diag) const;
+  std::optional<std::string> ToArtifactName(const android::StringPiece& format,
+                                            const android::StringPiece& apk_name,
+                                            IDiagnostics* diag) const;
 
   /** Convert an artifact name template into a name string based on configuration contents. */
-  Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
+  std::optional<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
 };
 
 /** AAPT2 XML configuration file binary representation. */
 struct PostProcessingConfiguration {
   std::vector<ConfiguredArtifact> artifacts;
-  Maybe<std::string> artifact_format;
+  std::optional<std::string> artifact_format;
 
   Group<Abi> abi_groups;
   Group<android::ConfigDescription> screen_density_groups;
@@ -212,9 +213,9 @@
 };
 
 /** Parses the provided XML document returning the post processing configuration. */
-Maybe<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
-                                                        const std::string& config_path,
-                                                        IDiagnostics* diag);
+std::optional<PostProcessingConfiguration> ExtractConfiguration(const std::string& contents,
+                                                                const std::string& config_path,
+                                                                IDiagnostics* diag);
 
 namespace handler {
 
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index e5b3107..e5eaccc 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -31,11 +31,6 @@
 namespace aapt {
 
 namespace configuration {
-void PrintTo(const AndroidSdk& sdk, std::ostream* os) {
-  *os << "SDK: min=" << sdk.min_sdk_version
-      << ", target=" << sdk.target_sdk_version.value_or_default(-1)
-      << ", max=" << sdk.max_sdk_version.value_or_default(-1);
-}
 
 bool operator==(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) {
   return lhs.name == rhs.name && lhs.abi_group == rhs.abi_group &&
@@ -45,20 +40,6 @@
          lhs.gl_texture_group == rhs.gl_texture_group;
 }
 
-std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) {
-  PrintTo(value, &out);
-  return out;
-}
-
-void PrintTo(const ConfiguredArtifact& artifact, std::ostream* os) {
-  *os << "\n{"
-      << "\n  name: " << artifact.name << "\n  sdk: " << artifact.android_sdk
-      << "\n  abi: " << artifact.abi_group << "\n  density: " << artifact.screen_density_group
-      << "\n  locale: " << artifact.locale_group
-      << "\n  features: " << artifact.device_feature_group
-      << "\n  textures: " << artifact.gl_texture_group << "\n}\n";
-}
-
 namespace handler {
 
 namespace {
@@ -186,7 +167,7 @@
 }
 
 TEST_F(ConfigurationParserTest, ExtractConfiguration) {
-  Maybe<PostProcessingConfiguration> maybe_config =
+  std::optional<PostProcessingConfiguration> maybe_config =
       ExtractConfiguration(kValidConfig, "fake.xml", &diag_);
 
   PostProcessingConfiguration config = maybe_config.value();
@@ -928,7 +909,8 @@
 
   EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag));
 
-  const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag);
+  const std::optional<std::string>& name =
+      x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag);
   ASSERT_TRUE(name);
   EXPECT_EQ(name.value(), "something.${abix86}.apk");
 }
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp
index 41f01a0..c20b053 100644
--- a/tools/aapt2/format/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -43,7 +43,7 @@
   bool Open(const StringPiece& out_dir) {
     dir_ = out_dir.to_string();
     file::FileType type = file::GetFileType(dir_);
-    if (type == file::FileType::kNonexistant) {
+    if (type == file::FileType::kNonExistant) {
       error_ = "directory does not exist";
       return false;
     } else if (type != file::FileType::kDirectory) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 8139d73..cd1c0af 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -123,7 +123,7 @@
       return ::testing::AssertionFailure() << "failed to find resource name";
     }
 
-    Maybe<ResourceName> resName = ResourceUtils::ToResourceName(actual_name);
+    std::optional<ResourceName> resName = ResourceUtils::ToResourceName(actual_name);
     if (!resName) {
       return ::testing::AssertionFailure()
              << "expected name '" << expected_res_name << "' but got '"
@@ -423,7 +423,7 @@
   ResourceTable result;
   ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
 
-  Maybe<ResourceTable::SearchResult> search_result =
+  std::optional<ResourceTable::SearchResult> search_result =
       result.FindResource(test::ParseNameOrDie("lib:id/foo"));
   ASSERT_TRUE(search_result);
   EXPECT_EQ(0x00u, search_result.value().entry->id.value().package_id());
@@ -454,7 +454,7 @@
   ResourceTable result;
   ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
 
-  Maybe<ResourceTable::SearchResult> search_result =
+  std::optional<ResourceTable::SearchResult> search_result =
       result.FindResource(test::ParseNameOrDie("lib:style/Theme"));
   ASSERT_TRUE(search_result);
   EXPECT_EQ(0x00030001u, search_result.value().entry->id.value());
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index afbaae4..cdbe882 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -264,7 +264,7 @@
       }
 
       std::string processed_str;
-      Maybe<StringPiece> compiled_text;
+      std::optional<StringPiece> compiled_text;
       if (xml_attr->compiled_value != nullptr) {
         // Make sure we're not flattening a String. A String can be referencing a string from
         // a different StringPool than we're using here to build the binary XML.
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 6042ba8..f3b7f75 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -438,7 +438,7 @@
 }
 
 static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref) {
-  pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
+  pb_ref->set_id(ref.id.value_or(ResourceId(0x0)).id);
 
   if (ref.name) {
     pb_ref->set_name(ref.name.value().to_string());
@@ -759,13 +759,13 @@
     pb_attr->set_namespace_uri(attr.namespace_uri);
     pb_attr->set_value(attr.value);
     if (attr.compiled_attribute) {
-      const ResourceId attr_id = attr.compiled_attribute.value().id.value_or_default({});
+      const ResourceId attr_id = attr.compiled_attribute.value().id.value_or(ResourceId{});
       pb_attr->set_resource_id(attr_id.id);
     }
     if (attr.compiled_value != nullptr) {
       SerializeItemToPb(*attr.compiled_value, pb_attr->mutable_compiled_item());
       pb::SourcePosition* pb_src = pb_attr->mutable_source();
-      pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or_default(0));
+      pb_src->set_line_number(attr.compiled_value->GetSource().line.value_or(0));
     }
   }
 
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 38c811f..d1d72e0 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -189,7 +189,7 @@
   ASSERT_THAT(new_id, NotNull());
   EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
 
-  Maybe<ResourceTable::SearchResult> result =
+  std::optional<ResourceTable::SearchResult> result =
       new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
   ASSERT_TRUE(result);
 
@@ -234,7 +234,7 @@
   EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
   EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
 
-  Maybe<ResourceTable::SearchResult> search_result =
+  std::optional<ResourceTable::SearchResult> search_result =
       new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
@@ -637,7 +637,7 @@
   ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
   EXPECT_THAT(error, IsEmpty());
 
-  Maybe<ResourceTable::SearchResult> search_result =
+  std::optional<ResourceTable::SearchResult> search_result =
       new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index e15f935..fc2e45e 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -21,11 +21,10 @@
 #include "android-base/errors.h"
 #include "androidfw/StringPiece.h"
 #include "utils/FileMap.h"
-
 #include "Source.h"
 #include "io/FileStream.h"
 #include "util/Files.h"
-#include "util/Maybe.h"
+
 #include "util/Util.h"
 
 using ::android::StringPiece;
@@ -38,7 +37,7 @@
 
 std::unique_ptr<IData> RegularFile::OpenAsData() {
   android::FileMap map;
-  if (Maybe<android::FileMap> map = file::MmapPath(source_.path, nullptr)) {
+  if (std::optional<android::FileMap> map = file::MmapPath(source_.path, nullptr)) {
     if (map.value().getDataPtr() && map.value().getDataLength() > 0) {
       return util::make_unique<MmappedData>(std::move(map.value()));
     }
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index de6524d..3b3c6e1 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -204,7 +204,7 @@
 }
 
 // Whether or not to skip writing this symbol.
-bool JavaClassGenerator::SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol) {
+bool JavaClassGenerator::SkipSymbol(const std::optional<SymbolTable::Symbol>& symbol) {
   return !symbol || (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic &&
                      !symbol.value().is_public);
 }
@@ -212,12 +212,12 @@
 struct StyleableAttr {
   const Reference* attr_ref = nullptr;
   std::string field_name;
-  Maybe<SymbolTable::Symbol> symbol;
+  std::optional<SymbolTable::Symbol> symbol;
 };
 
 static bool operator<(const StyleableAttr& lhs, const StyleableAttr& rhs) {
-  const ResourceId lhs_id = lhs.attr_ref->id.value_or_default(ResourceId(0));
-  const ResourceId rhs_id = rhs.attr_ref->id.value_or_default(ResourceId(0));
+  const ResourceId lhs_id = lhs.attr_ref->id.value_or(ResourceId(0));
+  const ResourceId rhs_id = rhs.attr_ref->id.value_or(ResourceId(0));
   if (lhs_id == rhs_id) {
     return lhs.attr_ref->name.value() < rhs.attr_ref->name.value();
   }
@@ -362,7 +362,7 @@
       array_def->AddElement(field_name);
       r_txt_contents = field_name.ref;
     } else {
-      const ResourceId attr_id = attr.attr_ref->id.value_or_default(ResourceId(0));
+      const ResourceId attr_id = attr.attr_ref->id.value_or(ResourceId(0));
       array_def->AddElement(attr_id);
       r_txt_contents = to_string(attr_id);
     }
@@ -504,9 +504,9 @@
   }
 }
 
-Maybe<std::string> JavaClassGenerator::UnmangleResource(const StringPiece& package_name,
-                                                        const StringPiece& package_name_to_generate,
-                                                        const ResourceEntry& entry) {
+std::optional<std::string> JavaClassGenerator::UnmangleResource(
+    const StringPiece& package_name, const StringPiece& package_name_to_generate,
+    const ResourceEntry& entry) {
   if (SkipSymbol(entry.visibility.level)) {
     return {};
   }
@@ -535,7 +535,7 @@
                                      MethodDefinition* out_rewrite_method_def,
                                      Printer* r_txt_printer) {
   for (const auto& entry : type.entries) {
-    const Maybe<std::string> unmangled_name =
+    const std::optional<std::string> unmangled_name =
         UnmangleResource(package.name, package_name_to_generate, *entry);
     if (!unmangled_name) {
       continue;
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index d9d1b39..b45a2f1 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -46,7 +46,7 @@
 
   // If set, generates code to rewrite the package ID of resources.
   // Implies use_final == true. Default is unset.
-  Maybe<OnResourcesLoadedCallbackOptions> rewrite_callback_options;
+  std::optional<OnResourcesLoadedCallbackOptions> rewrite_callback_options;
 
   enum class SymbolTypes {
     kAll,
@@ -83,13 +83,13 @@
 
  private:
   bool SkipSymbol(Visibility::Level state);
-  bool SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol);
+  bool SkipSymbol(const std::optional<SymbolTable::Symbol>& symbol);
 
   // Returns the unmangled resource entry name if the unmangled package is the same as
   // package_name_to_generate. Returns nothing if the resource should be skipped.
-  Maybe<std::string> UnmangleResource(const android::StringPiece& package_name,
-                                      const android::StringPiece& package_name_to_generate,
-                                      const ResourceEntry& entry);
+  std::optional<std::string> UnmangleResource(const android::StringPiece& package_name,
+                                              const android::StringPiece& package_name_to_generate,
+                                              const ResourceEntry& entry);
 
   bool ProcessType(const android::StringPiece& package_name_to_generate,
                    const ResourceTablePackage& package, const ResourceTableType& type,
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index 09ea03b..a0db41b 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -19,19 +19,17 @@
 #include <algorithm>
 
 #include "Source.h"
-#include "java/AnnotationProcessor.h"
 #include "java/ClassDefinition.h"
 #include "java/JavaClassGenerator.h"
 #include "text/Unicode.h"
-#include "util/Maybe.h"
 #include "xml/XmlDom.h"
 
 using ::aapt::text::IsJavaIdentifier;
 
 namespace aapt {
 
-static Maybe<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
-                                                const std::string& value) {
+static std::optional<std::string> ExtractJavaIdentifier(IDiagnostics* diag, const Source& source,
+                                                        const std::string& value) {
   std::string result = value;
   size_t pos = value.rfind('.');
   if (pos != std::string::npos) {
@@ -63,7 +61,7 @@
     return false;
   }
 
-  Maybe<std::string> result =
+  std::optional<std::string> result =
       ExtractJavaIdentifier(diag, source.WithLine(el->line_number), attr->value);
   if (!result) {
     return false;
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index d9a4caa..b939f35 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -48,7 +48,7 @@
 
   void Visit(xml::Element* node) override {
     if (!node->namespace_uri.empty()) {
-      Maybe<xml::ExtractedPackage> maybe_package =
+      std::optional<xml::ExtractedPackage> maybe_package =
           xml::ExtractPackageFromNamespace(node->namespace_uri);
       if (maybe_package) {
         // This is a custom view, let's figure out the class name from this.
@@ -270,14 +270,16 @@
         get_name = true;
         xml::Attribute* attr = node->FindAttribute(xml::kSchemaAndroid, "backupAgent");
         if (attr) {
-          Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value);
+          std::optional<std::string> result =
+              util::GetFullyQualifiedClassName(package_, attr->value);
           if (result) {
             AddClass(node->line_number, result.value(), "");
           }
         }
         attr = node->FindAttribute(xml::kSchemaAndroid, "appComponentFactory");
         if (attr) {
-          Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value);
+          std::optional<std::string> result =
+              util::GetFullyQualifiedClassName(package_, attr->value);
           if (result) {
             AddClass(node->line_number, result.value(), "");
           }
@@ -285,7 +287,8 @@
 
         attr = node->FindAttribute(xml::kSchemaAndroid, "zygotePreloadName");
         if (attr) {
-          Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value);
+          std::optional<std::string> result =
+              util::GetFullyQualifiedClassName(package_, attr->value);
           if (result) {
             AddClass(node->line_number, result.value(), "");
           }
@@ -317,7 +320,8 @@
         get_name = attr != nullptr;
 
         if (get_name) {
-          Maybe<std::string> result = util::GetFullyQualifiedClassName(package_, attr->value);
+          std::optional<std::string> result =
+              util::GetFullyQualifiedClassName(package_, attr->value);
           if (result) {
             AddClass(node->line_number, result.value(), "");
           }
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index 876494e..328ac97 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -90,7 +90,7 @@
           }
 
           if (Style* style = ValueCast<Style>(config_value->value.get())) {
-            Maybe<ApiVersion> min_sdk_stripped;
+            std::optional<ApiVersion> min_sdk_stripped;
             std::vector<Style::Entry> stripped;
 
             auto iter = style->entries.begin();
diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp
index 02fd00b..8179d46 100644
--- a/tools/aapt2/link/AutoVersioner_test.cpp
+++ b/tools/aapt2/link/AutoVersioner_test.cpp
@@ -87,25 +87,27 @@
   Style* style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v4"));
   ASSERT_THAT(style, NotNull());
   ASSERT_EQ(style->entries.size(), 1u);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")), style->entries.front().key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries.front().key.name);
 
   style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v13"));
   ASSERT_THAT(style, NotNull());
   ASSERT_EQ(style->entries.size(), 2u);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")),style->entries[0].key.name);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp")), style->entries[1].key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries[0].key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp"),
+            style->entries[1].key.name);
 
   style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v17"));
   ASSERT_THAT(style, NotNull());
   ASSERT_EQ(style->entries.size(), 3u);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/onClick")), style->entries[0].key.name);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp")), style->entries[1].key.name);
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/paddingStart")), style->entries[2].key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/onClick"), style->entries[0].key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/requiresSmallestWidthDp"),
+            style->entries[1].key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/paddingStart"), style->entries[2].key.name);
 
   style = test::GetValueForConfig<Style>(table.get(), "app:style/Foo", test::ParseConfigOrDie("v21"));
   ASSERT_THAT(style, NotNull());
   ASSERT_EQ(1u, style->entries.size());
-  EXPECT_EQ(make_value(test::ParseNameOrDie("android:attr/paddingEnd")), style->entries.front().key.name);
+  EXPECT_EQ(test::ParseNameOrDie("android:attr/paddingEnd"), style->entries.front().key.name);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 8abd9de..1bb0696 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -52,7 +52,7 @@
   // We allow unqualified class names (ie: .HelloActivity)
   // Since we don't know the package name, we can just make a fake one here and
   // the test will be identical as long as the real package name is valid too.
-  Maybe<std::string> fully_qualified_class_name =
+  std::optional<std::string> fully_qualified_class_name =
       util::GetFullyQualifiedClassName("a", attr->value);
 
   StringPiece qualified_class_name = fully_qualified_class_name
@@ -146,7 +146,7 @@
     // Now inject the android:isFeatureSplit="true" attribute.
     xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit);
     if (attr != nullptr) {
-      if (!ResourceUtils::ParseBool(attr->value).value_or_default(false)) {
+      if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
         // The isFeatureSplit attribute is false, which conflicts with the use
         // of "featureSplit".
         diag->Error(DiagMessage(el->line_number)
@@ -523,7 +523,8 @@
                                   const StringPiece& attr_name, xml::Element* el) {
   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
   if (attr != nullptr) {
-    if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
+    if (std::optional<std::string> new_value =
+            util::GetFullyQualifiedClassName(package, attr->value)) {
       attr->value = std::move(new_value.value());
     }
   }
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 34ad8d5..d5d1d17 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -22,7 +22,7 @@
 #include "android-base/macros.h"
 
 #include "process/IResourceTableConsumer.h"
-#include "util/Maybe.h"
+
 #include "xml/XmlActionExecutor.h"
 #include "xml/XmlDom.h"
 
@@ -30,47 +30,47 @@
 
 struct ManifestFixerOptions {
   // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a <uses-sdk> tag.
-  Maybe<std::string> min_sdk_version_default;
+  std::optional<std::string> min_sdk_version_default;
 
   // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag.
-  Maybe<std::string> target_sdk_version_default;
+  std::optional<std::string> target_sdk_version_default;
 
   // The Android package to use instead of the one defined in 'package' in <manifest>.
   // This also renames all relative package/class names in the manifest to fully qualified
   // Java names.
-  Maybe<std::string> rename_manifest_package;
+  std::optional<std::string> rename_manifest_package;
 
   // The Android package to use instead of the one defined in 'android:targetPackage' in
   // <instrumentation>.
-  Maybe<std::string> rename_instrumentation_target_package;
+  std::optional<std::string> rename_instrumentation_target_package;
 
   // The Android package to use instead of the one defined in 'android:targetPackage' in
   // <overlay>.
-  Maybe<std::string> rename_overlay_target_package;
+  std::optional<std::string> rename_overlay_target_package;
 
   // The version name to set if 'android:versionName' is not defined in <manifest> or if
   // replace_version is set.
-  Maybe<std::string> version_name_default;
+  std::optional<std::string> version_name_default;
 
   // The version code to set if 'android:versionCode' is not defined in <manifest> or if
   // replace_version is set.
-  Maybe<std::string> version_code_default;
+  std::optional<std::string> version_code_default;
 
   // The version code to set if 'android:versionCodeMajor' is not defined in <manifest> or if
   // replace_version is set.
-  Maybe<std::string> version_code_major_default;
+  std::optional<std::string> version_code_major_default;
 
   // The revision code to set if 'android:revisionCode' is not defined in <manifest> or if
   // replace_version is set.
-  Maybe<std::string> revision_code_default;
+  std::optional<std::string> revision_code_default;
 
   // The version of the framework being compiled against to set for 'android:compileSdkVersion' in
   // the <manifest> tag.
-  Maybe<std::string> compile_sdk_version;
+  std::optional<std::string> compile_sdk_version;
 
   // The version codename of the framework being compiled against to set for
   // 'android:compileSdkVersionCodename' in the <manifest> tag.
-  Maybe<std::string> compile_sdk_version_codename;
+  std::optional<std::string> compile_sdk_version_codename;
 
   // Whether validation errors should be treated only as warnings. If this is 'true', then an
   // incorrect node will not result in an error, but only as a warning, and the parsing will
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 4ac25bd..47c804c 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -190,7 +190,8 @@
  public:
   EmptyDeclStack() = default;
 
-  Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override {
+  std::optional<xml::ExtractedPackage> TransformPackageAlias(
+      const StringPiece& alias) const override {
     if (alias.empty()) {
       return xml::ExtractedPackage{{}, true /*private*/};
     }
@@ -206,7 +207,8 @@
       : alias_namespaces_(std::move(namespaces)) {
   }
 
-  Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override {
+  std::optional<xml::ExtractedPackage> TransformPackageAlias(
+      const StringPiece& alias) const override {
     if (alias.empty()) {
       return xml::ExtractedPackage{{}, true /*private*/};
     }
@@ -322,11 +324,11 @@
   return symbol;
 }
 
-Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
-                                                               const CallSite& callsite,
-                                                               IAaptContext* context,
-                                                               SymbolTable* symbols,
-                                                               std::string* out_error) {
+std::optional<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
+                                                                       const CallSite& callsite,
+                                                                       IAaptContext* context,
+                                                                       SymbolTable* symbols,
+                                                                       std::string* out_error) {
   const SymbolTable::Symbol* symbol =
       ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error);
   if (!symbol) {
diff --git a/tools/aapt2/link/ReferenceLinker.h b/tools/aapt2/link/ReferenceLinker.h
index 770f1e5..b460853 100644
--- a/tools/aapt2/link/ReferenceLinker.h
+++ b/tools/aapt2/link/ReferenceLinker.h
@@ -97,11 +97,11 @@
 
   // Resolves the attribute reference and returns an xml::AaptAttribute if successful.
   // If resolution fails, outError holds the error message.
-  static Maybe<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference,
-                                                       const CallSite& callsite,
-                                                       IAaptContext* context,
-                                                       SymbolTable* symbols,
-                                                       std::string* out_error);
+  static std::optional<xml::AaptAttribute> CompileXmlAttribute(const Reference& reference,
+                                                               const CallSite& callsite,
+                                                               IAaptContext* context,
+                                                               SymbolTable* symbols,
+                                                               std::string* out_error);
 
   // Writes the resource name to the DiagMessage, using the
   // "orig_name (aka <transformed_name>)" syntax.
diff --git a/tools/aapt2/link/ReferenceLinker_test.cpp b/tools/aapt2/link/ReferenceLinker_test.cpp
index 2d8f0d3..97bdd3e 100644
--- a/tools/aapt2/link/ReferenceLinker_test.cpp
+++ b/tools/aapt2/link/ReferenceLinker_test.cpp
@@ -317,12 +317,12 @@
                                                                 CallSite{"com.app.test"},
                                                                 context.get(), &table);
   ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010000)));
+  EXPECT_THAT(s->id, Eq(0x7f010000));
 
   s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
                                      context.get(), &table);
   ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x7f010001)));
+  EXPECT_THAT(s->id, Eq(0x7f010001));
 
   EXPECT_THAT(ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"),
                                              CallSite{"com.app.bad"}, context.get(), &table),
@@ -348,7 +348,7 @@
                                                                 CallSite{"com.app.test"},
                                                                 context.get(), &table);
   ASSERT_THAT(s, NotNull());
-  EXPECT_THAT(s->id, Eq(make_value<ResourceId>(0x80010000)));
+  EXPECT_THAT(s->id, Eq(0x80010000));
 
   s = ReferenceLinker::ResolveSymbol(*test::BuildReference("string/foo"), CallSite{"com.app.lib"},
                                      context.get(), &table);
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 22f4d18..d094d36 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -303,8 +303,8 @@
           dst_config_value->value = std::move(new_file_ref);
 
         } else {
-          Maybe<std::string> original_comment = (dst_config_value->value)
-              ? dst_config_value->value->GetComment() : Maybe<std::string>();
+          auto original_comment = (dst_config_value->value)
+              ? dst_config_value->value->GetComment() : std::optional<std::string>();
 
           dst_config_value->value = src_config_value->value->Transform(cloner);
 
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 4358fb5..4cbf2d3 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -409,8 +409,7 @@
 
   const auto expected = ResourceUtils::MakeBool(true);
   EXPECT_THAT(style->entries, Contains(Field(&Style::Entry::value, Pointee(ValueEq(*expected)))));
-  EXPECT_THAT(style->parent,
-              Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")))));
+  EXPECT_THAT(style->parent, Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")));
 }
 
 TEST_F(TableMergerTest, OverrideStyleInsteadOfOverlaying) {
@@ -483,7 +482,7 @@
   ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
 
   const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
-  Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
+  std::optional<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
@@ -517,7 +516,7 @@
   ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
 
   const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
-  Maybe<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
+  std::optional<ResourceTable::SearchResult> search_result = final_table.FindResource(name);
   ASSERT_TRUE(search_result);
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
diff --git a/tools/aapt2/link/XmlReferenceLinker.cpp b/tools/aapt2/link/XmlReferenceLinker.cpp
index aaa085e..1f8548b 100644
--- a/tools/aapt2/link/XmlReferenceLinker.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker.cpp
@@ -68,7 +68,7 @@
 
       const Attribute* attribute = &default_attribute;
 
-      if (Maybe<xml::ExtractedPackage> maybe_package =
+      if (std::optional<xml::ExtractedPackage> maybe_package =
               xml::ExtractPackageFromNamespace(attr.namespace_uri)) {
         // There is a valid package name for this attribute. We will look this up.
         Reference attr_ref(
diff --git a/tools/aapt2/link/XmlReferenceLinker_test.cpp b/tools/aapt2/link/XmlReferenceLinker_test.cpp
index ddf5b9a..6d96cf1 100644
--- a/tools/aapt2/link/XmlReferenceLinker_test.cpp
+++ b/tools/aapt2/link/XmlReferenceLinker_test.cpp
@@ -100,18 +100,18 @@
   xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "layout_width");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010000)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x01010000), xml_attr->compiled_attribute.value().id);
   EXPECT_THAT(ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()), NotNull());
 
   xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "background");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010001)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x01010001), xml_attr->compiled_attribute.value().id);
   Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get());
   ASSERT_THAT(ref, NotNull());
-  EXPECT_EQ(make_value(test::ParseNameOrDie("color/green")), ref->name);  // Make sure the name
-                                                                          // didn't change.
-  EXPECT_EQ(make_value(ResourceId(0x7f020000)), ref->id);
+  EXPECT_EQ(test::ParseNameOrDie("color/green"), ref->name);  // Make sure the name
+                                                              // didn't change.
+  EXPECT_EQ(ResourceId(0x7f020000), ref->id);
 
   xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "text");
   ASSERT_THAT(xml_attr, NotNull());
@@ -172,7 +172,7 @@
       view_el->FindAttribute(xml::BuildPackageNamespace("com.android.support"), "colorAccent");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x7f010001)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x7f010001), xml_attr->compiled_attribute.value().id);
   EXPECT_THAT(ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get()), NotNull());
 }
 
@@ -190,11 +190,11 @@
   xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAuto, "colorAccent");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x7f010000)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x7f010000), xml_attr->compiled_attribute.value().id);
   Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get());
   ASSERT_THAT(ref, NotNull());
   ASSERT_TRUE(ref->name);
-  EXPECT_EQ(make_value(ResourceId(0x7f020001)), ref->id);
+  EXPECT_EQ(ResourceId(0x7f020001), ref->id);
 }
 
 TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) {
@@ -214,10 +214,10 @@
   xml::Attribute* xml_attr = view_el->FindAttribute(xml::kSchemaAndroid, "attr");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010002)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x01010002), xml_attr->compiled_attribute.value().id);
   Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get());
   ASSERT_THAT(ref, NotNull());
-  EXPECT_EQ(make_value(ResourceId(0x01030000)), ref->id);
+  EXPECT_EQ(ResourceId(0x01030000), ref->id);
 
   ASSERT_FALSE(view_el->GetChildElements().empty());
   view_el = view_el->GetChildElements().front();
@@ -228,10 +228,10 @@
   xml_attr = view_el->FindAttribute(xml::BuildPackageNamespace("com.app.test"), "attr");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x7f010002)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x7f010002), xml_attr->compiled_attribute.value().id);
   ref = ValueCast<Reference>(xml_attr->compiled_value.get());
   ASSERT_THAT(ref, NotNull());
-  EXPECT_EQ(make_value(ResourceId(0x7f030000)), ref->id);
+  EXPECT_EQ(ResourceId(0x7f030000), ref->id);
 }
 
 TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) {
@@ -250,10 +250,10 @@
   xml::Attribute* xml_attr = view_el->FindAttribute(xml::BuildPackageNamespace("com.app.test"), "attr");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x7f010002)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x7f010002), xml_attr->compiled_attribute.value().id);
   Reference* ref = ValueCast<Reference>(xml_attr->compiled_value.get());
   ASSERT_THAT(ref, NotNull());
-  EXPECT_EQ(make_value(ResourceId(0x7f030000)), ref->id);
+  EXPECT_EQ(ResourceId(0x7f030000), ref->id);
 }
 
 
@@ -270,7 +270,7 @@
   xml::Attribute* xml_attr = gradient_el->FindAttribute(xml::kSchemaAndroid, "angle");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010004)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x01010004), xml_attr->compiled_attribute.value().id);
 
   BinaryPrimitive* value = ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get());
   ASSERT_THAT(value, NotNull());
@@ -292,7 +292,7 @@
   xml::Attribute* xml_attr = gradient_el->FindAttribute(xml::kSchemaAndroid, "angle");
   ASSERT_THAT(xml_attr, NotNull());
   ASSERT_TRUE(xml_attr->compiled_attribute);
-  EXPECT_EQ(make_value(ResourceId(0x01010004)), xml_attr->compiled_attribute.value().id);
+  EXPECT_EQ(ResourceId(0x01010004), xml_attr->compiled_attribute.value().id);
 
   BinaryPrimitive* value = ValueCast<BinaryPrimitive>(xml_attr->compiled_value.get());
   ASSERT_THAT(value, NotNull());
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index d385267..2d58cbf 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -75,8 +75,8 @@
 
   // Fill in the package name if necessary.
   // If there is no package in `name`, we will need to copy the ResourceName
-  // and store it somewhere; we use the Maybe<> class to reserve storage.
-  Maybe<ResourceName> name_with_package_impl;
+  // and store it somewhere; we use the std::optional<> class to reserve storage.
+  std::optional<ResourceName> name_with_package_impl;
   if (name.package.empty()) {
     name_with_package_impl = ResourceName(mangler_->GetTargetPackageName(), name.type, name.entry);
     name_with_package = &name_with_package_impl.value();
@@ -88,9 +88,9 @@
   }
 
   // The name was not found in the cache. Mangle it (if necessary) and find it in our sources.
-  // Again, here we use a Maybe<> object to reserve storage if we need to mangle.
+  // Again, here we use a std::optional<> object to reserve storage if we need to mangle.
   const ResourceName* mangled_name = name_with_package;
-  Maybe<ResourceName> mangled_name_impl;
+  std::optional<ResourceName> mangled_name_impl;
   if (mangler_->ShouldMangle(name_with_package->package)) {
     mangled_name_impl = mangler_->MangleName(*name_with_package);
     mangled_name = &mangled_name_impl.value();
@@ -183,7 +183,7 @@
 
 std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::FindByName(
     const ResourceName& name) {
-  Maybe<ResourceTable::SearchResult> result = table_->FindResource(name);
+  std::optional<ResourceTable::SearchResult> result = table_->FindResource(name);
   if (!result) {
     if (name.type == ResourceType::kAttr) {
       // Recurse and try looking up a private attribute.
@@ -306,7 +306,7 @@
         return nullptr;
       }
 
-      Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name);
+      std::optional<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name);
       if (!parsed_name) {
         return nullptr;
       }
@@ -382,8 +382,7 @@
   return {};
 }
 
-static Maybe<ResourceName> GetResourceName(android::AssetManager2& am,
-                                           ResourceId id) {
+static std::optional<ResourceName> GetResourceName(android::AssetManager2& am, ResourceId id) {
   auto name = am.GetResourceName(id.id);
   if (!name.has_value()) {
     return {};
@@ -402,7 +401,7 @@
     return {};
   }
 
-  Maybe<ResourceName> maybe_name = GetResourceName(asset_manager_, id);
+  std::optional<ResourceName> maybe_name = GetResourceName(asset_manager_, id);
   if (!maybe_name) {
     return {};
   }
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 06eaf63..65ae7be 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -56,7 +56,7 @@
   struct Symbol {
     Symbol() = default;
 
-    explicit Symbol(const Maybe<ResourceId>& i, const std::shared_ptr<Attribute>& attr = {},
+    explicit Symbol(const std::optional<ResourceId>& i, const std::shared_ptr<Attribute>& attr = {},
                     bool pub = false)
         : id(i), attribute(attr), is_public(pub) {
     }
@@ -66,7 +66,7 @@
     Symbol& operator=(const Symbol&) = default;
     Symbol& operator=(Symbol&&) = default;
 
-    Maybe<ResourceId> id;
+    std::optional<ResourceId> id;
     std::shared_ptr<Attribute> attribute;
     bool is_public = false;
     bool is_dynamic = false;
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 4816596..23331de 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -159,7 +159,8 @@
   return std::move(table_);
 }
 
-std::unique_ptr<Reference> BuildReference(const StringPiece& ref, const Maybe<ResourceId>& id) {
+std::unique_ptr<Reference> BuildReference(const StringPiece& ref,
+                                          const std::optional<ResourceId>& id) {
   std::unique_ptr<Reference> reference = util::make_unique<Reference>(ParseNameOrDie(ref));
   reference->id = id;
   return reference;
@@ -218,7 +219,8 @@
   return std::move(style_);
 }
 
-StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str, const Maybe<ResourceId>& id) {
+StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str,
+                                            const std::optional<ResourceId>& id) {
   styleable_->entries.push_back(Reference(ParseNameOrDie(str)));
   styleable_->entries.back().id = id;
   return *this;
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 3ff955d..55778ae 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -29,7 +29,6 @@
 #include "configuration/ConfigurationParser.internal.h"
 #include "process/IResourceTableConsumer.h"
 #include "test/Common.h"
-#include "util/Maybe.h"
 #include "xml/XmlDom.h"
 
 namespace aapt {
@@ -86,7 +85,7 @@
 };
 
 std::unique_ptr<Reference> BuildReference(const android::StringPiece& ref,
-                                          const Maybe<ResourceId>& id = {});
+                                          const std::optional<ResourceId>& id = {});
 std::unique_ptr<BinaryPrimitive> BuildPrimitive(uint8_t type, uint32_t data);
 
 template <typename T>
@@ -149,7 +148,8 @@
 class StyleableBuilder {
  public:
   StyleableBuilder() = default;
-  StyleableBuilder& AddItem(const android::StringPiece& str, const Maybe<ResourceId>& id = {});
+  StyleableBuilder& AddItem(const android::StringPiece& str,
+                            const std::optional<ResourceId>& id = {});
   std::unique_ptr<Styleable> Build();
 
  private:
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index 23c2218..e029d02 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -48,7 +48,7 @@
                                           const android::StringPiece& res_name,
                                           const ConfigDescription& config,
                                           const android::StringPiece& product) {
-  Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
+  std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
   if (result) {
     ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
     if (config_value) {
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 777ca5c..7006964 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -55,7 +55,7 @@
 T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name,
                                const android::ConfigDescription& config,
                                const android::StringPiece& product) {
-  Maybe<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
+  std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
   if (result) {
     ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
     if (config_value) {
@@ -130,7 +130,7 @@
 
 // Add a print method to Maybe.
 template <typename T>
-void PrintTo(const Maybe<T>& value, std::ostream* out) {
+void PrintTo(const std::optional<T>& value, std::ostream* out) {
   if (value) {
     *out << ::testing::PrintToString(value.value());
   } else {
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 5d8ded3..e1b8dd5 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -95,8 +95,8 @@
   friend class ContextBuilder;
 
   PackageType package_type_ = PackageType::kApp;
-  Maybe<std::string> compilation_package_;
-  Maybe<uint8_t> package_id_;
+  std::optional<std::string> compilation_package_;
+  std::optional<uint8_t> package_id_;
   StdErrDiagnostics diagnostics_;
   NameMangler name_mangler_;
   SymbolTable symbols_;
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 285e5a1..e2f71dc 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -126,7 +126,7 @@
   link_args.insert(link_args.end(), {"-I", android_sdk});
 
   // Add the files from the compiled resources directory to the link file arguments
-  Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
+  std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
   if (compiled_files) {
     for (std::string& compile_file : compiled_files.value()) {
       compile_file = file::BuildPath({flat_dir, compile_file});
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5d57de6..5d2eda3 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -50,12 +50,12 @@
 FileType GetFileType(const std::string& path) {
   std::wstring path_utf16;
   if (!::android::base::UTF8PathToWindowsLongPath(path.c_str(), &path_utf16)) {
-    return FileType::kNonexistant;
+    return FileType::kNonExistant;
   }
 
   DWORD result = GetFileAttributesW(path_utf16.c_str());
   if (result == INVALID_FILE_ATTRIBUTES) {
-    return FileType::kNonexistant;
+    return FileType::kNonExistant;
   }
 
   if (result & FILE_ATTRIBUTE_DIRECTORY) {
@@ -72,7 +72,7 @@
 
   if (result == -1) {
     if (errno == ENOENT || errno == ENOTDIR) {
-      return FileType::kNonexistant;
+      return FileType::kNonExistant;
     }
     return FileType::kUnknown;
   }
@@ -208,7 +208,7 @@
   return out_path;
 }
 
-Maybe<FileMap> MmapPath(const std::string& path, std::string* out_error) {
+std::optional<FileMap> MmapPath(const std::string& path, std::string* out_error) {
   int flags = O_RDONLY | O_CLOEXEC | O_BINARY;
   unique_fd fd(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), flags)));
   if (fd == -1) {
@@ -344,8 +344,8 @@
   return true;
 }
 
-Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDiagnostics* diag,
-                                          const FileFilter* filter) {
+std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
+                                                  IDiagnostics* diag, const FileFilter* filter) {
   const std::string root_dir = path.to_string();
   std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
   if (!d) {
@@ -382,7 +382,7 @@
   for (const std::string& subdir : subdirs) {
     std::string full_subdir = root_dir;
     AppendPath(&full_subdir, subdir);
-    Maybe<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter);
+    std::optional<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter);
     if (!subfiles) {
       return {};
     }
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 481a4cd..877cd56 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -18,6 +18,7 @@
 #define AAPT_FILES_H
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <unordered_set>
 #include <vector>
@@ -27,7 +28,6 @@
 #include "utils/FileMap.h"
 
 #include "Diagnostics.h"
-#include "Maybe.h"
 #include "Source.h"
 
 namespace aapt {
@@ -43,7 +43,7 @@
 
 enum class FileType {
   kUnknown = 0,
-  kNonexistant,
+  kNonExistant,
   kRegular,
   kDirectory,
   kCharDev,
@@ -81,7 +81,7 @@
 std::string PackageToPath(const android::StringPiece& package);
 
 // Creates a FileMap for the file at path.
-Maybe<android::FileMap> MmapPath(const std::string& path, std::string* out_error);
+std::optional<android::FileMap> MmapPath(const std::string& path, std::string* out_error);
 
 // Reads the file at path and appends each line to the outArgList vector.
 bool AppendArgsFromFile(const android::StringPiece& path, std::vector<std::string>* out_arglist,
@@ -124,8 +124,9 @@
 
 // Returns a list of files relative to the directory identified by `path`.
 // An optional FileFilter filters out any files that don't pass.
-Maybe<std::vector<std::string>> FindFiles(const android::StringPiece& path, IDiagnostics* diag,
-                                          const FileFilter* filter = nullptr);
+std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
+                                                  IDiagnostics* diag,
+                                                  const FileFilter* filter = nullptr);
 
 }  // namespace file
 }  // namespace aapt
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
deleted file mode 100644
index 047e1a5..0000000
--- a/tools/aapt2/util/Maybe.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AAPT_MAYBE_H
-#define AAPT_MAYBE_H
-
-#include <type_traits>
-#include <utility>
-
-#include "android-base/logging.h"
-
-#include "util/TypeTraits.h"
-
-namespace aapt {
-
-/**
- * Either holds a valid value of type T, or holds Nothing.
- * The value is stored inline in this structure, so no
- * heap memory is used when creating a Maybe<T> object.
- */
-template <typename T>
-class Maybe {
- public:
-  /**
-   * Construct Nothing.
-   */
-  Maybe();
-
-  ~Maybe();
-
-  Maybe(const Maybe& rhs);
-
-  template <typename U>
-  Maybe(const Maybe<U>& rhs);  // NOLINT(google-explicit-constructor)
-
-  Maybe(Maybe&& rhs) noexcept;
-
-  template <typename U>
-  Maybe(Maybe<U>&& rhs);  // NOLINT(google-explicit-constructor)
-
-  Maybe& operator=(const Maybe& rhs);
-
-  template <typename U>
-  Maybe& operator=(const Maybe<U>& rhs);
-
-  Maybe& operator=(Maybe&& rhs) noexcept;
-
-  template <typename U>
-  Maybe& operator=(Maybe<U>&& rhs);
-
-  /**
-   * Construct a Maybe holding a value.
-   */
-  Maybe(const T& value);  // NOLINT(google-explicit-constructor)
-
-  /**
-   * Construct a Maybe holding a value.
-   */
-  Maybe(T&& value);  // NOLINT(google-explicit-constructor)
-
-  /**
-   * True if this holds a value, false if
-   * it holds Nothing.
-   */
-  explicit operator bool() const;
-
-  /**
-   * Gets the value if one exists, or else
-   * panics.
-   */
-  T& value();
-
-  /**
-   * Gets the value if one exists, or else
-   * panics.
-   */
-  const T& value() const;
-
-  T value_or_default(const T& def) const;
-
- private:
-  template <typename U>
-  friend class Maybe;
-
-  template <typename U>
-  Maybe& copy(const Maybe<U>& rhs);
-
-  template <typename U>
-  Maybe& move(Maybe<U>&& rhs);
-
-  void destroy();
-
-  bool nothing_;
-
-  typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
-};
-
-template <typename T>
-Maybe<T>::Maybe() : nothing_(true) {}
-
-template <typename T>
-Maybe<T>::~Maybe() {
-  if (!nothing_) {
-    destroy();
-  }
-}
-
-template <typename T>
-Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) {
-  if (!rhs.nothing_) {
-    new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_));
-  }
-}
-
-template <typename T>
-template <typename U>
-Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) {
-  if (!rhs.nothing_) {
-    new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
-  }
-}
-
-template <typename T>
-Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) {
-  if (!rhs.nothing_) {
-    rhs.nothing_ = true;
-
-    // Move the value from rhs.
-    new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_)));
-    rhs.destroy();
-  }
-}
-
-template <typename T>
-template <typename U>
-Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) {
-  if (!rhs.nothing_) {
-    rhs.nothing_ = true;
-
-    // Move the value from rhs.
-    new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
-    rhs.destroy();
-  }
-}
-
-template <typename T>
-inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) {
-  // Delegate to the actual assignment.
-  return copy(rhs);
-}
-
-template <typename T>
-template <typename U>
-inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
-  return copy(rhs);
-}
-
-template <typename T>
-template <typename U>
-Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) {
-  if (nothing_ && rhs.nothing_) {
-    // Both are nothing, nothing to do.
-    return *this;
-  } else if (!nothing_ && !rhs.nothing_) {
-    // We both are something, so assign rhs to us.
-    reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_);
-  } else if (nothing_) {
-    // We are nothing but rhs is something.
-    nothing_ = rhs.nothing_;
-
-    // Copy the value from rhs.
-    new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_));
-  } else {
-    // We are something but rhs is nothing, so destroy our value.
-    nothing_ = rhs.nothing_;
-    destroy();
-  }
-  return *this;
-}
-
-template <typename T>
-inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept {
-  // Delegate to the actual assignment.
-  return move(std::forward<Maybe<T>>(rhs));
-}
-
-template <typename T>
-template <typename U>
-inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
-  return move(std::forward<Maybe<U>>(rhs));
-}
-
-template <typename T>
-template <typename U>
-Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) {
-  if (nothing_ && rhs.nothing_) {
-    // Both are nothing, nothing to do.
-    return *this;
-  } else if (!nothing_ && !rhs.nothing_) {
-    // We both are something, so move assign rhs to us.
-    rhs.nothing_ = true;
-    reinterpret_cast<T&>(storage_) =
-        std::move(reinterpret_cast<U&>(rhs.storage_));
-    rhs.destroy();
-  } else if (nothing_) {
-    // We are nothing but rhs is something.
-    nothing_ = false;
-    rhs.nothing_ = true;
-
-    // Move the value from rhs.
-    new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_)));
-    rhs.destroy();
-  } else {
-    // We are something but rhs is nothing, so destroy our value.
-    nothing_ = true;
-    destroy();
-  }
-  return *this;
-}
-
-template <typename T>
-Maybe<T>::Maybe(const T& value) : nothing_(false) {
-  new (&storage_) T(value);
-}
-
-template <typename T>
-Maybe<T>::Maybe(T&& value) : nothing_(false) {
-  new (&storage_) T(std::forward<T>(value));
-}
-
-template <typename T>
-Maybe<T>::operator bool() const {
-  return !nothing_;
-}
-
-template <typename T>
-T& Maybe<T>::value() {
-  CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
-  return reinterpret_cast<T&>(storage_);
-}
-
-template <typename T>
-const T& Maybe<T>::value() const {
-  CHECK(!nothing_) << "Maybe<T>::value() called on Nothing";
-  return reinterpret_cast<const T&>(storage_);
-}
-
-template <typename T>
-T Maybe<T>::value_or_default(const T& def) const {
-  if (nothing_) {
-    return def;
-  }
-  return reinterpret_cast<const T&>(storage_);
-}
-
-template <typename T>
-void Maybe<T>::destroy() {
-  reinterpret_cast<T&>(storage_).~T();
-}
-
-template <typename T>
-inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
-  return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
-}
-
-template <typename T>
-inline Maybe<T> make_nothing() {
-  return Maybe<T>();
-}
-
-// Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined.
-// That way the compiler will show an error at the callsite when comparing two Maybe<> objects
-// whose inner types can't be compared.
-template <typename T, typename U>
-typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a,
-                                                                       const Maybe<U>& b) {
-  if (a && b) {
-    return a.value() == b.value();
-  } else if (!a && !b) {
-    return true;
-  }
-  return false;
-}
-
-template <typename T, typename U>
-typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a,
-                                                                       const U& b) {
-  return a ? a.value() == b : false;
-}
-
-// Same as operator== but negated.
-template <typename T, typename U>
-typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(const Maybe<T>& a,
-                                                                       const Maybe<U>& b) {
-  return !(a == b);
-}
-
-template <typename T, typename U>
-typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a,
-                                                                      const Maybe<U>& b) {
-  if (a && b) {
-    return a.value() < b.value();
-  } else if (!a && !b) {
-    return false;
-  }
-  return !a;
-}
-
-}  // namespace aapt
-
-#endif  // AAPT_MAYBE_H
diff --git a/tools/aapt2/util/Maybe_test.cpp b/tools/aapt2/util/Maybe_test.cpp
deleted file mode 100644
index 4c921f1..0000000
--- a/tools/aapt2/util/Maybe_test.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "util/Maybe.h"
-
-#include <string>
-
-#include "test/Test.h"
-
-namespace aapt {
-
-struct Fake {
-  Fake() {
-    data = new int;
-    *data = 1;
-    std::cerr << "Construct Fake{0x" << (void*)this << "} with data=0x"
-              << (void*)data << std::endl;
-  }
-
-  Fake(const Fake& rhs) {
-    data = nullptr;
-    if (rhs.data) {
-      data = new int;
-      *data = *rhs.data;
-    }
-    std::cerr << "CopyConstruct Fake{0x" << (void*)this << "} from Fake{0x"
-              << (const void*)&rhs << "}" << std::endl;
-  }
-
-  Fake(Fake&& rhs) {
-    data = rhs.data;
-    rhs.data = nullptr;
-    std::cerr << "MoveConstruct Fake{0x" << (void*)this << "} from Fake{0x"
-              << (const void*)&rhs << "}" << std::endl;
-  }
-
-  Fake& operator=(const Fake& rhs) {
-    delete data;
-    data = nullptr;
-
-    if (rhs.data) {
-      data = new int;
-      *data = *rhs.data;
-    }
-    std::cerr << "CopyAssign Fake{0x" << (void*)this << "} from Fake{0x"
-              << (const void*)&rhs << "}" << std::endl;
-    return *this;
-  }
-
-  Fake& operator=(Fake&& rhs) {
-    delete data;
-    data = rhs.data;
-    rhs.data = nullptr;
-    std::cerr << "MoveAssign Fake{0x" << (void*)this << "} from Fake{0x"
-              << (const void*)&rhs << "}" << std::endl;
-    return *this;
-  }
-
-  ~Fake() {
-    std::cerr << "Destruct Fake{0x" << (void*)this << "} with data=0x"
-              << (void*)data << std::endl;
-    delete data;
-  }
-
-  int* data;
-};
-
-TEST(MaybeTest, MakeNothing) {
-  Maybe<int> val = make_nothing<int>();
-  EXPECT_FALSE(val);
-
-  Maybe<std::string> val2 = make_nothing<std::string>();
-  EXPECT_FALSE(val2);
-
-  val2 = make_nothing<std::string>();
-  EXPECT_FALSE(val2);
-}
-
-TEST(MaybeTest, MakeSomething) {
-  Maybe<int> val = make_value(23);
-  ASSERT_TRUE(val);
-  EXPECT_EQ(23, val.value());
-
-  Maybe<std::string> val2 = make_value(std::string("hey"));
-  ASSERT_TRUE(val2);
-  EXPECT_EQ(std::string("hey"), val2.value());
-}
-
-TEST(MaybeTest, Lifecycle) {
-  Maybe<Fake> val = make_nothing<Fake>();
-
-  Maybe<Fake> val2 = make_value(Fake());
-}
-
-TEST(MaybeTest, MoveAssign) {
-  Maybe<Fake> val;
-  {
-    Maybe<Fake> val2 = Fake();
-    val = std::move(val2);
-  }
-}
-
-TEST(MaybeTest, Equality) {
-  Maybe<int> a = 1;
-  Maybe<int> b = 1;
-  Maybe<int> c;
-
-  Maybe<int> emptyA, emptyB;
-
-  EXPECT_EQ(a, b);
-  EXPECT_EQ(b, a);
-  EXPECT_NE(a, c);
-  EXPECT_EQ(emptyA, emptyB);
-}
-
-}  // namespace aapt
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index d7a8e6f..44b4ec1 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -28,7 +28,6 @@
 #include "text/Unicode.h"
 #include "text/Utf8Iterator.h"
 #include "util/BigBuffer.h"
-#include "util/Maybe.h"
 #include "utils/Unicode.h"
 
 using ::aapt::text::Utf8Iterator;
@@ -193,8 +192,8 @@
   return IsAndroidNameImpl(str) > 0;
 }
 
-Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
-                                              const StringPiece& classname) {
+std::optional<std::string> GetFullyQualifiedClassName(const StringPiece& package,
+                                                      const StringPiece& classname) {
   if (classname.empty()) {
     return {};
   }
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index c77aca3..c3efe6a 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -28,7 +28,6 @@
 #include "utils/ByteOrder.h"
 
 #include "util/BigBuffer.h"
-#include "util/Maybe.h"
 
 #ifdef _WIN32
 // TODO(adamlesinski): remove once http://b/32447322 is resolved.
@@ -105,8 +104,8 @@
 // .asdf        --> package.asdf
 // .a.b         --> package.a.b
 // asdf.adsf    --> asdf.adsf
-Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
-                                              const android::StringPiece& class_name);
+std::optional<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
+                                                      const android::StringPiece& class_name);
 
 // Retrieves the formatted name of aapt2.
 const char* GetToolName();
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 2cdcfe4..8b7eadf9 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -545,7 +545,7 @@
 void PackageAwareVisitor::BeforeVisitElement(Element* el) {
   std::vector<PackageDecl> decls;
   for (const NamespaceDecl& decl : el->namespace_decls) {
-    if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
+    if (std::optional<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
       decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
     }
   }
@@ -556,7 +556,8 @@
   package_decls_.pop_back();
 }
 
-Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const {
+std::optional<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
+    const StringPiece& alias) const {
   if (alias.empty()) {
     return ExtractedPackage{{}, false /*private*/};
   }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index a5b2d10..5d31804 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -65,12 +65,12 @@
 };
 
 struct AaptAttribute {
-  explicit AaptAttribute(const ::aapt::Attribute& attr, const Maybe<ResourceId>& resid = {})
+  explicit AaptAttribute(const ::aapt::Attribute& attr, const std::optional<ResourceId>& resid = {})
       : attribute(attr), id(resid) {
   }
 
   aapt::Attribute attribute;
-  Maybe<ResourceId> id;
+  std::optional<ResourceId> id;
 };
 
 // An XML attribute.
@@ -79,7 +79,7 @@
   std::string name;
   std::string value;
 
-  Maybe<AaptAttribute> compiled_attribute;
+  std::optional<AaptAttribute> compiled_attribute;
   std::unique_ptr<Item> compiled_value;
 };
 
@@ -235,7 +235,8 @@
  public:
   using Visitor::Visit;
 
-  Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override;
+  std::optional<ExtractedPackage> TransformPackageAlias(
+      const android::StringPiece& alias) const override;
 
  protected:
   PackageAwareVisitor() = default;
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index ca46d53..6c717dc 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -98,7 +98,7 @@
   // the Attribute accepts (eg: string|reference).
   ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute);
   EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id,
-              Eq(make_value(ResourceId(0x01010001u))));
+              Eq(ResourceId(0x01010001u)));
 
   EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo"));
   EXPECT_THAT(new_doc->root->attributes[0].compiled_value,
@@ -145,21 +145,19 @@
 
   void Visit(Element* el) override {
     if (el->name == "View1") {
-      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false}));
     } else if (el->name == "View2") {
-      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
-      EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false}));
+      EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false}));
     } else if (el->name == "View3") {
-      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
-      EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
-      EXPECT_THAT(TransformPackageAlias("three"),
-                  Eq(make_value(ExtractedPackage{"com.three", false})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false}));
+      EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false}));
+      EXPECT_THAT(TransformPackageAlias("three"), Eq(ExtractedPackage{"com.three", false}));
     } else if (el->name == "View4") {
-      EXPECT_THAT(TransformPackageAlias("one"), Eq(make_value(ExtractedPackage{"com.one", false})));
-      EXPECT_THAT(TransformPackageAlias("two"), Eq(make_value(ExtractedPackage{"com.two", false})));
-      EXPECT_THAT(TransformPackageAlias("three"),
-                  Eq(make_value(ExtractedPackage{"com.three", false})));
-      EXPECT_THAT(TransformPackageAlias("four"), Eq(make_value(ExtractedPackage{"", true})));
+      EXPECT_THAT(TransformPackageAlias("one"), Eq(ExtractedPackage{"com.one", false}));
+      EXPECT_THAT(TransformPackageAlias("two"), Eq(ExtractedPackage{"com.two", false}));
+      EXPECT_THAT(TransformPackageAlias("three"), Eq(ExtractedPackage{"com.three", false}));
+      EXPECT_THAT(TransformPackageAlias("four"), Eq(ExtractedPackage{"", true}));
     }
   }
 };
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index 182203d..bfa0749 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -17,7 +17,6 @@
 #include <iostream>
 #include <string>
 
-#include "util/Maybe.h"
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 #include "xml/XmlUtil.h"
@@ -84,8 +83,7 @@
   // handling of references that use namespace aliases.
   if (next_event == Event::kStartNamespace ||
       next_event == Event::kEndNamespace) {
-    Maybe<ExtractedPackage> result =
-        ExtractPackageFromNamespace(namespace_uri());
+    std::optional<ExtractedPackage> result = ExtractPackageFromNamespace(namespace_uri());
     if (next_event == Event::kStartNamespace) {
       if (result) {
         package_aliases_.emplace_back(
@@ -142,7 +140,8 @@
   return event_queue_.front().data2;
 }
 
-Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(const StringPiece& alias) const {
+std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(
+    const StringPiece& alias) const {
   if (alias.empty()) {
     return ExtractedPackage{{}, false /*private*/};
   }
@@ -308,8 +307,7 @@
                                       parser->depth_ });
 }
 
-Maybe<StringPiece> FindAttribute(const XmlPullParser* parser,
-                                 const StringPiece& name) {
+std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const StringPiece& name) {
   auto iter = parser->FindAttribute("", name);
   if (iter != parser->end_attributes()) {
     return StringPiece(util::TrimWhitespace(iter->value));
@@ -317,8 +315,8 @@
   return {};
 }
 
-Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
-                                         const StringPiece& name) {
+std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
+                                                 const StringPiece& name) {
   auto iter = parser->FindAttribute("", name);
   if (iter != parser->end_attributes()) {
     StringPiece trimmed = util::TrimWhitespace(iter->value);
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index 5da2d4b..ab34772 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -33,7 +33,6 @@
 #include "Resource.h"
 #include "io/Io.h"
 #include "process/IResourceTableConsumer.h"
-#include "util/Maybe.h"
 #include "xml/XmlUtil.h"
 
 namespace aapt {
@@ -121,7 +120,8 @@
    * If xmlns:app="http://schemas.android.com/apk/res-auto", then
    * 'package' will be set to 'defaultPackage'.
    */
-  Maybe<ExtractedPackage> TransformPackageAlias(const android::StringPiece& alias) const override;
+  std::optional<ExtractedPackage> TransformPackageAlias(
+      const android::StringPiece& alias) const override;
 
   struct PackageDecl {
     std::string prefix;
@@ -193,16 +193,16 @@
 /**
  * Finds the attribute in the current element within the global namespace.
  */
-Maybe<android::StringPiece> FindAttribute(const XmlPullParser* parser,
-                                          const android::StringPiece& name);
+std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser,
+                                                  const android::StringPiece& name);
 
 /**
  * Finds the attribute in the current element within the global namespace. The
  * attribute's value
  * must not be the empty string.
  */
-Maybe<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
-                                                  const android::StringPiece& name);
+std::optional<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
+                                                          const android::StringPiece& name);
 
 //
 // Implementation
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index 0a622b2..114b5ba 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -19,7 +19,6 @@
 #include <algorithm>
 #include <string>
 
-#include "util/Maybe.h"
 #include "util/Util.h"
 #include "xml/XmlDom.h"
 
@@ -34,8 +33,7 @@
   return result;
 }
 
-Maybe<ExtractedPackage> ExtractPackageFromNamespace(
-    const std::string& namespace_uri) {
+std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri) {
   if (util::StartsWith(namespace_uri, kSchemaPublicPrefix)) {
     StringPiece schema_prefix = kSchemaPublicPrefix;
     StringPiece package = namespace_uri;
@@ -62,7 +60,7 @@
 
 void ResolvePackage(const IPackageDeclStack* decl_stack, Reference* in_ref) {
   if (in_ref->name) {
-    if (Maybe<ExtractedPackage> transformed_package =
+    if (std::optional<ExtractedPackage> transformed_package =
             decl_stack->TransformPackageAlias(in_ref->name.value().package)) {
       ExtractedPackage& extracted_package = transformed_package.value();
       in_ref->name.value().package = std::move(extracted_package.package);
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 592a604..1ab05a9 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "ResourceValues.h"
-#include "util/Maybe.h"
 
 namespace aapt {
 namespace xml {
@@ -53,7 +52,7 @@
 //
 // Special case: if namespaceUri is http://schemas.android.com/apk/res-auto, returns an empty
 // package name.
-Maybe<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri);
+std::optional<ExtractedPackage> ExtractPackageFromNamespace(const std::string& namespace_uri);
 
 // Returns an XML Android namespace for the given package of the form:
 //   http://schemas.android.com/apk/res/<package>
@@ -69,7 +68,7 @@
   virtual ~IPackageDeclStack() = default;
 
   // Returns an ExtractedPackage struct if the alias given corresponds with a package declaration.
-  virtual Maybe<ExtractedPackage> TransformPackageAlias(
+  virtual std::optional<ExtractedPackage> TransformPackageAlias(
       const android::StringPiece& alias) const = 0;
 };
 
diff --git a/tools/aapt2/xml/XmlUtil_test.cpp b/tools/aapt2/xml/XmlUtil_test.cpp
index cbded8f..7b6ce9e 100644
--- a/tools/aapt2/xml/XmlUtil_test.cpp
+++ b/tools/aapt2/xml/XmlUtil_test.cpp
@@ -27,7 +27,7 @@
   ASSERT_FALSE(xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/res/"));
   ASSERT_FALSE(xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/prv/res/"));
 
-  Maybe<xml::ExtractedPackage> p =
+  std::optional<xml::ExtractedPackage> p =
       xml::ExtractPackageFromNamespace("http://schemas.android.com/apk/res/a");
   ASSERT_TRUE(p);
   EXPECT_EQ(std::string("a"), p.value().package);