Merge "Add API flag for AFL API" into main
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 00be9fe..376118c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1529,6 +1529,11 @@
         factory reset. -->
     <bool name="config_enableCredentialFactoryResetProtection">true</bool>
 
+    <!-- If true, then work around broken Weaver HALs that don't work reliably before the device has
+         fully booted. Setting this to true weakens a security feature; it should be done only when
+         necessary, though it is still better than not using Weaver at all. -->
+    <bool name="config_disableWeaverOnUnsecuredUsers">false</bool>
+
     <!-- Control the behavior when the user long presses the home button.
             0 - Nothing
             1 - Launch all apps intent
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 06a4d55..9ab8ad8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3958,6 +3958,7 @@
   <java-symbol type="string" name="foreground_service_multiple_separator" />
 
   <java-symbol type="bool" name="config_enableCredentialFactoryResetProtection" />
+  <java-symbol type="bool" name="config_disableWeaverOnUnsecuredUsers" />
 
   <!-- ETWS primary messages -->
   <java-symbol type="string" name="etws_primary_default_message_earthquake" />
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
new file mode 100644
index 0000000..8a77d88
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2024, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the screen that shows the 9 circle unlock widget and instructs
+     the user how to unlock their device, or make an emergency call.  This
+     is the landscape layout.  -->
+<com.android.keyguard.KeyguardPatternView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pattern_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="horizontal">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="2"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <include layout="@layout/keyguard_bouncer_message_area"/>
+
+        <com.android.systemui.bouncer.ui.BouncerMessageView
+            android:id="@+id/bouncer_message_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            androidprv:layout_constraintBottom_toTopOf="@+id/lockPatternView"
+            androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintVertical_chainStyle="packed" />
+
+        <include
+            android:id="@+id/keyguard_selector_fade_container"
+            layout="@layout/keyguard_eca"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            androidprv:layout_constraintBottom_toBottomOf="parent" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/pattern_container"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="3"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/pattern_top_guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            androidprv:layout_constraintGuide_percent="0" />
+
+        <com.android.internal.widget.LockPatternView
+            android:id="@+id/lockPatternView"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="horizontal"
+            androidprv:layout_constraintDimensionRatio="1.0"
+            androidprv:layout_constraintVertical_bias="1.0"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintBottom_toBottomOf="parent"
+            androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
new file mode 100644
index 0000000..4b8b63f
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_pin_view.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2024, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
+<com.android.keyguard.KeyguardSimPinView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_sim_pin_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="horizontal">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="2"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <include layout="@layout/keyguard_bouncer_message_area"/>
+
+        <ImageView
+            android:id="@+id/keyguard_sim"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_marginBottom="3dp"
+            android:src="@drawable/ic_lockscreen_sim"
+            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            app:tint="@color/background_protected"/>
+
+        <include
+            android:id="@+id/keyguard_esim_area"
+            layout="@layout/keyguard_esim_area"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
+
+        <com.android.keyguard.AlphaOptimizedRelativeLayout
+            android:id="@+id/pin_entry_area"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
+
+            <com.android.keyguard.PasswordTextView
+                android:id="@+id/simPinEntry"
+                style="@style/Widget.TextView.Password"
+                android:layout_width="@dimen/keyguard_security_width"
+                android:layout_height="@dimen/keyguard_password_height"
+                android:layout_centerHorizontal="true"
+                android:layout_marginRight="72dp"
+                android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
+                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
+        </com.android.keyguard.AlphaOptimizedRelativeLayout>
+
+        <include
+            android:id="@+id/keyguard_selector_fade_container"
+            layout="@layout/keyguard_eca"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            androidprv:layout_constraintBottom_toBottomOf="parent"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/sim_pin_container"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="3"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <androidx.constraintlayout.helper.widget.Flow
+            android:id="@+id/flow1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="horizontal"
+            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+            androidprv:flow_horizontalStyle="packed"
+            androidprv:flow_maxElementsWrap="3"
+            androidprv:flow_verticalBias="0.5"
+            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:flow_verticalStyle="packed"
+            androidprv:flow_wrapMode="aligned"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintBottom_toBottomOf="parent"/>
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/delete_button"
+            style="@style/NumPadKey.Delete"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key0"
+            android:contentDescription="@string/keyboardview_keycode_delete" />
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/key_enter"
+            style="@style/NumPadKey.Enter"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:contentDescription="@string/keyboardview_keycode_enter" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key2"
+            androidprv:digit="1"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key2"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key3"
+            androidprv:digit="2"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key3"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key4"
+            androidprv:digit="3"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key4"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key5"
+            androidprv:digit="4"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key5"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key6"
+            androidprv:digit="5"
+            androidprv:textView="@+id/simPinEntry" />
+
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key6"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key7"
+            androidprv:digit="6"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key7"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key8"
+            androidprv:digit="7"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key8"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key9"
+            androidprv:digit="8"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key9"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/delete_button"
+            androidprv:digit="9"
+            androidprv:textView="@+id/simPinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key0"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key_enter"
+            androidprv:digit="0"
+            androidprv:textView="@+id/simPinEntry" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
new file mode 100644
index 0000000..9012856
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout-land/keyguard_sim_puk_view.xml
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2024, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<!-- This is the SIM PUK view that allows the user to recover their device by entering the
+    carrier-provided PUK code and entering a new SIM PIN for it. -->
+<com.android.keyguard.KeyguardSimPukView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_sim_puk_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="horizontal">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="2"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <include layout="@layout/keyguard_bouncer_message_area"/>
+
+        <ImageView
+            android:id="@+id/keyguard_sim"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_marginBottom="3dp"
+            android:src="@drawable/ic_lockscreen_sim"
+            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            app:tint="@color/background_protected"/>
+
+        <include
+            android:id="@+id/keyguard_esim_area"
+            layout="@layout/keyguard_esim_area"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintBottom_toTopOf="@+id/pin_entry_area"/>
+
+        <com.android.keyguard.AlphaOptimizedRelativeLayout
+            android:id="@+id/pin_entry_area"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container">
+
+            <com.android.keyguard.PasswordTextView
+                android:id="@+id/pukEntry"
+                style="@style/Widget.TextView.Password"
+                android:layout_width="@dimen/keyguard_security_width"
+                android:layout_height="@dimen/keyguard_password_height"
+                android:layout_centerHorizontal="true"
+                android:layout_marginRight="72dp"
+                android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
+                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
+        </com.android.keyguard.AlphaOptimizedRelativeLayout>
+
+        <include
+            android:id="@+id/keyguard_selector_fade_container"
+            layout="@layout/keyguard_eca"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            androidprv:layout_constraintBottom_toBottomOf="parent"/>
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/sim_puk_container"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="3"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <androidx.constraintlayout.helper.widget.Flow
+            android:id="@+id/flow1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="horizontal"
+            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+            androidprv:flow_horizontalStyle="packed"
+            androidprv:flow_maxElementsWrap="3"
+            androidprv:flow_verticalBias="0.5"
+            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:flow_verticalStyle="packed"
+            androidprv:flow_wrapMode="aligned"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintBottom_toBottomOf="parent"/>
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/delete_button"
+            style="@style/NumPadKey.Delete"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key0"
+            android:contentDescription="@string/keyboardview_keycode_delete" />
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/key_enter"
+            style="@style/NumPadKey.Enter"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:contentDescription="@string/keyboardview_keycode_enter" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key2"
+            androidprv:digit="1"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key2"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key3"
+            androidprv:digit="2"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key3"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key4"
+            androidprv:digit="3"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key4"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key5"
+            androidprv:digit="4"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key5"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key6"
+            androidprv:digit="5"
+            androidprv:textView="@+id/pukEntry" />
+
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key6"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key7"
+            androidprv:digit="6"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key7"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key8"
+            androidprv:digit="7"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key8"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key9"
+            androidprv:digit="8"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key9"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/delete_button"
+            androidprv:digit="9"
+            androidprv:textView="@+id/pukEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key0"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key_enter"
+            androidprv:digit="0"
+            androidprv:textView="@+id/pukEntry" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.keyguard.KeyguardSimPukView>
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index 7151c42..7031b2b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -80,8 +80,9 @@
         `when`(telephonyManager.createForSubscriptionId(anyInt())).thenReturn(telephonyManager)
         `when`(telephonyManager.supplyIccLockPin(anyString())).thenReturn(mock())
         simPinView =
-            LayoutInflater.from(context).inflate(R.layout.keyguard_sim_pin_view, null)
-                as KeyguardSimPinView
+            LayoutInflater.from(context)
+                .inflate(R.layout.keyguard_sim_pin_view, null)
+                .requireViewById(R.id.keyguard_sim_pin_view) as KeyguardSimPinView
         val fakeFeatureFlags = FakeFeatureFlags()
         val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
 
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index 86246e2..72f62c5 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -5,7 +5,8 @@
     { "name": "hoststubgen-test-tiny-test" },
     { "name": "hoststubgen-invoke-test" },
     { "name": "RavenwoodMockitoTest_device" },
-    { "name": "RavenwoodBivalentTest_device" },
+    // TODO(b/371215487): Re-enable when the test is fixed.
+    // { "name": "RavenwoodBivalentTest_device" },
 
     { "name": "RavenwoodBivalentInstTest_nonself_inst" },
     { "name": "RavenwoodBivalentInstTest_self_inst_device" },
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 3780fbd..bbdac56 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -99,6 +99,7 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -126,6 +127,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.LongSparseArray;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -253,6 +255,8 @@
     private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace";
     private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce";
     private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys";
+    private static final String MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS =
+            "migrated_weaver_disabled_on_unsecured_users";
 
     // Duration that LockSettingsService will store the gatekeeper password for. This allows
     // multiple biometric enrollments without prompting the user to enter their password via
@@ -309,6 +313,10 @@
     @GuardedBy("mUserCreationAndRemovalLock")
     private boolean mThirdPartyAppsStarted;
 
+    // This list contains the (protectorId, userId) of any protectors that were by replaced by a
+    // migration and should be destroyed once rollback to the old build is no longer possible.
+    private ArrayList<Pair<Long, Integer>> mProtectorsToDestroyOnBootCompleted = new ArrayList<>();
+
     // Current password metrics for all secured users on the device. Updated when user unlocks the
     // device or changes password. Removed if user is stopped with its CE key evicted.
     @GuardedBy("this")
@@ -363,6 +371,10 @@
                 mLockSettingsService.migrateOldDataAfterSystemReady();
                 mLockSettingsService.deleteRepairModePersistentDataIfNeeded();
             } else if (phase == PHASE_BOOT_COMPLETED) {
+                // In the case of an upgrade, PHASE_BOOT_COMPLETED means that a rollback to the old
+                // build can no longer occur.  This is the time to destroy any migrated protectors.
+                mLockSettingsService.destroyMigratedProtectors();
+
                 mLockSettingsService.loadEscrowData();
             }
         }
@@ -1076,6 +1088,11 @@
         mStorage.deleteRepairModePersistentData();
     }
 
+    private boolean isWeaverDisabledOnUnsecuredUsers() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers);
+    }
+
     // This is called when Weaver is guaranteed to be available (if the device supports Weaver).
     // It does any synthetic password related work that was delayed from earlier in the boot.
     private void onThirdPartyAppsStarted() {
@@ -1114,13 +1131,20 @@
             //
             // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys.
             //
+            // - Upgrading from a build with config_disableWeaverOnUnsecuredUsers=false to one with
+            //   config_disableWeaverOnUnsecuredUsers=true.  (We don't bother to proactively add
+            //   Weaver for the reverse update to false, as it's too late to help in that case.)
+            //
             // The end result is that all users, regardless of whether they are secured or not, have
-            // a synthetic password with all keys initialized and protected by it.
+            // a synthetic password with all keys initialized and protected by it, and honoring
+            // config_disableWeaverOnUnsecuredUsers=true when applicable.
             //
             // Note: if this migration gets interrupted (e.g. by the device powering off), there
             // shouldn't be a problem since this will run again on the next boot, and
             // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent.
-            if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
+            if (!getBoolean(MIGRATED_SP_FULL, false, 0)
+                    || (isWeaverDisabledOnUnsecuredUsers()
+                        && !getBoolean(MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS, false, 0))) {
                 for (UserInfo user : mUserManager.getAliveUsers()) {
                     removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
                     synchronized (mSpManager) {
@@ -1128,6 +1152,9 @@
                     }
                 }
                 setBoolean(MIGRATED_SP_FULL, true, 0);
+                if (isWeaverDisabledOnUnsecuredUsers()) {
+                    setBoolean(MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS, true, 0);
+                }
             }
 
             mThirdPartyAppsStarted = true;
@@ -1151,13 +1178,61 @@
                 getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId,
                 null);
         SyntheticPassword sp = result.syntheticPassword;
-        if (sp == null) {
+        if (isWeaverDisabledOnUnsecuredUsers()) {
+            Slog.i(TAG, "config_disableWeaverOnUnsecuredUsers=true");
+
+            // If config_disableWeaverOnUnsecuredUsers=true, then the Weaver HAL may be buggy and
+            // need multiple retries before it works here to unwrap the SP, if the SP was already
+            // protected by Weaver.  Note that the problematic HAL can also deadlock if called with
+            // the ActivityManagerService lock held, but that should not be a problem here since
+            // that lock isn't held here, unlike unlockUserKeyIfUnsecured() where it is.
+            for (int i = 0; i < 12 && sp == null; i++) {
+                Slog.e(TAG, "Failed to unwrap synthetic password. Waiting 5 seconds to retry.");
+                SystemClock.sleep(5000);
+                result = mSpManager.unlockLskfBasedProtector(getGateKeeperService(), protectorId,
+                            LockscreenCredential.createNone(), userId, null);
+                sp = result.syntheticPassword;
+            }
+            if (sp == null) {
+                throw new IllegalStateException(
+                        "Failed to unwrap synthetic password for unsecured user");
+            }
+            // If the SP is protected by Weaver, then remove the Weaver protection in order to make
+            // config_disableWeaverOnUnsecuredUsers=true take effect.
+            if (result.usedWeaver) {
+                Slog.i(TAG, "Removing Weaver protection from the synthetic password");
+                // Create a new protector, which will not use Weaver.
+                long newProtectorId = mSpManager.createLskfBasedProtector(
+                        getGateKeeperService(), LockscreenCredential.createNone(), sp, userId);
+
+                // Out of paranoia, make sure the new protector really works.
+                result = mSpManager.unlockLskfBasedProtector(getGateKeeperService(),
+                            newProtectorId, LockscreenCredential.createNone(), userId, null);
+                sp = result.syntheticPassword;
+                if (sp == null) {
+                    throw new IllegalStateException("New SP protector does not work");
+                }
+
+                // Replace the protector.  Wait until PHASE_BOOT_COMPLETED to destroy the old
+                // protector, since the Weaver slot erasure and freeing cannot be rolled back.
+                setCurrentLskfBasedProtectorId(newProtectorId, userId);
+                mProtectorsToDestroyOnBootCompleted.add(new Pair(protectorId, userId));
+            } else {
+                Slog.i(TAG, "Synthetic password is already not protected by Weaver");
+            }
+        } else if (sp == null) {
             Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
             return;
         }
-        // While setCeStorageProtection() is idempotent, it does log some error messages when called
-        // again.  Skip it if we know it was already handled by an earlier upgrade to Android 14.
-        if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
+
+        // Call setCeStorageProtection(), to re-encrypt the CE key with the SP if it's currently
+        // encrypted by an empty secret.  Skip this if it was definitely already done as part of the
+        // upgrade to Android 14, since while setCeStorageProtection() is idempotent it does log
+        // some error messages when called again.  Do not skip this if
+        // config_disableWeaverOnUnsecuredUsers=true, since in that case we'd like to recover from
+        // the case where an earlier upgrade to Android 14 incorrectly skipped this step.
+        if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null
+                || isWeaverDisabledOnUnsecuredUsers()) {
             Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId);
             setCeStorageProtection(userId, sp);
         }
@@ -1165,6 +1240,17 @@
         initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true);
     }
 
+    private void destroyMigratedProtectors() {
+        if (!mProtectorsToDestroyOnBootCompleted.isEmpty()) {
+            synchronized (mSpManager) {
+                for (Pair<Long, Integer> pair : mProtectorsToDestroyOnBootCompleted) {
+                    mSpManager.destroyLskfBasedProtector(pair.first, pair.second);
+                }
+            }
+        }
+        mProtectorsToDestroyOnBootCompleted = null; // The list is no longer needed.
+    }
+
     /**
      * Returns the lowest password quality that still presents the same UI for entering it.
      *
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 3a429b0..47788f2 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -195,6 +195,8 @@
         // ERROR: password / token fails verification
         // RETRY: password / token verification is throttled at the moment.
         @Nullable public VerifyCredentialResponse gkResponse;
+        // For unlockLskfBasedProtector() this is set to true if the protector uses Weaver.
+        public boolean usedWeaver;
     }
 
     /**
@@ -532,6 +534,11 @@
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
     }
 
+    private boolean isWeaverDisabledOnUnsecuredUsers() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers);
+    }
+
     @VisibleForTesting
     protected android.hardware.weaver.V1_0.IWeaver getWeaverHidlService() throws RemoteException {
         try {
@@ -1011,7 +1018,13 @@
 
         Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId);
 
-        final IWeaver weaver = getWeaverService();
+        final IWeaver weaver;
+        if (credential.isNone() && isWeaverDisabledOnUnsecuredUsers()) {
+            weaver = null;
+            Slog.w(TAG, "Not using Weaver for unsecured user (disabled by config)");
+        } else {
+            weaver = getWeaverService();
+        }
         if (weaver != null) {
             // Weaver is available, so make the protector use it to verify the LSKF.  Do this even
             // if the LSKF is empty, as that gives us support for securely deleting the protector.
@@ -1404,6 +1417,7 @@
         int weaverSlot = loadWeaverSlot(protectorId, userId);
         if (weaverSlot != INVALID_WEAVER_SLOT) {
             // Protector uses Weaver to verify the LSKF
+            result.usedWeaver = true;
             final IWeaver weaver = getWeaverService();
             if (weaver == null) {
                 Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable");
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
index 50f3a88..5bcddc4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
@@ -1,6 +1,10 @@
 package com.android.server.locksettings;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -56,4 +60,44 @@
         mService.initializeSyntheticPassword(userId); // This should allocate a Weaver slot.
         assertEquals(Sets.newHashSet(0), mPasswordSlotManager.getUsedSlots());
     }
+
+    private int getNumUsedWeaverSlots() {
+        return mPasswordSlotManager.getUsedSlots().size();
+    }
+
+    @Test
+    public void testDisableWeaverOnUnsecuredUsers_false() {
+        final int userId = PRIMARY_USER_ID;
+        when(mResources.getBoolean(eq(
+                        com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers)))
+                .thenReturn(false);
+        assertEquals(0, getNumUsedWeaverSlots());
+        mService.initializeSyntheticPassword(userId);
+        assertEquals(1, getNumUsedWeaverSlots());
+        assertTrue(mService.setLockCredential(newPassword("password"), nonePassword(), userId));
+        assertEquals(1, getNumUsedWeaverSlots());
+        assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), userId));
+        assertEquals(1, getNumUsedWeaverSlots());
+    }
+
+    @Test
+    public void testDisableWeaverOnUnsecuredUsers_true() {
+        final int userId = PRIMARY_USER_ID;
+        when(mResources.getBoolean(eq(
+                        com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers)))
+                .thenReturn(true);
+        assertEquals(0, getNumUsedWeaverSlots());
+        mService.initializeSyntheticPassword(userId);
+        assertEquals(0, getNumUsedWeaverSlots());
+        assertTrue(mService.setLockCredential(newPassword("password"), nonePassword(), userId));
+        assertEquals(1, getNumUsedWeaverSlots());
+        assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), userId));
+        assertEquals(0, getNumUsedWeaverSlots());
+    }
+
+    @Test
+    public void testDisableWeaverOnUnsecuredUsers_defaultsToFalse() {
+        assertFalse(mResources.getBoolean(
+                    com.android.internal.R.bool.config_disableWeaverOnUnsecuredUsers));
+    }
 }
diff --git a/tests/Internal/src/com/android/internal/os/OWNERS b/tests/Internal/src/com/android/internal/os/OWNERS
new file mode 100644
index 0000000..64ffa46
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/os/OWNERS
@@ -0,0 +1,2 @@
+# ApplicationSharedMemory
+per-file *ApplicationSharedMemory* = file:/PERFORMANCE_OWNERS