Merge "Refactor preference controllers to receive and mutate ZenMode/ZenPolicy" into main
diff --git a/res/layout-land/fingerprint_v2_udfps_enroll_enrolling.xml b/res/layout-land/fingerprint_v2_udfps_enroll_enrolling.xml
index 86768d6..669c282 100644
--- a/res/layout-land/fingerprint_v2_udfps_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_v2_udfps_enroll_enrolling.xml
@@ -14,87 +14,65 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<LinearLayout
+<!-- This is used to grab style attributes and apply them
+to this layout -->
+<com.google.android.setupdesign.GlifLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/udfps_layout"
+    android:id="@+id/glif_layout"
     style="?attr/fingerprint_layout_theme"
     android:layout_width="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
     android:layout_height="match_parent"
-    android:orientation="horizontal">
-
-    <!-- This is used to grab style attributes and apply them
-    to this layout -->
-    <com.google.android.setupdesign.GlifLayout
-        android:id="@+id/dummy_glif_layout"
-        style="?attr/fingerprint_layout_theme"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:visibility="gone"
-        />
+    >
 
     <LinearLayout
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
 
-        <ImageView
-            android:id="@+id/sud_layout_icon"
-            style="@style/SudGlifIcon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:scaleType="fitStart"
-            android:src="@drawable/ic_lock" />
-
-        <TextView
-            android:id="@+id/title"
-            style="@style/SudGlifHeaderTitle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:lines="2"
-            />
-
-        <TextView
-            android:id="@+id/description"
-            style="@style/SudDescription.Glif"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:lines="3"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            />
-
-
-        <com.airbnb.lottie.LottieAnimationView
-            android:id="@+id/illustration_lottie"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            android:scaleType="centerInside"
-            android:visibility="gone"
-            app:lottie_autoPlay="true"
-            app:lottie_loop="true"
-            app:lottie_speed=".85"
-            />
-    </LinearLayout>
-
-    <FrameLayout
-        android:id="@+id/layout_container"
+        style="@style/SudContentFrame"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_gravity="center_horizontal|bottom"
+        android:clipChildren="false"
         android:clipToPadding="false"
+        android:orientation="vertical"
         >
 
-        <include layout="@layout/fingerprint_v2_udfps_enroll_view" />
-    </FrameLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:gravity="center|bottom"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:orientation="vertical">
 
+            <FrameLayout
+                android:id="@+id/layout_container"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_horizontal|bottom"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                >
 
-</LinearLayout>
+                <com.airbnb.lottie.LottieAnimationView
+                    android:id="@+id/illustration_lottie"
+                    android:layout_width="0dp"
+                    android:layout_height="0dp"
+                    android:clipChildren="false"
+                    android:clipToPadding="false"
+                    android:scaleType="centerInside"
+                    android:visibility="gone"
+                    app:lottie_autoPlay="true"
+                    app:lottie_loop="true"
+                    app:lottie_speed=".85"
+                    />
+
+                <include layout="@layout/fingerprint_v2_udfps_enroll_view" />
+
+            </FrameLayout>
+        </LinearLayout>
+    </LinearLayout>
+</com.google.android.setupdesign.GlifLayout>
+
 
diff --git a/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml b/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml
index ab8fb2c..497e164 100644
--- a/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml
+++ b/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml
@@ -19,7 +19,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/udfps_layout"
-    style="?attr/fingerprint_layout_theme"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
@@ -27,65 +26,57 @@
     <!-- This is used to grab style attributes and apply them
     to this layout -->
     <com.google.android.setupdesign.GlifLayout
-        android:id="@+id/dummy_glif_layout"
+        android:id="@+id/glif_layout"
         style="?attr/fingerprint_layout_theme"
-        android:layout_width="0dp"
+        android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:visibility="gone"
-        />
+        android:layout_weight="5"
+        >
 
-    <ImageView
-        android:id="@+id/sud_layout_icon"
-        style="@style/SudGlifIcon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:scaleType="fitStart"
-        android:src="@drawable/ic_lock" />
+        <LinearLayout
+            style="@style/SudContentFrame"
+            android:id="@+id/sud_content_frame"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            >
 
-    <TextView
-        android:id="@+id/title"
-        style="@style/SudGlifHeaderTitle"
-        android:layout_width="match_parent"
-        android:layout_height="80dp"
-        android:ellipsize="end"
-        android:lines="2"
-        />
-
-    <TextView
-        android:id="@+id/description"
-        style="@style/SudDescription.Glif"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:lines="3"
-        android:paddingLeft="10dp"
-        android:paddingRight="10dp"
-        />
-
-
-    <com.airbnb.lottie.LottieAnimationView
-        android:id="@+id/illustration_lottie"
-        android:layout_width="match_parent"
-        android:layout_height="200dp"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:paddingLeft="10dp"
-        android:paddingRight="10dp"
-        android:scaleType="centerInside"
-        app:lottie_autoPlay="true"
-        app:lottie_loop="true"
-        app:lottie_speed=".85" />
+            <com.airbnb.lottie.LottieAnimationView
+                android:id="@+id/illustration_lottie"
+                android:layout_width="match_parent"
+                android:layout_height="200dp"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingLeft="10dp"
+                android:paddingRight="10dp"
+                android:scaleType="centerInside"
+                app:lottie_autoPlay="true"
+                app:lottie_loop="true"
+                app:lottie_speed=".85" />
+        </LinearLayout>
+    </com.google.android.setupdesign.GlifLayout>
 
     <FrameLayout
         android:id="@+id/layout_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="0dp"
         android:layout_gravity="center_horizontal|bottom"
+        android:layout_weight="4"
         android:clipToPadding="false"
+        android:clipChildren="false"
         >
 
         <include layout="@layout/fingerprint_v2_udfps_enroll_view" />
-    </FrameLayout>
 
+        <Button
+            android:id="@+id/skip"
+            style="@style/SudGlifButton.Secondary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|left"
+            android:layout_marginStart="20dp"
+            android:layout_marginBottom="20dp"
+            android:text="@string/security_settings_fingerprint_enroll_enrolling_skip" />
+
+    </FrameLayout>
 
 </LinearLayout>
diff --git a/res/layout/fingerprint_v2_udfps_enroll_view.xml b/res/layout/fingerprint_v2_udfps_enroll_view.xml
index 20df6e1..9002eca 100644
--- a/res/layout/fingerprint_v2_udfps_enroll_view.xml
+++ b/res/layout/fingerprint_v2_udfps_enroll_view.xml
@@ -21,6 +21,8 @@
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
     android:orientation="vertical">
 
     <ImageView
diff --git a/res/raw/udfps_left_edge_hint_lottie.json b/res/raw/udfps_left_edge_hint_lottie.json
index 9e26dfe..e3c4ce1 100644
--- a/res/raw/udfps_left_edge_hint_lottie.json
+++ b/res/raw/udfps_left_edge_hint_lottie.json
@@ -1 +1 @@
-{}
\ No newline at end of file
+{"v":"5.8.1","fr":60,"ip":0,"op":211,"w":412,"h":200,"nm":"FPS Left Side","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":85,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":115,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":140,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":170,"s":[100]},{"t":195,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.175,161.377,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[7.894,8.852],[0,0]],"v":[[-7.497,-6.019],[7.497,6.019]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-13.066,-25.141],[-1.414,-2.132]],"o":[[0,0],[1.326,2.55],[0,0]],"v":[[-25.707,-58.269],[-17.526,-20.998],[-13.399,-13.981]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-10.063,-10.595],[0,0]],"o":[[0.312,1.13],[11.84,12.467],[0,0]],"v":[[-8.095,-38.352],[4.748,-14.866],[28.345,-2.398]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.68235296011,0.796078443527,0.980392158031,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Fingerprint Side","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.175,161.377,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[7.894,8.852],[0,0]],"v":[[-7.497,-6.019],[7.497,6.019]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-13.066,-25.141],[-1.414,-2.132]],"o":[[0,0],[1.326,2.55],[0,0]],"v":[[-25.707,-58.269],[-17.526,-20.998],[-13.399,-13.981]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-10.063,-10.595],[0,0]],"o":[[0.312,1.13],[11.84,12.467],[0,0]],"v":[[-8.095,-38.352],[4.748,-14.866],[28.345,-2.398]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[3.585,11.306],[0,0]],"v":[[90.35,-61.769],[93.054,-42.731]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0],[-14.956,-24.065],[-1.112,-2.304]],"o":[[0,0],[1.517,2.441],[0,0]],"v":[[54.72,-104.215],[82.601,-78.164],[86.53,-71.035]],"c":false},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,0],[-3.978,-14.061],[0,0]],"o":[[0.813,0.844],[4.681,16.544],[0,0]],"v":[[63.033,-78.092],[76.68,-55.064],[75.364,-28.408]],"c":false},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596069335938,0.321563720703,0.239196777344,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Fingerprint","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.139,66.987,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.408,-0.232],[1.017,0.68],[-0.959,1.434],[-6.841,3.896],[-7.562,0.41],[-0.093,-1.722],[1.724,-0.094],[6.003,-3.419],[3.674,-5.493]],"o":[[-0.995,0.567],[-1.433,-0.959],[4.21,-6.294],[6.841,-3.896],[1.722,-0.093],[0.094,1.722],[-6.599,0.357],[-6.003,3.418],[-0.279,0.417]],"v":[[-16.693,13.1],[-19.976,12.983],[-20.836,8.652],[-3.944,-6.925],[18.072,-13.506],[21.359,-10.556],[18.409,-7.27],[-0.853,-1.498],[-15.645,12.124]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[7.044,-4.012],[6.96,0.908],[-0.223,1.71],[-1.711,-0.224],[-5.298,3.017],[-2.065,5.824],[-1.624,-0.577],[0.576,-1.626]],"o":[[-6.489,3.695],[-1.71,-0.223],[0.223,-1.71],[5.601,0.73],[5.742,-3.27],[0.577,-1.625],[1.625,0.576],[-2.566,7.236]],"v":[[44.597,78.169],[24.039,82.43],[21.346,78.93],[24.846,76.237],[41.507,72.742],[53.614,58.64],[57.601,56.74],[59.5,60.727]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0.323,-0.184],[1.029,0.844],[0.13,0.229],[-15.469,8.81],[-8.28,-14.539],[1.498,-0.853],[0.853,1.498],[12.426,-7.076],[-6.547,-11.496],[-4.085,-3.35],[1.094,-1.333]],"o":[[-1.091,0.621],[-5.004,-4.103],[-8.28,-14.539],[15.469,-8.81],[0.853,1.498],[-1.498,0.853],[-6.547,-11.496],[-12.426,7.077],[0.024,0.042],[1.333,1.093],[-0.25,0.305]],"v":[[10.147,71.146],[6.621,70.847],[-1.636,61.086],[11.185,19.448],[53.537,29.665],[52.369,33.924],[48.111,32.756],[14.276,24.874],[3.791,57.996],[10.581,66.018],[11.016,70.413]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[1.183,-0.674],[0.287,-0.071],[3.505,8.779],[-6.102,3.475],[-3.887,-4.766],[0,0],[-3.067,1.747],[1.97,3.459],[0,0],[-1.498,0.853],[-0.853,-1.498],[0,0],[6.451,-3.674],[4.175,5.108],[0,0],[2.675,-1.523],[-1.489,-3.73],[-5.283,1.305],[-0.414,-1.674]],"o":[[-0.244,0.139],[-9.188,2.268],[-2.649,-6.633],[5.335,-3.038],[0,0],[2.235,2.735],[3.459,-1.97],[0,0],[-0.853,-1.498],[1.498,-0.853],[0,0],[3.674,6.452],[-5.725,3.26],[0,0],[-1.949,-2.391],[-3.377,1.923],[2.674,6.697],[1.674,-0.413],[0.342,1.387]],"v":[[36.276,64.961],[35.477,65.279],[11.151,49.991],[16.667,33.848],[32.582,36.831],[36.686,41.876],[45.842,43.586],[48.542,33.739],[47.994,32.777],[49.163,28.518],[53.421,29.686],[53.969,30.648],[48.932,49.012],[31.846,45.823],[27.739,40.774],[19.758,39.275],[16.951,47.675],[33.98,59.216],[37.761,61.499]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.501,-0.285],[0.978,0.515],[11.066,-6.302],[0.514,-9.958],[1.721,0.088],[-0.089,1.722],[-13.068,7.442],[-10.828,-5.692],[0.802,-1.526]],"o":[[-0.895,0.51],[-8.827,-4.639],[-11.066,6.302],[-0.089,1.722],[-1.722,-0.089],[0.63,-12.217],[13.068,-7.442],[1.527,0.802],[-0.288,0.548]],"v":[[42.238,8.912],[39.237,8.964],[6.49,11.701],[-12.571,38.468],[-15.851,41.426],[-18.808,38.146],[3.4,6.274],[42.142,3.436],[43.453,7.653]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Thumb","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[225.438,108.028,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[42.783,10.613],[3.8,0.302],[0,0],[0.105,0.008],[0.484,0.019],[6.105,-2.438],[0,0],[0.032,-0.013],[0.85,-0.396],[0,0],[0,0],[0,0],[0,0],[-26.827,-45.427],[0,0],[0,0]],"o":[[-28.424,-53.851],[-3.608,-1.195],[0,0],[-0.106,-0.009],[-0.482,-0.035],[-6.685,-0.314],[0,0],[-0.032,0.013],[-0.853,0.343],[-20.172,9.126],[0,0],[-6.217,10.813],[0,0],[-5.276,37.379],[0,0],[0,0],[0,0]],"v":[[76.157,43.103],[-34.58,-89.69],[-45.717,-91.957],[-45.708,-91.966],[-46.022,-91.983],[-47.471,-92.063],[-66.474,-88.859],[-66.467,-88.866],[-66.56,-88.826],[-69.115,-87.715],[-94.124,-66.879],[-94.112,-66.885],[-101.514,-44.23],[-101.507,-44.234],[-53.003,92.116],[30.37,92.116],[102.173,92.116]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,100,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[412,200],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":38,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.1254902035,0.129411771894,0.141176477075,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/udfps_right_edge_hint_lottie.json b/res/raw/udfps_right_edge_hint_lottie.json
index 9e26dfe..93a75b3 100644
--- a/res/raw/udfps_right_edge_hint_lottie.json
+++ b/res/raw/udfps_right_edge_hint_lottie.json
@@ -1 +1 @@
-{}
\ No newline at end of file
+{"v":"5.8.1","fr":60,"ip":0,"op":211,"w":412,"h":200,"nm":"FPS Right Side","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":85,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":115,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":140,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":170,"s":[100]},{"t":195,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.175,161.377,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[3.585,11.306],[0,0]],"v":[[90.35,-61.769],[93.054,-42.731]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-14.956,-24.065],[-1.112,-2.304]],"o":[[0,0],[1.517,2.441],[0,0]],"v":[[54.72,-104.215],[82.601,-78.164],[86.53,-71.035]],"c":false},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-3.978,-14.061],[0,0]],"o":[[0.813,0.844],[4.681,16.544],[0,0]],"v":[[63.033,-78.092],[76.68,-55.064],[75.364,-28.408]],"c":false},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.68235296011,0.796078443527,0.980392158031,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Fingerprint Side","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.175,161.377,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[7.894,8.852],[0,0]],"v":[[-7.497,-6.019],[7.497,6.019]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-13.066,-25.141],[-1.414,-2.132]],"o":[[0,0],[1.326,2.55],[0,0]],"v":[[-25.707,-58.269],[-17.526,-20.998],[-13.399,-13.981]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-10.063,-10.595],[0,0]],"o":[[0.312,1.13],[11.84,12.467],[0,0]],"v":[[-8.095,-38.352],[4.748,-14.866],[28.345,-2.398]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[3.585,11.306],[0,0]],"v":[[90.35,-61.769],[93.054,-42.731]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0],[-14.956,-24.065],[-1.112,-2.304]],"o":[[0,0],[1.517,2.441],[0,0]],"v":[[54.72,-104.215],[82.601,-78.164],[86.53,-71.035]],"c":false},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,0],[-3.978,-14.061],[0,0]],"o":[[0.813,0.844],[4.681,16.544],[0,0]],"v":[[63.033,-78.092],[76.68,-55.064],[75.364,-28.408]],"c":false},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596069335938,0.321563720703,0.239196777344,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Fingerprint","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.139,66.987,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.408,-0.232],[1.017,0.68],[-0.959,1.434],[-6.841,3.896],[-7.562,0.41],[-0.093,-1.722],[1.724,-0.094],[6.003,-3.419],[3.674,-5.493]],"o":[[-0.995,0.567],[-1.433,-0.959],[4.21,-6.294],[6.841,-3.896],[1.722,-0.093],[0.094,1.722],[-6.599,0.357],[-6.003,3.418],[-0.279,0.417]],"v":[[-16.693,13.1],[-19.976,12.983],[-20.836,8.652],[-3.944,-6.925],[18.072,-13.506],[21.359,-10.556],[18.409,-7.27],[-0.853,-1.498],[-15.645,12.124]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[7.044,-4.012],[6.96,0.908],[-0.223,1.71],[-1.711,-0.224],[-5.298,3.017],[-2.065,5.824],[-1.624,-0.577],[0.576,-1.626]],"o":[[-6.489,3.695],[-1.71,-0.223],[0.223,-1.71],[5.601,0.73],[5.742,-3.27],[0.577,-1.625],[1.625,0.576],[-2.566,7.236]],"v":[[44.597,78.169],[24.039,82.43],[21.346,78.93],[24.846,76.237],[41.507,72.742],[53.614,58.64],[57.601,56.74],[59.5,60.727]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0.323,-0.184],[1.029,0.844],[0.13,0.229],[-15.469,8.81],[-8.28,-14.539],[1.498,-0.853],[0.853,1.498],[12.426,-7.076],[-6.547,-11.496],[-4.085,-3.35],[1.094,-1.333]],"o":[[-1.091,0.621],[-5.004,-4.103],[-8.28,-14.539],[15.469,-8.81],[0.853,1.498],[-1.498,0.853],[-6.547,-11.496],[-12.426,7.077],[0.024,0.042],[1.333,1.093],[-0.25,0.305]],"v":[[10.147,71.146],[6.621,70.847],[-1.636,61.086],[11.185,19.448],[53.537,29.665],[52.369,33.924],[48.111,32.756],[14.276,24.874],[3.791,57.996],[10.581,66.018],[11.016,70.413]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[1.183,-0.674],[0.287,-0.071],[3.505,8.779],[-6.102,3.475],[-3.887,-4.766],[0,0],[-3.067,1.747],[1.97,3.459],[0,0],[-1.498,0.853],[-0.853,-1.498],[0,0],[6.451,-3.674],[4.175,5.108],[0,0],[2.675,-1.523],[-1.489,-3.73],[-5.283,1.305],[-0.414,-1.674]],"o":[[-0.244,0.139],[-9.188,2.268],[-2.649,-6.633],[5.335,-3.038],[0,0],[2.235,2.735],[3.459,-1.97],[0,0],[-0.853,-1.498],[1.498,-0.853],[0,0],[3.674,6.452],[-5.725,3.26],[0,0],[-1.949,-2.391],[-3.377,1.923],[2.674,6.697],[1.674,-0.413],[0.342,1.387]],"v":[[36.276,64.961],[35.477,65.279],[11.151,49.991],[16.667,33.848],[32.582,36.831],[36.686,41.876],[45.842,43.586],[48.542,33.739],[47.994,32.777],[49.163,28.518],[53.421,29.686],[53.969,30.648],[48.932,49.012],[31.846,45.823],[27.739,40.774],[19.758,39.275],[16.951,47.675],[33.98,59.216],[37.761,61.499]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.501,-0.285],[0.978,0.515],[11.066,-6.302],[0.514,-9.958],[1.721,0.088],[-0.089,1.722],[-13.068,7.442],[-10.828,-5.692],[0.802,-1.526]],"o":[[-0.895,0.51],[-8.827,-4.639],[-11.066,6.302],[-0.089,1.722],[-1.722,-0.089],[0.63,-12.217],[13.068,-7.442],[1.527,0.802],[-0.288,0.548]],"v":[[42.238,8.912],[39.237,8.964],[6.49,11.701],[-12.571,38.468],[-15.851,41.426],[-18.808,38.146],[3.4,6.274],[42.142,3.436],[43.453,7.653]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Thumb","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[225.438,108.028,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[42.783,10.613],[3.8,0.302],[0,0],[0.105,0.008],[0.484,0.019],[6.105,-2.438],[0,0],[0.032,-0.013],[0.85,-0.396],[0,0],[0,0],[0,0],[0,0],[-26.827,-45.427],[0,0],[0,0]],"o":[[-28.424,-53.851],[-3.608,-1.195],[0,0],[-0.106,-0.009],[-0.482,-0.035],[-6.685,-0.314],[0,0],[-0.032,0.013],[-0.853,0.343],[-20.172,9.126],[0,0],[-6.217,10.813],[0,0],[-5.276,37.379],[0,0],[0,0],[0,0]],"v":[[76.157,43.103],[-34.58,-89.69],[-45.717,-91.957],[-45.708,-91.966],[-46.022,-91.983],[-47.471,-92.063],[-66.474,-88.859],[-66.467,-88.866],[-66.56,-88.826],[-69.115,-87.715],[-94.124,-66.879],[-94.112,-66.885],[-101.514,-44.23],[-101.507,-44.234],[-53.003,92.116],[30.37,92.116],[102.173,92.116]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,100,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[412,200],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":38,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.1254902035,0.129411771894,0.141176477075,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/udfps_tip_hint_lottie.json b/res/raw/udfps_tip_hint_lottie.json
index 9e26dfe..1e45382 100644
--- a/res/raw/udfps_tip_hint_lottie.json
+++ b/res/raw/udfps_tip_hint_lottie.json
@@ -1 +1 @@
-{}
\ No newline at end of file
+{"v":"5.7.6","fr":60,"ip":0,"op":211,"w":412,"h":200,"nm":"FPS Tip","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":85,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":115,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":140,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":170,"s":[100]},{"t":195,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.598,42.31,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[14.087,-6.682],[0,0]],"v":[[-13.068,2.034],[13.068,-1.085]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-22.142,12.611]],"o":[[0,0],[0,0]],"v":[[-49.515,34.761],[-23.485,7.239]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-17.076,8.616],[-6.271,0.508]],"o":[[0,0],[7.731,-3.901],[0,0]],"v":[[-49.303,7.104],[-26.763,-9.607],[-5.197,-15.604]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.68235296011,0.796078443527,0.980392158031,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Fingerprint Tip","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.598,42.31,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[14.087,-6.682],[0,0]],"v":[[-13.068,2.034],[13.068,-1.085]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-22.142,12.611]],"o":[[0,0],[0,0]],"v":[[-49.515,34.761],[-23.485,7.239]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-17.076,8.616],[-6.271,0.508]],"o":[[0,0],[7.731,-3.901],[0,0]],"v":[[-49.303,7.104],[-26.763,-9.607],[-5.197,-15.604]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596069335938,0.321563720703,0.239196777344,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Fingerprint","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[176.139,66.987,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.408,-0.232],[1.017,0.68],[-0.959,1.434],[-6.841,3.896],[-7.562,0.41],[-0.093,-1.722],[1.724,-0.094],[6.003,-3.419],[3.674,-5.493]],"o":[[-0.995,0.567],[-1.433,-0.959],[4.21,-6.294],[6.841,-3.896],[1.722,-0.093],[0.094,1.722],[-6.599,0.357],[-6.003,3.418],[-0.279,0.417]],"v":[[-16.693,13.1],[-19.976,12.983],[-20.836,8.652],[-3.944,-6.925],[18.072,-13.506],[21.359,-10.556],[18.409,-7.27],[-0.853,-1.498],[-15.645,12.124]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[7.044,-4.012],[6.96,0.908],[-0.223,1.71],[-1.711,-0.224],[-5.298,3.017],[-2.065,5.824],[-1.624,-0.577],[0.576,-1.626]],"o":[[-6.489,3.695],[-1.71,-0.223],[0.223,-1.71],[5.601,0.73],[5.742,-3.27],[0.577,-1.625],[1.625,0.576],[-2.566,7.236]],"v":[[44.597,78.169],[24.039,82.43],[21.346,78.93],[24.846,76.237],[41.507,72.742],[53.614,58.64],[57.601,56.74],[59.5,60.727]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0.323,-0.184],[1.029,0.844],[0.13,0.229],[-15.469,8.81],[-8.28,-14.539],[1.498,-0.853],[0.853,1.498],[12.426,-7.076],[-6.547,-11.496],[-4.085,-3.35],[1.094,-1.333]],"o":[[-1.091,0.621],[-5.004,-4.103],[-8.28,-14.539],[15.469,-8.81],[0.853,1.498],[-1.498,0.853],[-6.547,-11.496],[-12.426,7.077],[0.024,0.042],[1.333,1.093],[-0.25,0.305]],"v":[[10.147,71.146],[6.621,70.847],[-1.636,61.086],[11.185,19.448],[53.537,29.665],[52.369,33.924],[48.111,32.756],[14.276,24.874],[3.791,57.996],[10.581,66.018],[11.016,70.413]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[1.183,-0.674],[0.287,-0.071],[3.505,8.779],[-6.102,3.475],[-3.887,-4.766],[0,0],[-3.067,1.747],[1.97,3.459],[0,0],[-1.498,0.853],[-0.853,-1.498],[0,0],[6.451,-3.674],[4.175,5.108],[0,0],[2.675,-1.523],[-1.489,-3.73],[-5.283,1.305],[-0.414,-1.674]],"o":[[-0.244,0.139],[-9.188,2.268],[-2.649,-6.633],[5.335,-3.038],[0,0],[2.235,2.735],[3.459,-1.97],[0,0],[-0.853,-1.498],[1.498,-0.853],[0,0],[3.674,6.452],[-5.725,3.26],[0,0],[-1.949,-2.391],[-3.377,1.923],[2.674,6.697],[1.674,-0.413],[0.342,1.387]],"v":[[36.276,64.961],[35.477,65.279],[11.151,49.991],[16.667,33.848],[32.582,36.831],[36.686,41.876],[45.842,43.586],[48.542,33.739],[47.994,32.777],[49.163,28.518],[53.421,29.686],[53.969,30.648],[48.932,49.012],[31.846,45.823],[27.739,40.774],[19.758,39.275],[16.951,47.675],[33.98,59.216],[37.761,61.499]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.501,-0.285],[0.978,0.515],[11.066,-6.302],[0.514,-9.958],[1.721,0.088],[-0.089,1.722],[-13.068,7.442],[-10.828,-5.692],[0.802,-1.526]],"o":[[-0.895,0.51],[-8.827,-4.639],[-11.066,6.302],[-0.089,1.722],[-1.722,-0.089],[0.63,-12.217],[13.068,-7.442],[1.527,0.802],[-0.288,0.548]],"v":[[42.238,8.912],[39.237,8.964],[6.49,11.701],[-12.571,38.468],[-15.851,41.426],[-18.808,38.146],[3.4,6.274],[42.142,3.436],[43.453,7.653]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Thumb","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[225.438,108.028,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[42.783,10.613],[3.8,0.302],[0,0],[0.105,0.008],[0.484,0.019],[6.105,-2.438],[0,0],[0.032,-0.013],[0.85,-0.396],[0,0],[0,0],[0,0],[0,0],[-26.827,-45.427],[0,0],[0,0]],"o":[[-28.424,-53.851],[-3.608,-1.195],[0,0],[-0.106,-0.009],[-0.482,-0.035],[-6.685,-0.314],[0,0],[-0.032,0.013],[-0.853,0.343],[-20.172,9.126],[0,0],[-6.217,10.813],[0,0],[-5.276,37.379],[0,0],[0,0],[0,0]],"v":[[76.157,43.103],[-34.58,-89.69],[-45.717,-91.957],[-45.708,-91.966],[-46.022,-91.983],[-47.471,-92.063],[-66.474,-88.859],[-66.467,-88.866],[-66.56,-88.826],[-69.115,-87.715],[-94.124,-66.879],[-94.112,-66.885],[-101.514,-44.23],[-101.507,-44.234],[-53.003,92.116],[30.37,92.116],[102.173,92.116]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".grey900","cl":"grey900","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,100,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[412,200],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":38,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.1254902035,0.129411771894,0.141176477075,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":960,"st":0,"bm":0}],"markers":[]}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e84356b..e62bf14 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -11896,6 +11896,10 @@
     <string name="sim_onboarding_progressbar_turning_sim_on">Turning on <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>&#8230;</string>
     <!-- Title of service provider name(SPN) at mobile network settings page. [CHAR LIMIT=30] -->
     <string name="mobile_network_spn_title">Mobile network</string>
+    <!-- At the mobile network page, title for primary IMEI for multi-sim devices -->
+    <string name="imei_primary">IMEI (primary)</string>
+    <!-- At the mobile network page, title for primary MEID for multi-sim devices -->
+    <string name="meid_primary">MEID (primary)</string>
     <!-- Title of phone number at mobile network settings page. [CHAR LIMIT=30] -->
     <string name="mobile_network_phone_number_title">Phone number</string>
     <!-- Title of SIM label and color editor dialog at mobile network settings page. [CHAR LIMIT=30] -->
diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
index 53de7c5..1d80099 100644
--- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
@@ -559,7 +559,8 @@
         if (android.app.Flags.appRestrictionsApi()) {
             am.noteAppRestrictionEnabled(pkgName, mAppEntry.info.uid,
                     ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED, true,
-                    ActivityManager.RESTRICTION_REASON_USER, "settings", 0L);
+                    ActivityManager.RESTRICTION_REASON_USER,
+                    "settings", ActivityManager.RESTRICTION_SOURCE_USER, 0L);
         }
         am.forceStopPackage(pkgName);
         int userId = UserHandle.getUserId(mAppEntry.info.uid);
diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollHelper.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollHelper.java
index 8d1113e..f292aae 100644
--- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollHelper.java
+++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollHelper.java
@@ -184,6 +184,7 @@
      */
     public void onAcquired(boolean isAcquiredGood) {
         if (mListener != null) {
+            Log.e("JRM", "OnaCquired " + isAcquiredGood + " lastStepIsGood" + animateIfLastStep());
             mListener.onAcquired(isAcquiredGood && animateIfLastStep());
         }
     }
diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/DebuggingRepository.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/DebuggingRepository.kt
index e99f85b..d007e1a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/data/repository/DebuggingRepository.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/DebuggingRepository.kt
@@ -34,7 +34,7 @@
    */
   private val isBuildDebuggable = Build.IS_DEBUGGABLE
   /** This flag indicates if udfps should use debug repos to supply data to its various views. */
-  private val udfpsEnrollmentDebugEnabled = true
+  private val udfpsEnrollmentDebugEnabled = false
 
   override fun isDebuggingEnabled(): Boolean {
     return isBuildDebuggable
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollStageInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollStageInteractor.kt
index e683cb8..32a1763 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollStageInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollStageInteractor.kt
@@ -34,10 +34,10 @@
     flowOf(
       mapOf(
         0.0f to EnrollStageModel.Center,
-        0.25f to EnrollStageModel.Guided,
-        0.5f to EnrollStageModel.Fingertip,
-        0.75f to EnrollStageModel.LeftEdge,
-        0.875f to EnrollStageModel.RightEdge,
+        0.065f to EnrollStageModel.Guided,
+        0.48f to EnrollStageModel.Fingertip,
+        0.584f to EnrollStageModel.LeftEdge,
+        0.792f to EnrollStageModel.RightEdge,
       )
     )
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt
index e4180d3..f967e04 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt
@@ -33,6 +33,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.transform
 import kotlinx.coroutines.flow.update
 
 /** This repository is responsible for collecting all state related to the enroll API. */
@@ -106,6 +107,30 @@
           streamEnded = true
           enrollRequestOutstanding.update { false }
         }
+
+        override fun onUdfpsPointerDown(sensorId: Int) {
+          trySend(FingerEnrollState.PointerDown(sensorId)).onFailure { error ->
+            Log.d(TAG, "onUdfpsPointerDown failed to send, due to $error")
+          }
+        }
+
+        override fun onUdfpsPointerUp(sensorId: Int) {
+          trySend(FingerEnrollState.PointerUp(sensorId)).onFailure { error ->
+            Log.d(TAG, "onUdfpsPointerUp failed to send, due to $error")
+          }
+        }
+
+        override fun onUdfpsOverlayShown() {
+          trySend(FingerEnrollState.OverlayShown).onFailure { error ->
+            Log.d(TAG, "OverlayShown failed to send, due to $error")
+          }
+        }
+
+        override fun onAcquired(isAcquiredGood: Boolean) {
+          trySend(FingerEnrollState.Acquired(isAcquiredGood)).onFailure { error ->
+            Log.d(TAG, "Acquired failed to send, due to $error")
+          }
+        }
       }
 
     val cancellationSignal = CancellationSignal()
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt
index f9276e6..3ecf312 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/OrientationInteractor.kt
@@ -17,17 +17,12 @@
 package com.android.settings.biometrics.fingerprint2.domain.interactor
 
 import android.content.Context
-import android.util.Log
 import android.view.OrientationEventListener
 import com.android.internal.R
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.shareIn
-import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.flow.transform
 
 /** Interactor which provides information about orientation */
@@ -35,7 +30,9 @@
   /** A flow that contains the information about the orientation changing */
   val orientation: Flow<Int>
   /**
-   * A flow that contains the rotation info
+   * This indicates the surface rotation that hte view is currently in. For instance its possible to
+   * rotate a view to 90 degrees but for it to still be portrait mode. In this case, this flow
+   * should emit that we are in rotation 0 (SurfaceView.Rotation_0)
    */
   val rotation: Flow<Int>
   /**
@@ -50,8 +47,7 @@
   fun getRotationFromDefault(rotation: Int): Int
 }
 
-class OrientationInteractorImpl(private val context: Context, activityScope: CoroutineScope) :
-  OrientationInteractor {
+class OrientationInteractorImpl(private val context: Context) : OrientationInteractor {
 
   override val orientation: Flow<Int> = callbackFlow {
     val orientationEventListener =
@@ -62,9 +58,12 @@
       }
     orientationEventListener.enable()
     awaitClose { orientationEventListener.disable() }
-  }.shareIn(activityScope, SharingStarted.Eagerly, replay = 1)
+  }
 
-  override val rotation: Flow<Int> = orientation.transform { emit(context.display!!.rotation) }
+  override val rotation: Flow<Int> =
+    orientation.transform {
+      emit(context.display!!.rotation)
+    }
 
   override val rotationFromDefault: Flow<Int> = rotation.map { getRotationFromDefault(it) }
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UdfpsEnrollInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UdfpsEnrollInteractor.kt
index ec09ffd..107d1f6 100644
--- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UdfpsEnrollInteractor.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/UdfpsEnrollInteractor.kt
@@ -17,6 +17,7 @@
 package com.android.settings.biometrics.fingerprint2.domain.interactor
 
 import android.graphics.PointF
+import android.util.Log
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
@@ -69,6 +70,7 @@
 
   override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) {
     val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size
+    Log.e("JRM", "guided enroll step $index")
     _guidedEnrollment.update { guidedEnrollmentPoints[index] }
   }
 
diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/model/FingerEnrollState.kt b/src/com/android/settings/biometrics/fingerprint2/lib/model/FingerEnrollState.kt
index 24a9a86..e087304 100644
--- a/src/com/android/settings/biometrics/fingerprint2/lib/model/FingerEnrollState.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/lib/model/FingerEnrollState.kt
@@ -47,10 +47,10 @@
   data class Acquired(val acquiredGood: Boolean) : FingerEnrollState()
 
   /** Indicates a pointer down event has occurred */
-  data object PointerDown : FingerEnrollState()
+  data class PointerDown(val fingerId: Int) : FingerEnrollState()
 
   /** Indicates a pointer up event has occurred */
-  data object PointerUp : FingerEnrollState()
+  data class PointerUp(val fingerId: Int) : FingerEnrollState()
 
   /** Indicates the overlay has shown */
   data object OverlayShown : FingerEnrollState()
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
index 6d353a4..d25fcd0 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
@@ -72,6 +72,7 @@
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.fragment.RFPSEnrollFragment
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.fragment.UdfpsEnrollFragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsLastStepViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
@@ -126,6 +127,7 @@
   private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
   private lateinit var fingerprintEnrollConfirmationViewModel:
     FingerprintEnrollConfirmationViewModel
+  private lateinit var udfpsLastStepViewModel: UdfpsLastStepViewModel
   private lateinit var udfpsViewModel: UdfpsViewModel
   private lateinit var enrollStageInteractor: EnrollStageInteractor
   private val coroutineDispatcher = Dispatchers.Default
@@ -320,7 +322,7 @@
     foldStateInteractor = FoldStateInteractorImpl(context)
     foldStateInteractor.onConfigurationChange(resources.configuration)
 
-    orientationInteractor = OrientationInteractorImpl(context, lifecycleScope)
+    orientationInteractor = OrientationInteractorImpl(context)
     vibrationInteractor =
       VibrationInteractorImpl(context.getSystemService(Vibrator::class.java)!!, context)
 
@@ -373,11 +375,15 @@
         fingerprintEnrollEnrollingViewModel,
         navigationViewModel,
         orientationInteractor,
+        fingerprintManagerInteractor,
       ),
     )[RFPSViewModel::class.java]
 
     enrollStageInteractor = EnrollStageInteractorImpl()
 
+    udfpsLastStepViewModel =
+      UdfpsLastStepViewModel(fingerprintEnrollEnrollingViewModel, vibrationInteractor)
+
     udfpsViewModel =
       ViewModelProvider(
         this,
@@ -393,6 +399,9 @@
           backgroundViewModel,
           fingerprintSensorRepo,
           udfpsEnrollInteractor,
+          fingerprintManagerInteractor,
+          udfpsLastStepViewModel,
+          accessibilityInteractor,
         ),
       )[UdfpsViewModel::class.java]
 
@@ -456,7 +465,7 @@
                 step.exitTransition.toAnimation(),
               )
               .setReorderingAllowed(true)
-              .add(R.id.fragment_container_view, theClass::class.java, null)
+              .replace(R.id.fragment_container_view, theClass::class.java, null)
               .commit()
             navigationViewModel.update(
               FingerprintAction.TRANSITION_FINISHED,
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt
index 0645081..8abcf1a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt
@@ -20,15 +20,18 @@
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
 import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
+import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
 import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
@@ -41,6 +44,7 @@
   private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel,
   private val navigationViewModel: FingerprintNavigationViewModel,
   orientationInteractor: OrientationInteractor,
+  private val fingerprintManager: FingerprintManagerInteractor,
 ) : ViewModel() {
 
   private val _textViewIsVisible = MutableStateFlow(false)
@@ -52,7 +56,16 @@
   /** Indicates if the icon should be animating or not */
   val shouldAnimateIcon = _shouldAnimateIcon
 
-  private var enrollFlow: Flow<FingerEnrollState?> = fingerprintEnrollViewModel.enrollFlow
+  private var enrollFlow: Flow<FingerEnrollState?> =
+    fingerprintManager.sensorPropertiesInternal.filterNotNull().combine(
+      fingerprintEnrollViewModel.enrollFlow
+    ) { props, enroll ->
+      if (props.sensorType == FingerprintSensorType.REAR) {
+        enroll
+      } else {
+        null
+      }
+    }
 
   /**
    * Enroll progress message with a replay of size 1 allowing for new subscribers to get the most
@@ -149,6 +162,7 @@
     private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
     private val navigationViewModel: FingerprintNavigationViewModel,
     private val orientationInteractor: OrientationInteractor,
+    private val fingerprintManager: FingerprintManagerInteractor,
   ) : ViewModelProvider.Factory {
 
     @Suppress("UNCHECKED_CAST")
@@ -157,6 +171,7 @@
         fingerprintEnrollEnrollingViewModel,
         navigationViewModel,
         orientationInteractor,
+        fingerprintManager,
       )
         as T
     }
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt
index a2e5232..4588a07 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt
@@ -21,8 +21,10 @@
 import android.view.MotionEvent
 import android.view.MotionEvent.ACTION_HOVER_MOVE
 import android.view.View
+import android.view.ViewGroup
 import android.view.WindowManager
-import android.widget.TextView
+import android.widget.Button
+import android.widget.FrameLayout
 import androidx.annotation.VisibleForTesting
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.Lifecycle
@@ -40,7 +42,6 @@
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.EducationAnimationModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.widget.UdfpsEnrollViewV2
-import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
 import com.google.android.setupdesign.GlifLayout
 import kotlinx.coroutines.launch
 
@@ -71,10 +72,8 @@
     val fragment = this
     lottie = view.findViewById(R.id.illustration_lottie)!!
     udfpsEnrollView = view.findViewById(R.id.udfps_animation_view)!!
-    val titleTextView = view.findViewById<TextView>(R.id.title)!!
-    val descriptionTextView = view.findViewById<TextView>(R.id.description)!!
+    val glifLayout: GlifLayout = view.findViewById(R.id.glif_layout)!!
 
-    val glifLayout = view.findViewById<GlifLayout>(R.id.dummy_glif_layout)!!
     val backgroundColor = glifLayout.backgroundBaseColor
     val window = requireActivity().window
     window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
@@ -83,6 +82,10 @@
     window.statusBarColor = color
     view.setBackgroundColor(color)
 
+    view.findViewById<Button>(R.id.skip)?.apply {
+      setOnClickListener { viewModel.negativeButtonClicked() }
+    }
+
     udfpsEnrollView.setFinishAnimationCompleted { viewModel.finishedSuccessfully() }
 
     viewLifecycleOwner.lifecycleScope.launch {
@@ -92,32 +95,41 @@
             udfpsEnrollView.setSensorRect(sensor.sensorBounds, sensor.sensorType)
           }
         }
-        viewLifecycleOwner.lifecycleScope.launch {
-          viewModel.headerText.collect { titleTextView.setText(it.toResource()) }
-        }
 
-        viewLifecycleOwner.lifecycleScope.launch {
-          viewModel.descriptionText.collect {
-            if (it != null) {
-              it.toResource()?.let { text -> descriptionTextView.setText(text) }
-            } else {
-              descriptionTextView.text = ""
+        launch { viewModel.overlayShown.collect { udfpsEnrollView.overlayShown() } }
+        launch { viewModel.headerText.collect { glifLayout.setHeaderText(it.toResource()) } }
+        launch {
+          viewModel.userInteractedWithSensor.collect {
+            if (!it) {
+              glifLayout.setHeaderText(R.string.security_settings_fingerprint_enroll_udfps_title)
+              glifLayout.setDescriptionText(R.string.security_settings_udfps_enroll_start_message)
             }
           }
         }
-        viewLifecycleOwner.lifecycleScope.launch {
+
+        launch {
+          viewModel.descriptionText.collect {
+            if (it != null) {
+              it.toResource()?.let { text -> glifLayout.setDescriptionText(text) }
+            } else {
+              glifLayout.descriptionText = ""
+            }
+          }
+        }
+        launch {
           viewModel.shouldShowLottie.collect {
             lottie.visibility = if (it) View.VISIBLE else View.GONE
           }
         }
 
-        viewLifecycleOwner.lifecycleScope.launch {
+        launch {
           viewModel.lottie.collect { lottieModel ->
             if (lottie.visibility == View.GONE) {
               return@collect
             }
             val resource = lottieModel.toResource()
             if (resource != null) {
+              glifLayout.descriptionTextView.visibility = View.GONE
               LottieCompositionFactory.fromRawRes(requireContext(), resource).addListener { comp ->
                 comp?.let { composition ->
                   lottie.setComposition(composition)
@@ -126,27 +138,24 @@
                 }
               }
             } else {
+              glifLayout.descriptionTextView.visibility = View.VISIBLE
               lottie.visibility = View.INVISIBLE
             }
           }
         }
-
-        viewLifecycleOwner.lifecycleScope.launch {
-          repeatOnLifecycle(Lifecycle.State.DESTROYED) { viewModel.stopEnrollment() }
-        }
-
-        viewLifecycleOwner.lifecycleScope.launch {
+        launch {
           viewModel.accessibilityEnabled.collect { enabled ->
             udfpsEnrollView.setAccessibilityEnabled(enabled)
           }
         }
 
-        viewLifecycleOwner.lifecycleScope.launch {
+        launch {
           viewModel.enrollState.collect {
             Log.d(TAG, "EnrollEvent $it")
             if (it is FingerEnrollState.EnrollError) {
               try {
                 FingerprintErrorDialog.showInstance(it, fragment)
+                viewModel.errorDialogShown(it)
               } catch (exception: Exception) {
                 Log.e(TAG, "Exception occurred $exception")
               }
@@ -156,19 +165,40 @@
           }
         }
 
-        viewLifecycleOwner.lifecycleScope.launch {
-          viewModel.progressSaved.collect { udfpsEnrollView.onEnrollProgressSaved(it) }
+        launch { viewModel.progressSaved.collect { udfpsEnrollView.onEnrollProgressSaved(it) } }
+
+        launch { viewModel.guidedEnrollment.collect { udfpsEnrollView.updateGuidedEnrollment(it) } }
+        launch {
+          viewModel.guidedEnrollmentSaved.collect { udfpsEnrollView.onGuidedPointSaved(it) }
         }
 
-        viewLifecycleOwner.lifecycleScope.launch {
-          viewModel.guidedEnrollment.collect {
-            glifLayout.post { udfpsEnrollView.updateGuidedEnrollment(it) }
+        launch { viewModel.shouldDrawIcon.collect { udfpsEnrollView.shouldDrawIcon(it) } }
+
+        // Hack to get the final step of enroll progress to animate.
+        launch {
+          viewModel.udfpsLastStepViewModel.shouldAnimateCompletion.collect {
+            Log.d(TAG, "Sending fake last enroll event $it")
+            udfpsEnrollView.onUdfpsEvent(it)
           }
         }
-        viewLifecycleOwner.lifecycleScope.launch {
-          viewModel.guidedEnrollmentSaved.collect {
-            glifLayout.post { udfpsEnrollView.onGuidedPointSaved(it) }
-          }
+      }
+    }
+
+    viewLifecycleOwner.lifecycleScope.launch {
+      repeatOnLifecycle(Lifecycle.State.DESTROYED) { viewModel.stopEnrollment() }
+    }
+
+    viewLifecycleOwner.lifecycleScope.launch {
+      viewModel.isLandscape.collect {
+        if (it) {
+          changeViewToLandscape()
+        }
+      }
+    }
+    viewLifecycleOwner.lifecycleScope.launch {
+      viewModel.isReverseLandscape.collect {
+        if (it) {
+          changeViewToReverseLandscape()
         }
       }
     }
@@ -183,12 +213,70 @@
     viewModel.readyForEnrollment()
   }
 
+  private fun changeViewToReverseLandscape() {
+    Log.d(TAG, "changeViewToReverseLandscape")
+    val glifContainer = requireView().findViewById<GlifLayout>(R.id.glif_layout)!!
+    val headerView =
+      glifContainer.findViewById<View>(
+        com.google.android.setupdesign.R.id.sud_landscape_header_area
+      )
+    // The landscape_header_area nad landscape_content_area should have the same parent
+    val parent = headerView!!.parent as ViewGroup
+    val sudContentFrame =
+      glifContainer.findViewById<View>(
+        com.google.android.setupdesign.R.id.sud_landscape_content_area
+      )!!
+    val udfpsContainer = requireView().findViewById<FrameLayout>(R.id.layout_container)!!
+
+    parent.removeView(headerView)
+    parent.removeView(sudContentFrame)
+    parent.addView(sudContentFrame)
+    parent.addView(headerView)
+
+    unclipSubviewsFromParent(udfpsContainer)
+    udfpsEnrollView.requestLayout()
+  }
+
+  private fun changeViewToLandscape() {
+    Log.d(TAG, "changeViewToLandscape")
+
+    val glifContainer = requireView().findViewById<GlifLayout>(R.id.glif_layout)!!
+    val headerView =
+      glifContainer.findViewById<View>(
+        com.google.android.setupdesign.R.id.sud_landscape_header_area
+      )
+    // The landscape_header_area nad landscape_content_area should have the same parent
+    val parent = headerView!!.parent as ViewGroup
+    val sudContentFrame =
+      glifContainer.findViewById<View>(
+        com.google.android.setupdesign.R.id.sud_landscape_content_area
+      )!!
+
+    parent.removeView(headerView)
+    parent.removeView(sudContentFrame)
+    parent.addView(headerView)
+    parent.addView(sudContentFrame)
+
+    val udfpsContainer = requireView().findViewById<FrameLayout>(R.id.layout_container)!!
+    unclipSubviewsFromParent(udfpsContainer)
+    udfpsEnrollView.requestLayout()
+  }
+
+  private fun unclipSubviewsFromParent(view: View) {
+    var currParent = view.parent
+    while (currParent is ViewGroup) {
+      currParent.clipChildren = false
+      currParent.clipToPadding = false
+      currParent = currParent.parent
+    }
+  }
+
   private fun HeaderText.toResource(): Int {
     return when (this.enrollStageModel) {
       EnrollStageModel.Center,
-      EnrollStageModel.Guided,
-      EnrollStageModel.Fingertip,
-      EnrollStageModel.Unknown -> R.string.security_settings_udfps_enroll_fingertip_title
+      EnrollStageModel.Guided -> R.string.security_settings_fingerprint_enroll_repeat_title
+      EnrollStageModel.Fingertip -> R.string.security_settings_udfps_enroll_fingertip_title
+      EnrollStageModel.Unknown -> R.string.security_settings_fingerprint_enroll_udfps_title
       EnrollStageModel.LeftEdge -> R.string.security_settings_udfps_enroll_left_edge_title
       EnrollStageModel.RightEdge -> R.string.security_settings_udfps_enroll_right_edge_title
     }
@@ -218,6 +306,5 @@
 
   companion object {
     private const val TAG = "UDFPSEnrollFragment"
-    private val navStep = FingerprintNavigationStep.Enrollment::class
   }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/model/UdfpsSensorLocation.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/model/UdfpsSensorLocation.kt
new file mode 100644
index 0000000..6eb29f9
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/model/UdfpsSensorLocation.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model
+
+import android.graphics.PointF
+import com.android.systemui.biometrics.shared.model.FingerprintSensor
+
+data class UdfpsSensorLocation(val sensorLocation: FingerprintSensor, val offset: PointF?)
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsLastStepViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsLastStepViewModel.kt
new file mode 100644
index 0000000..6a45ec4
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsLastStepViewModel.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintVibrationEffects
+import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
+import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.take
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.flow.transform
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+
+/**
+ * This class is responsible for determining if we should animate the last step of an enrollment. It
+ * seems to be due to poor hardware implementation that the last step of a UDFPS enrollment takes
+ * much longer then normal (likely due to to saving the whole enrollment/or some kind of
+ * verification)
+ *
+ * Because of this, we will use the information of if a fingerprint was acquired(good) + enrollment
+ * has reached the last step
+ */
+class UdfpsLastStepViewModel(
+  private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
+  private val vibrationInteractor: VibrationInteractor,
+) : ViewModel() {
+
+  private val lastStep: MutableStateFlow<FingerEnrollState.EnrollProgress?> = MutableStateFlow(null)
+  private val stepSize: MutableStateFlow<Int?> = MutableStateFlow(null)
+
+  init {
+    viewModelScope.launch {
+      val steps =
+        fingerprintEnrollEnrollingViewModel.enrollFlow
+          .filterIsInstance<FingerEnrollState.EnrollProgress>()
+          .distinctUntilChanged()
+          .take(2)
+          .toList()
+      stepSize.update { steps[0].remainingSteps - steps[1].remainingSteps }
+      lastStep.update { FingerEnrollState.EnrollProgress(0, steps[0].totalStepsRequired) }
+    }
+  }
+
+  private val enrollProgress =
+    fingerprintEnrollEnrollingViewModel.enrollFlow.filterIsInstance<
+      FingerEnrollState.EnrollProgress
+    >()
+
+  /** Indicates if we should animate the completion of udfps enrollment. */
+  val shouldAnimateCompletion =
+    enrollProgress
+      .transform { it ->
+        if (it.remainingSteps == stepSize.value) {
+          fingerprintEnrollEnrollingViewModel.enrollFlow
+            .filterIsInstance<FingerEnrollState.Acquired>()
+            .filter { acquired -> acquired.acquiredGood }
+            .collect {
+              vibrationInteractor.vibrate(
+                FingerprintVibrationEffects.UdfpsSuccess,
+                "UdfpsLastStepViewModel",
+              )
+
+              emit(lastStep.value)
+            }
+        }
+      }
+      .filterNotNull()
+
+  class UdfpsLastStepViewModelFactory(
+    private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
+    private val vibrationInteractor: VibrationInteractor,
+  ) : ViewModelProvider.Factory {
+
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+      return UdfpsLastStepViewModel(fingerprintEnrollEnrollingViewModel, vibrationInteractor) as T
+    }
+  }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt
index a22f680..508084e 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt
@@ -22,9 +22,10 @@
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
-import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
 import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
+import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
 import com.android.settings.biometrics.fingerprint2.data.repository.SimulatedTouchEventsRepository
+import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
@@ -32,6 +33,7 @@
 import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
 import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
+import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
 import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.DescriptionText
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText
@@ -41,6 +43,7 @@
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
 import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.combineTransform
@@ -51,6 +54,8 @@
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.transform
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
 /** ViewModel used to drive UDFPS Enrollment through [UdfpsEnrollFragment] */
@@ -66,13 +71,25 @@
   backgroundViewModel: BackgroundViewModel,
   sensorRepository: FingerprintSensorRepository,
   udfpsEnrollInteractor: UdfpsEnrollInteractor,
+  fingerprintManager: FingerprintManagerInteractor,
+  val udfpsLastStepViewModel: UdfpsLastStepViewModel,
+  accessibilityInteractor: AccessibilityInteractor,
 ) : ViewModel() {
 
   private val isSetupWizard = flowOf(false)
   private var shouldResetErollment = false
 
   private var _enrollState: Flow<FingerEnrollState?> =
-    fingerprintEnrollEnrollingViewModel.enrollFlow
+    fingerprintManager.sensorPropertiesInternal.filterNotNull().combine(
+      fingerprintEnrollEnrollingViewModel.enrollFlow
+    ) { props, enroll ->
+      if (props.sensorType.isUdfps()) {
+        enroll
+      } else {
+        null
+      }
+    }
+
   /** The current state of the enrollment. */
   var enrollState: Flow<FingerEnrollState> =
     combine(fingerprintEnrollEnrollingViewModel.enrollFlowShouldBeRunning, _enrollState) {
@@ -86,48 +103,59 @@
       }
       .filterNotNull()
 
+  /** Indicates that overlay has been shown */
+  val overlayShown =
+    enrollState
+      .filterIsInstance<FingerEnrollState.OverlayShown>()
+      .shareIn(viewModelScope, SharingStarted.Eagerly, 1)
+
+  private var _userInteractedWithSensor = MutableStateFlow(false)
+
+  /**
+   * This indicates whether the user has interacted with the sensor or not. This indicates if we are
+   * in the initial state of the UI.
+   */
+  val userInteractedWithSensor: Flow<Boolean> =
+    enrollState.transform {
+      val interactiveMessage =
+        when (it) {
+          is FingerEnrollState.Acquired,
+          is FingerEnrollState.EnrollError,
+          is FingerEnrollState.EnrollHelp,
+          is FingerEnrollState.EnrollProgress,
+          is FingerEnrollState.PointerDown,
+          is FingerEnrollState.PointerUp -> true
+          else -> false
+        }
+      val hasPreviouslyInteracted = _userInteractedWithSensor.value or interactiveMessage
+      _userInteractedWithSensor.update { hasPreviouslyInteracted }
+      emit(hasPreviouslyInteracted)
+    }
+
   /**
    * Forwards the property sensor information. This is typically used to recreate views that must be
    * aligned with the sensor.
    */
   val sensorLocation = sensorRepository.fingerprintSensor
 
-  /** Indicates if accessibility is enabled */
-  val accessibilityEnabled = flowOf(true).shareIn(viewModelScope, SharingStarted.Eagerly, 1)
-
-  init {
-    viewModelScope.launch {
-      enrollState
-        .combine(accessibilityEnabled) { event, isEnabled -> Pair(event, isEnabled) }
-        .collect {
-          if (
-            when (it.first) {
-              is FingerEnrollState.EnrollError -> true
-              is FingerEnrollState.EnrollHelp -> it.second
-              is FingerEnrollState.EnrollProgress -> true
-              else -> false
-            }
-          ) {
-            vibrate(it.first)
-          }
-        }
-    }
-
-    viewModelScope.launch {
-      backgroundViewModel.background.filter { it }.collect { didGoToBackground() }
-    }
-  }
-
-  /**
-   * This indicates at which point the UI should offset the fingerprint sensor icon for guided
-   * enrollment.
-   */
+  /** Indicates a step of guided enrollment, the ui should animate the icon to the new location. */
   val guidedEnrollment: Flow<PointF> =
-    udfpsEnrollInteractor.guidedEnrollmentOffset.distinctUntilChanged()
+    udfpsEnrollInteractor.guidedEnrollmentOffset
+      .distinctUntilChanged()
+      .shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
 
-  /** The saved version of [guidedEnrollment] */
-  val guidedEnrollmentSaved: Flow<PointF> =
-    guidedEnrollment.shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
+  private var _lastOrientation: Int? = null
+
+  /** In case of rotations we should ensure the UI does not re-animate the last state. */
+  private val shouldReplayLastEvent =
+    orientationInteractor.rotation.transform {
+      if (_lastOrientation != null && _lastOrientation!! != it) {
+        emit(true)
+      } else {
+        emit(false)
+      }
+      _lastOrientation = it
+    }
 
   /**
    * This is the saved progress, this is for when views are recreated and need saved state for the
@@ -136,8 +164,32 @@
   var progressSaved: Flow<FingerEnrollState.EnrollProgress> =
     enrollState
       .filterIsInstance<FingerEnrollState.EnrollProgress>()
-      .filterNotNull()
-      .shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
+      .combineTransform(shouldReplayLastEvent) { enroll, shouldReplay ->
+        if (shouldReplay) {
+          emit(enroll)
+        }
+      }
+      .shareIn(viewModelScope, SharingStarted.Eagerly, 1)
+
+  /** Indicates if accessibility is enabled */
+  val accessibilityEnabled =
+    accessibilityInteractor.isAccessibilityEnabled.shareIn(
+      this.viewModelScope,
+      SharingStarted.Eagerly,
+      replay = 1,
+    )
+
+  /** Indicates if we are in reverse landscape orientation. */
+  val isReverseLandscape =
+    orientationInteractor.rotation
+      .transform { emit(it == Surface.ROTATION_270) }
+      .distinctUntilChanged()
+
+  /** Indicates if we are in the landscape orientation */
+  val isLandscape =
+    orientationInteractor.rotation
+      .transform { emit(it == Surface.ROTATION_90) }
+      .distinctUntilChanged()
 
   /** This sends touch exploration events only used for debugging purposes. */
   val touchExplorationDebug: Flow<Point> =
@@ -170,6 +222,18 @@
       .filterNotNull()
       .shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
 
+  /** The saved version of [guidedEnrollment] */
+  val guidedEnrollmentSaved: Flow<PointF> =
+    combineTransform(guidedEnrollment, shouldReplayLastEvent, enrollStage) {
+        point,
+        shouldReplay,
+        stage ->
+        if (shouldReplay && stage is EnrollStageModel.Guided) {
+          emit(point)
+        }
+      }
+      .shareIn(viewModelScope, SharingStarted.Eagerly, 1)
+
   init {
     viewModelScope.launch {
       enrollState
@@ -200,7 +264,7 @@
     }
 
     viewModelScope.launch {
-      backgroundViewModel.background.filter { true }.collect { didGoToBackground() }
+      backgroundViewModel.background.filter { it }.collect { didGoToBackground() }
     }
   }
 
@@ -210,20 +274,12 @@
         displayDensityInteractor.displayDensity,
         displayDensityInteractor.defaultDisplayDensity,
         displayDensityInteractor.fontScale,
-        orientationInteractor.rotation,
-      ) { currDisplayDensity, defaultDisplayDensity, fontScale, rotation ->
-        val canShowLottieForRotation =
-          when (rotation) {
-            Surface.ROTATION_0 -> true
-            else -> false
-          }
-
-        canShowLottieForRotation &&
-          if (fontScale > 1.0f) {
-            false
-          } else {
-            defaultDisplayDensity == currDisplayDensity
-          }
+      ) { currDisplayDensity, defaultDisplayDensity, fontScale ->
+        if (fontScale > 1.0f) {
+          false
+        } else {
+          defaultDisplayDensity == currDisplayDensity
+        }
       }
       .shareIn(viewModelScope, SharingStarted.Eagerly, 1)
 
@@ -234,6 +290,18 @@
       }
       .shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
 
+  /** Indicates if we should or shold not draw the fingerprint icon */
+  val shouldDrawIcon: Flow<Boolean> =
+    enrollState.transform { state ->
+      when (state) {
+        is FingerEnrollState.EnrollProgress,
+        is FingerEnrollState.EnrollError,
+        is FingerEnrollState.PointerUp -> emit(true)
+        is FingerEnrollState.PointerDown -> emit(false)
+        else -> {}
+      }
+    }
+
   private val shouldClearDescriptionText = enrollStage.map { it is EnrollStageModel.Unknown }
 
   /** The description text for UDFPS enrollment */
@@ -267,12 +335,12 @@
 
   /** Indicates the negative button has been clicked */
   fun negativeButtonClicked() {
-    doReset()
     navigationViewModel.update(
       FingerprintAction.NEGATIVE_BUTTON_PRESSED,
       navStep,
       "$TAG#negativeButtonClicked",
     )
+    doReset()
   }
 
   /** Indicates that an enrollment was completed */
@@ -282,7 +350,7 @@
   }
 
   /** Indicates that the application went to the background. */
-  private fun didGoToBackground() {
+  fun didGoToBackground() {
     navigationViewModel.update(
       FingerprintAction.DID_GO_TO_BACKGROUND,
       navStep,
@@ -293,11 +361,7 @@
 
   private fun doReset() {
     _enrollState = fingerprintEnrollEnrollingViewModel.enrollFlow
-    progressSaved =
-      enrollState
-        .filterIsInstance<FingerEnrollState.EnrollProgress>()
-        .filterNotNull()
-        .shareIn(this.viewModelScope, SharingStarted.Eagerly, replay = 1)
+    _userInteractedWithSensor.update { false }
   }
 
   /** The lottie that should be shown for UDFPS Enrollment */
@@ -320,6 +384,15 @@
     vibrationInteractor.vibrate(vibrationEvent, "UdfpsEnrollFragment")
   }
 
+  /** Indicates an error sent by the HAL has been acknowledged by the user */
+  fun errorDialogShown(it: FingerEnrollState.EnrollError) {
+    navigationViewModel.update(
+      FingerprintAction.USER_CLICKED_FINISH,
+      navStep,
+      "${TAG}#userClickedStopEnrollingDialog",
+    )
+  }
+
   class UdfpsEnrollmentFactory(
     private val vibrationInteractor: VibrationInteractor,
     private val displayDensityInteractor: DisplayDensityInteractor,
@@ -332,6 +405,9 @@
     private val backgroundViewModel: BackgroundViewModel,
     private val sensorRepository: FingerprintSensorRepository,
     private val udfpsEnrollInteractor: UdfpsEnrollInteractor,
+    private val fingerprintManager: FingerprintManagerInteractor,
+    private val udfpsLastStepViewModel: UdfpsLastStepViewModel,
+    private val accessibilityInteractor: AccessibilityInteractor,
   ) : ViewModelProvider.Factory {
 
     @Suppress("UNCHECKED_CAST")
@@ -348,6 +424,9 @@
         backgroundViewModel,
         sensorRepository,
         udfpsEnrollInteractor,
+        fingerprintManager,
+        udfpsLastStepViewModel,
+        accessibilityInteractor,
       )
         as T
     }
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollIconV2.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollIconV2.kt
index c209c55..1eec046 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollIconV2.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollIconV2.kt
@@ -36,8 +36,8 @@
 import android.view.animation.AccelerateDecelerateInterpolator
 import androidx.core.animation.addListener
 import androidx.core.graphics.toRect
-import androidx.core.graphics.toRectF
 import com.android.settings.R
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import kotlin.math.sin
 
 /**
@@ -45,7 +45,6 @@
  * various stages of enrollment
  */
 class UdfpsEnrollIconV2 internal constructor(context: Context, attrs: AttributeSet?) : Drawable() {
-  private var targetAnimationDuration: Long = TARGET_ANIM_DURATION_LONG
   private var targetAnimatorSet: AnimatorSet? = null
   private val movingTargetFpIcon: Drawable
   private val fingerprintDrawable: ShapeDrawable
@@ -55,7 +54,7 @@
   @ColorInt private var movingTargetFill = 0
   private var currentScale = 1.0f
   private var alpha = 0
-  private var guidedEnrollmentOffset: PointF? = null
+  private var stopDrawing = false
 
   /**
    * This is the physical location of the sensor. This rect will be updated by [drawSensorRectAt]
@@ -63,15 +62,12 @@
   private val sensorRectBounds: Rect = Rect()
 
   /**
-   * The following values are used to describe where the icon should be drawn. [currX] and [currY]
-   * are changed based on the current guided enrollment step which is given by the
-   * [UdfpsEnrollHelperV2]
+   * The following values are used to describe where the icon should be drawn. [sensorLeftOffset]
+   * and [sensorTopOffset] are changed based on the current guided enrollment step which is given by
+   * the [UdfpsEnrollHelperV2]
    */
-  private var currX = 0f
-  private var currY = 0f
-
-  private var sensorWidth = 0f
-  private var sensorHeight = 0f
+  private var sensorLeftOffset = 0f
+  private var sensorTopOffset = 0f
 
   init {
     fingerprintDrawable = createUdfpsIcon(context)
@@ -131,29 +127,35 @@
    * The [sensorRect] coordinates for the sensor area. The [sensorRect] should be the coordinates
    * with respect to its root frameview
    */
-  fun drawSensorRectAt(sensorRect: Rect) {
-    Log.e(TAG, "UdfpsEnrollIcon#drawSensorRect($sensorRect)")
+  fun drawSensorRectAt(overlayParams: UdfpsOverlayParams) {
+    Log.e(TAG, "UdfpsEnrollIcon#drawSensorRect(${overlayParams.sensorBounds})")
+    val sensorRect = overlayParams.sensorBounds
     sensorRectBounds.set(sensorRect)
     fingerprintDrawable.bounds = sensorRect
     movingTargetFpIcon.bounds = sensorRect
-    currX = sensorRect.left.toFloat()
-    currY = sensorRect.top.toFloat()
-    sensorWidth = (sensorRect.right - sensorRect.left).toFloat()
-    sensorHeight = (sensorRect.bottom - sensorRect.top).toFloat()
+
+    // End existing animation if we get an update of the sensor rect.
+    targetAnimatorSet?.end()
+
     invalidateSelf()
   }
 
   /** Stop drawing the fingerprint icon. */
   fun stopDrawing() {
-    alpha = 0
+    stopDrawing = true
+    invalidateSelf()
   }
 
   /** Resume drawing the fingerprint icon */
   fun startDrawing() {
-    alpha = 255
+    stopDrawing = false
+    invalidateSelf()
   }
 
   override fun draw(canvas: Canvas) {
+    if (stopDrawing) {
+      return
+    }
     movingTargetFpIcon.alpha = alpha
     fingerprintDrawable.setAlpha(alpha)
     sensorOutlinePaint.setAlpha(alpha)
@@ -165,23 +167,28 @@
     fingerprintDrawable.draw(canvas)
   }
 
-  private fun getCurrLocation(): RectF =
-    RectF(currX, currY, currX + sensorWidth, currY + sensorHeight)
+  private fun getCurrLocation(): RectF {
+    val x = sensorRectBounds.left + sensorLeftOffset
+    val y = sensorRectBounds.top + sensorTopOffset
+    return RectF(x, y, x + sensorRectBounds.width(), y + sensorRectBounds.height())
+  }
 
-  private fun animateMovement(currentBounds: Rect, offsetRect: RectF, scaleMovement: Boolean) {
-    if (currentBounds.equals(offsetRect)) {
+  private fun animateMovement(leftOffset: Float, topOffset: Float, scaleMovement: Boolean) {
+    if (leftOffset == sensorLeftOffset && topOffset == sensorTopOffset) {
       return
     }
 
-    val xAnimator = ValueAnimator.ofFloat(currentBounds.left.toFloat(), offsetRect.left)
+    val currLocation = getCurrLocation()
+
+    val xAnimator = ValueAnimator.ofFloat(currLocation.left - sensorRectBounds.left, leftOffset)
     xAnimator.addUpdateListener {
-      currX = it.animatedValue as Float
+      sensorLeftOffset = it.animatedValue as Float
       invalidateSelf()
     }
 
-    val yAnimator = ValueAnimator.ofFloat(currentBounds.top.toFloat(), offsetRect.top)
+    val yAnimator = ValueAnimator.ofFloat(currLocation.top - sensorRectBounds.top, topOffset)
     yAnimator.addUpdateListener {
-      currY = it.animatedValue as Float
+      sensorTopOffset = it.animatedValue as Float
       invalidateSelf()
     }
     val animators = mutableListOf(xAnimator, yAnimator)
@@ -199,6 +206,7 @@
       animators.add(scaleAnimator)
     }
 
+    targetAnimatorSet?.cancel()
     targetAnimatorSet = AnimatorSet()
 
     targetAnimatorSet?.let {
@@ -210,50 +218,13 @@
   }
 
   /**
-   * This sets animation time to 0. This typically happens after an activity recreation, we don't
-   * want to re-animate the progress/success animation with the default timer
-   */
-  private fun setAnimationTimeToZero() {
-    targetAnimationDuration = 0
-  }
-
-  /** This sets animation timers back to normal, this happens after we have */
-  private fun restoreAnimationTime() {
-    targetAnimationDuration = TARGET_ANIM_DURATION_LONG
-  }
-
-  /**
    * Indicates a change to guided enrollment has occurred. Also indicates if we are recreating the
    * view, in which case their is no need to animate the icon to whatever position it was in.
    */
-  fun updateGuidedEnrollment(point: PointF,  isRecreating: Boolean) {
-    guidedEnrollmentOffset = point
-    if (isRecreating) {
-      setAnimationTimeToZero()
-    } else {
-      restoreAnimationTime()
-    }
-
-    val currentBounds = getCurrLocation().toRect()
-    val offset = guidedEnrollmentOffset
-    if (offset?.x != 0f && offset?.y != 0f) {
-      val targetRect = Rect(sensorRectBounds).toRectF()
-      // This is the desired location of the sensor rect, the [EnrollHelper]
-      // offsets the initial sensor rect by a bit to get the user to move their finger a bit more.
-      targetRect.offset(offset!!.x, offset!!.y)
-      val shouldAnimateMovement = !currentBounds.equals(targetRect)
-      if (shouldAnimateMovement) {
-        targetAnimatorSet?.cancel()
-        animateMovement(currentBounds, targetRect, true)
-      } else {
-        // If we are not offsetting the sensor, move it back to its original place
-        animateMovement(currentBounds, sensorRectBounds.toRectF(), false)
-      }
-    } else {
-      // If we are not offsetting the sensor, move it back to its original place
-      animateMovement(currentBounds, sensorRectBounds.toRectF(), false)
-    }
-    invalidateSelf()
+  fun updateGuidedEnrollment(point: PointF, isRecreating: Boolean) {
+    val pointIsZero = point.x == 0f && point.y == 0f
+    val shouldAnimateMovement = pointIsZero || !isRecreating
+    animateMovement(point?.x ?: 0f, point?.y ?: 0f, shouldAnimateMovement)
   }
 
   companion object {
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollProgressBarDrawableV2.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollProgressBarDrawableV2.kt
index bf2f026..c3adc87 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollProgressBarDrawableV2.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollProgressBarDrawableV2.kt
@@ -27,16 +27,15 @@
 import android.graphics.drawable.Drawable
 import android.util.AttributeSet
 import android.util.DisplayMetrics
-import android.util.Log
 import android.view.animation.DecelerateInterpolator
 import android.view.animation.Interpolator
 import android.view.animation.OvershootInterpolator
 import androidx.annotation.ColorInt
-import androidx.core.animation.addListener
 import androidx.core.animation.doOnEnd
 import androidx.core.graphics.toRectF
 import com.android.internal.annotations.VisibleForTesting
 import com.android.settings.R
+import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import kotlin.math.cos
 import kotlin.math.max
 import kotlin.math.sin
@@ -145,7 +144,6 @@
 
   /** Indicates enrollment progress has occurred. */
   fun onEnrollmentProgress(remaining: Int, totalSteps: Int, isRecreating: Boolean = false) {
-
     afterFirstTouch = true
     updateProgress(remaining, totalSteps, isRecreating)
   }
@@ -216,8 +214,8 @@
    * Draws the progress with locations [sensorLocationX] [sensorLocationY], note these must be with
    * respect to the parent framelayout.
    */
-  fun drawProgressAt(sensorRect: Rect) {
-    this.sensorRect.set(sensorRect)
+  fun drawProgressAt(overlayParams: UdfpsOverlayParams) {
+    this.sensorRect.set(overlayParams.sensorBounds)
     invalidateSelf()
   }
 
@@ -251,8 +249,6 @@
 
     this.remainingSteps = remainingSteps
     this.totalSteps = totalSteps
-    this.remainingSteps = remainingSteps
-    this.totalSteps = totalSteps
     val targetProgress = (totalSteps - remainingSteps).toFloat().div(max(1, totalSteps))
 
     if (progressAnimator != null && progressAnimator!!.isRunning) {
@@ -290,12 +286,8 @@
         checkMarkDrawable.bounds = newBounds
         checkMarkDrawable.setVisible(true, false)
       }
-      doOnEnd {
-        onFinishedCompletionAnimation?.let{
-          it()
-        }
+      doOnEnd { onFinishedCompletionAnimation?.let { it() } }
 
-      }
       start()
     }
   }
@@ -356,6 +348,7 @@
   private fun flashHelpFillColor() {
     if (fillColorAnimator != null && fillColorAnimator!!.isRunning) {
       fillColorAnimator!!.end()
+      fillColorAnimator = null
     }
     @ColorInt val targetColor = helpColor
     fillColorAnimator =
@@ -375,7 +368,6 @@
    * want to re-animate the progress/success animation with the default timer
    */
   private fun setAnimationTimeToZero() {
-    fillColorAnimationDuration = 0
     animateArcDuration = 0
     checkmarkAnimationDelayDuration = 0
     checkmarkAnimationDuration = 0
@@ -383,7 +375,6 @@
 
   /** This sets animation timers back to normal, this happens after we have */
   private fun restoreAnimationTime() {
-    fillColorAnimationDuration = FILL_COLOR_ANIMATION_DURATION_MS
     animateArcDuration = PROGRESS_ANIMATION_DURATION_MS
     checkmarkAnimationDelayDuration = CHECKMARK_ANIMATION_DELAY_MS
     checkmarkAnimationDuration = CHECKMARK_ANIMATION_DURATION_MS
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollViewV2.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollViewV2.kt
index 586408f..d9593c1 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollViewV2.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/widget/UdfpsEnrollViewV2.kt
@@ -70,27 +70,11 @@
   fun setSensorRect(rect: Rect, sensorType: FingerprintSensorType) {
     this.sensorRect = rect
     this.fingerprintSensorType = sensorType
-    findViewById<ImageView?>(R.id.udfps_enroll_animation_fp_progress_view)?.also {
-      it.setImageDrawable(fingerprintProgressDrawable)
-    }
-    findViewById<ImageView>(R.id.udfps_enroll_animation_fp_view)?.also {
-      it.setImageDrawable(fingerprintIcon)
-    }
 
-    val rotation = display.rotation
     var displayInfo = DisplayInfo()
     context.display.getDisplayInfo(displayInfo)
+    val rotation = displayInfo.rotation
     val scaleFactor = udfpsUtils.getScaleFactor(displayInfo)
-    val overlayParams =
-      UdfpsOverlayParams(
-        sensorRect,
-        fingerprintProgressDrawable.bounds,
-        displayInfo.naturalWidth,
-        displayInfo.naturalHeight,
-        scaleFactor,
-        rotation,
-        sensorType.toInt(),
-      )
     val parentView = parent as ViewGroup
     val coords = parentView.getLocationOnScreen()
     val parentLeft = coords[0]
@@ -99,22 +83,44 @@
     // If the view has been rotated, we need to translate the sensor coordinates
     // to the new rotated view.
     when (rotation) {
-      Surface.ROTATION_90,
-      Surface.ROTATION_270 -> {
+      Surface.ROTATION_90 -> {
         sensorRectOffset.set(
           sensorRectOffset.top,
           sensorRectOffset.left,
           sensorRectOffset.bottom,
           sensorRectOffset.right,
         )
+        sensorRectOffset.offset(-parentLeft, -parentTop)
       }
-      else -> {}
-    }
-    // Translate the sensor position into UdfpsEnrollView's view space.
-    sensorRectOffset.offset(-parentLeft, -parentTop)
+      // When the view is rotated 270 degrees, 0,0 is the top corner left
+      Surface.ROTATION_270 -> {
+        sensorRectOffset.set(
+          (displayInfo.naturalHeight - sensorRectOffset.bottom) - parentLeft,
+          sensorRectOffset.left - parentTop,
+          (displayInfo.naturalHeight - sensorRectOffset.top) - parentLeft,
+          sensorRectOffset.right - parentTop,
+        )
+      }
+      else -> {
 
-    fingerprintIcon.drawSensorRectAt(sensorRectOffset)
-    fingerprintProgressDrawable.drawProgressAt(sensorRectOffset)
+        sensorRectOffset.offset(-parentLeft, -parentTop)
+      }
+    }
+
+    // Translate the sensor position into UdfpsEnrollView's view space.
+    val overlayParams =
+      UdfpsOverlayParams(
+        sensorRectOffset,
+        fingerprintProgressDrawable.bounds,
+        displayInfo.naturalWidth,
+        displayInfo.naturalHeight,
+        scaleFactor,
+        rotation,
+        sensorType.toInt(),
+      )
+
+    fingerprintIcon.drawSensorRectAt(overlayParams)
+    fingerprintProgressDrawable.drawProgressAt(overlayParams)
 
     touchExplorationAnnouncer = TouchExplorationAnnouncer(context, this, overlayParams, udfpsUtils)
   }
@@ -126,11 +132,8 @@
         onEnrollmentProgress(event.remainingSteps, event.totalStepsRequired)
       is FingerEnrollState.Acquired -> onAcquired(event.acquiredGood)
       is FingerEnrollState.EnrollHelp -> onEnrollmentHelp()
-      is FingerEnrollState.PointerDown -> onPointerDown()
-      is FingerEnrollState.PointerUp -> onPointerUp()
-      is FingerEnrollState.OverlayShown -> overlayShown()
-      is FingerEnrollState.EnrollError ->
-        throw IllegalArgumentException("$TAG should not handle udfps error")
+      // Else ignore
+      else -> {}
     }
   }
 
@@ -145,7 +148,6 @@
     }
   }
 
-  private fun udfpsError(errMsgId: Int, errString: String) {}
   /**
    * Sends a touch exploration event to the [onHoverListener] this should only be used for
    * debugging.
@@ -170,8 +172,15 @@
     onHoverListener = listener
   }
 
-  private fun overlayShown() {
-    Log.e(TAG, "Implement overlayShown")
+  /** Indicates the overlay has been shown */
+  fun overlayShown() {
+    Log.d(TAG, "Showing udfps overlay")
+    findViewById<ImageView?>(R.id.udfps_enroll_animation_fp_progress_view)?.also {
+      it.setImageDrawable(fingerprintProgressDrawable)
+    }
+    findViewById<ImageView>(R.id.udfps_enroll_animation_fp_view)?.also {
+      it.setImageDrawable(fingerprintIcon)
+    }
   }
 
   /** Receive enroll progress event */
@@ -190,16 +199,6 @@
     if (animateIfLastStepGood) fingerprintProgressDrawable.onLastStepAcquired()
   }
 
-  /** Receive onPointerDown event */
-  private fun onPointerDown() {
-    fingerprintIcon.stopDrawing()
-  }
-
-  /** Receive onPointerUp event */
-  private fun onPointerUp() {
-    fingerprintIcon.startDrawing()
-  }
-
   override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
     super.onLayout(changed, left, top, right, bottom)
     // Because the layout has changed, we need to recompute all locations.
@@ -261,6 +260,17 @@
     fingerprintIcon.updateGuidedEnrollment(point, false)
   }
 
+  /** Indicates if the enroll icon should be drawn. */
+  fun shouldDrawIcon(it: Boolean) {
+    post {
+      if (it) {
+        fingerprintIcon.startDrawing()
+      } else {
+        fingerprintIcon.stopDrawing()
+      }
+    }
+  }
+
   companion object {
     private const val TAG = "UdfpsEnrollView"
   }
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModel.kt
index 7ddb142..bbe3cfd 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
 
+import android.util.Log
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import com.android.systemui.biometrics.shared.model.FingerprintSensor
@@ -68,7 +69,8 @@
   val enrollFlow =
     enrollFlowShouldBeRunning.transformLatest {
       if (it) {
-        fingerprintEnrollViewModel.enrollFlow.collect { event -> emit(event) }
+        fingerprintEnrollViewModel.enrollFlow.collect { event ->
+          emit(event) }
       }
     }
 
@@ -82,4 +84,8 @@
         as T
     }
   }
+
+  companion object {
+    private val TAG = "FingerprintEnrollEnrollingViewModel"
+  }
 }
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index b53bf47..9e08664 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -393,7 +393,7 @@
                     packageName, uid, ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED,
                     mode == AppOpsManager.MODE_IGNORED,
                     ActivityManager.RESTRICTION_REASON_USER,
-                    "settings", 0);
+                    "settings", ActivityManager.RESTRICTION_SOURCE_USER, 0L);
         }
         // Control whether app could run jobs in the background
         mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index df23f12..f15808f 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -329,38 +329,6 @@
         return INVALID_PHYSICAL_SLOT_ID;
     }
 
-    // Device |                                        |Slot   |
-    // Working|                                        |Mapping|
-    // State  |Type                                    |Mode   |Friendly name
-    //--------------------------------------------------------------------------
-    // Single |SIM pSIM [RIL 0]                        |1      |pSIM active
-    // Single |SIM MEP Port #0 [RIL0]                  |2      |eSIM Port0 active
-    // Single |SIM MEP Port #1 [RIL0]                  |2.1    |eSIM Port1 active
-    // DSDS   |pSIM [RIL 0] + MEP Port #0 [RIL 1]      |3      |pSIM+Port0
-    // DSDS   |pSIM [RIL 0] + MEP Port #1 [RIL 1]      |3.1    |pSIM+Port1
-    // DSDS   |MEP Port #0 [RIL 0] + MEP Port #1 [RIL1]|3.2    |Dual-Ports-A
-    // DSDS   |MEP Port #1 [RIL 0] + MEP Port #0 [RIL1]|4      |Dual-Ports-B
-    //
-    // The rules are:
-    // 1. pSIM's logical slots always is [RIL 0].
-    // 2. assign the new active port to the same stack that will be de-activated
-    //    For example: mode#3->mode#4
-    // 3. Add an eSIM carrier or enable eSIM carrier. The cases are at the below.
-    //    1) 1   => 2 / 2.1 / 3 / 3.1
-    //    2) 2   => 1 / 3 / 3.2
-    //    3) 2.1 => 3.1 / 4
-    //    4) 3   => 4
-    //    5) 3.1 => 3.2
-    //    Note:
-    //        1) 2 <=> 2.1  blocked by LPA (reason: existing active port in SS so just re-use)
-    //        2) 3 <=> 3.1 blocked by LPA (reason: if pSIM+an active port, re-use the active port)
-    // 4. pSIM insertion or enabling
-    //     1) 2   => 1 / 3
-    //     2) 2.1 => 1 / 3.1
-    //     3) 3.2 => 3 / 3.1
-    //     4) 4   => 3 / 3.1
-
-
     @VisibleForTesting
     static Collection<UiccSlotMapping> prepareUiccSlotMappings(
             Collection<UiccSlotMapping> uiccSlotMappings, boolean isPsim, int physicalSlotId,
diff --git a/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt b/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt
index e134681..a6fb7ba 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt
+++ b/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceController.kt
@@ -17,7 +17,6 @@
 package com.android.settings.network.telephony
 
 import android.content.Context
-import android.os.UserManager
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
 import android.telephony.TelephonyManager
@@ -41,6 +40,7 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
+
 /**
  * Preference controller for "IMEI"
  */
@@ -123,17 +123,21 @@
         ImeiInfoDialogFragment.show(fragment, simSlot, preference.title.toString())
         return true
     }
+
     private fun getImei(): String {
         val phoneType = getPhoneType()
         return if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) mTelephonyManager.meid?: String()
                 else mTelephonyManager.imei?: String()
     }
+
     private fun getTitleForGsmPhone(): String {
-        return mContext.getString(R.string.status_imei)
+        return mContext.getString(
+            if (isPrimaryImei()) R.string.imei_primary else R.string.status_imei)
     }
 
     private fun getTitleForCdmaPhone(): String {
-        return mContext.getString(R.string.status_meid_number)
+        return mContext.getString(
+            if (isPrimaryImei()) R.string.meid_primary else R.string.status_meid_number)
     }
 
     private fun getTitle(): String {
@@ -142,6 +146,28 @@
                 else getTitleForGsmPhone()
     }
 
+    /**
+     * As per GSMA specification TS37, below Primary IMEI requirements are mandatory to support
+     *
+     * TS37_2.2_REQ_5
+     * TS37_2.2_REQ_8 (Attached the document has description about this test cases)
+     */
+    protected fun isPrimaryImei(): Boolean {
+        val imei = getImei()
+        var primaryImei = String()
+
+        try {
+            primaryImei = mTelephonyManager.primaryImei
+        } catch (exception: Exception) {
+            Log.e(TAG, "PrimaryImei not available. $exception")
+        }
+        return primaryImei == imei && isMultiSim()
+    }
+
+    private fun isMultiSim(): Boolean {
+        return mTelephonyManager.activeModemCount > 1
+    }
+
     fun getPhoneType(): Int {
         return mTelephonyManager.currentPhoneType
     }
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index d5ce3af..8dbcb14 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -160,7 +160,8 @@
                 context.activityManager.noteAppRestrictionEnabled(
                     packageName, uid,
                     ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED, true,
-                    ActivityManager.RESTRICTION_REASON_USER, "settings", 0)
+                    ActivityManager.RESTRICTION_REASON_USER, "settings",
+                    ActivityManager.RESTRICTION_SOURCE_USER, 0)
             }
             context.activityManager.forceStopPackageAsUser(packageName, userId)
         }
diff --git a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt
index ebdc504..652afa0 100644
--- a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt
+++ b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt
@@ -118,7 +118,12 @@
 
   var rfpsIconTouchViewModel = RFPSIconTouchViewModel()
   var rfpsViewModel =
-    RFPSViewModel(fingerprintEnrollEnrollingViewModel, navigationViewModel, orientationInteractor)
+    RFPSViewModel(
+      fingerprintEnrollEnrollingViewModel,
+      navigationViewModel,
+      orientationInteractor,
+      interactor,
+    )
 
   val fingerprintEnrollConfirmationViewModel =
     FingerprintEnrollConfirmationViewModel(navigationViewModel, interactor)
@@ -151,7 +156,8 @@
           BackgroundViewModel::class.java -> backgroundViewModel
           RFPSIconTouchViewModel::class.java -> rfpsIconTouchViewModel
           FingerprintEnrollEnrollingViewModel::class.java -> fingerprintEnrollEnrollingViewModel
-          FingerprintEnrollConfirmationViewModel::class.java -> fingerprintEnrollConfirmationViewModel
+          FingerprintEnrollConfirmationViewModel::class.java ->
+            fingerprintEnrollConfirmationViewModel
           else -> null
         }
           as T
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceControllerTest.kt
index 2f67846..1da8fd9 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileNetworkImeiPreferenceControllerTest.kt
@@ -19,18 +19,16 @@
 import android.content.Context
 import android.telephony.SubscriptionInfo
 import android.telephony.TelephonyManager
-import android.telephony.euicc.EuiccManager
 import androidx.fragment.app.Fragment
 import androidx.preference.Preference
 import androidx.preference.PreferenceManager
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.internal.telephony.PhoneConstants
+import com.android.settings.R
 import com.android.settings.core.BasePreferenceController
 import com.android.settings.network.SubscriptionInfoListViewModel
 import com.android.settings.network.SubscriptionUtil
-import com.android.settingslib.CustomDialogPreferenceCompat
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.runBlocking
 import org.junit.After
@@ -62,6 +60,8 @@
         on { currentPhoneType } doReturn TelephonyManager.PHONE_TYPE_GSM
         on { imei } doReturn mockImei
         on { meid } doReturn mockImei
+        on { primaryImei } doReturn mockImei
+        on { activeModemCount } doReturn 2
     }
 
     private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
@@ -90,7 +90,7 @@
     }
 
     @Test
-    fun refreshData_getPhoneNumber_preferenceSummaryIsExpected() = runBlocking {
+    fun refreshData_getImei_preferenceSummaryIsExpected() = runBlocking {
         whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
         whenever(SubscriptionUtil.getActiveSubscriptions(any())).thenReturn(
             listOf(
@@ -111,6 +111,50 @@
     }
 
     @Test
+    fun refreshData_getImeiTitle_showImei() = runBlocking {
+        whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
+        whenever(SubscriptionUtil.getActiveSubscriptions(any())).thenReturn(
+            listOf(
+                SUB_INFO_1,
+                SUB_INFO_2
+            )
+        )
+        var mockSubId = 2
+        controller.init(mockFragment, mockSubId)
+        mockImei = "test imei"
+        mockTelephonyManager.stub {
+            on { imei } doReturn mockImei
+            on { primaryImei } doReturn ""
+        }
+
+        controller.refreshData(SUB_INFO_2)
+
+        assertThat(preference.title).isEqualTo(context.getString(R.string.status_imei))
+    }
+
+    @Test
+    fun refreshData_getPrimaryImeiTitle_showPrimaryImei() = runBlocking {
+        whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
+        whenever(SubscriptionUtil.getActiveSubscriptions(any())).thenReturn(
+            listOf(
+                SUB_INFO_1,
+                SUB_INFO_2
+            )
+        )
+        var mockSubId = 2
+        controller.init(mockFragment, mockSubId)
+        mockImei = "test imei"
+        mockTelephonyManager.stub {
+            on { imei } doReturn mockImei
+            on { primaryImei } doReturn mockImei
+        }
+
+        controller.refreshData(SUB_INFO_2)
+
+        assertThat(preference.title).isEqualTo(context.getString(R.string.imei_primary))
+    }
+
+    @Test
     fun getAvailabilityStatus_notSimHardwareVisible() {
         whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)