Merge "Use isEssentialPackage instead of isSystemPackage"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8abdb09..132fc29 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -847,6 +847,37 @@
         </activity>
 
         <activity
+            android:name="Settings$LongBackgroundTasksActivity"
+            android:exported="true"
+            android:label="@string/long_background_tasks_label">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.MANAGE_APP_LONG_JOBS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.applications.manageapplications.ManageApplications" />
+            <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+                       android:value="@string/menu_key_apps"/>
+            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+                       android:value="true" />
+        </activity>
+
+        <activity
+            android:name="Settings$LongBackgroundTasksAppActivity"
+            android:exported="true"
+            android:label="@string/long_background_tasks_label">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.MANAGE_APP_LONG_JOBS" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="package" />
+            </intent-filter>
+            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+                       android:value="com.android.settings.applications.appinfo.LongBackgroundTasksDetails" />
+            <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+                       android:value="@string/menu_key_apps"/>
+        </activity>
+
+        <activity
             android:name="Settings$DateTimeSettingsActivity"
             android:label="@string/date_and_time"
             android:exported="true"
diff --git a/res/raw/udfps_center_hint_lottie.json b/res/raw/udfps_center_hint_lottie.json
new file mode 100644
index 0000000..c92e28d
--- /dev/null
+++ b/res/raw/udfps_center_hint_lottie.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":211,"w":412,"h":200,"nm":"FPS Pad","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":[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.682352941176,0.796078431373,0.980392156863,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":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/values/strings.xml b/res/values/strings.xml
index 2057666..74b7dab 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6026,7 +6026,8 @@
     <string name="help_uri_about" translatable="false"></string>
     <!-- Help URI, manage apps that can set alarms and reminders [DO NOT TRANSLATE] -->
     <string name="help_uri_alarms_and_reminders" translatable="false"></string>
-
+    <!-- Help URI, manage apps that can run long background tasks [DO NOT TRANSLATE] -->
+    <string name="help_uri_long_background_tasks" translatable="false"></string>
     <!-- Help URL, WiFi [DO NOT TRANSLATE] -->
     <string name="help_url_wifi" translatable="false"></string>
     <!-- Help URL, WiFi Direct [DO NOT TRANSLATE] -->
@@ -9117,6 +9118,22 @@
     <!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] -->
     <string name="special_access_more">See more</string>
 
+    <!-- Label for the settings activity for controlling apps that can run long background tasks [CHAR LIMIT=30] -->
+    <string name="long_background_tasks_label">Long background tasks</string>
+    <!-- Label for the switch to toggle the permission for running long background tasks [CHAR LIMIT=50] -->
+    <string name="long_background_tasks_switch_title">Allow long-running background tasks</string>
+    <!-- Title for the settings screen for controlling apps that can run long background tasks [CHAR LIMIT=30] -->
+    <string name="long_background_tasks_title">Long background tasks</string>
+    <!-- Description that appears below the long_background_tasks switch [CHAR LIMIT=NONE] -->
+    <string name="long_background_tasks_footer_title">
+        Allow this app to run long background tasks. This lets the app run tasks that might
+        take longer than a few minutes to finish, such as downloads and uploads.
+        \n\nIf this permission is denied, the system will limit how long the app can perform
+        such tasks in the background.
+    </string>
+    <!-- Keywords for settings screen for controlling apps that can run long background tasks [CHAR LIMIT=NONE] -->
+    <string name="keywords_long_background_tasks">long jobs, data transfer, background tasks</string>
+
     <!-- Reset rate-limiting in the system service ShortcutManager.  "ShortcutManager" is the name of a system service and not translatable.
     If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means
     the same thing in this context.
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index 2bb05d0..e004f28 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -189,6 +189,12 @@
             android:summary="@string/summary_placeholder"
             settings:controller="com.android.settings.applications.appinfo.AlarmsAndRemindersDetailPreferenceController" />
 
+        <Preference
+            android:key="long_background_tasks"
+            android:title="@string/long_background_tasks_title"
+            android:summary="@string/summary_placeholder"
+            settings:controller="com.android.settings.applications.appinfo.LongBackgroundTasksDetailsPreferenceController" />
+
     </PreferenceCategory>
 
     <!-- App installer info -->
diff --git a/res/xml/long_background_tasks.xml b/res/xml/long_background_tasks.xml
new file mode 100644
index 0000000..405b0cf
--- /dev/null
+++ b/res/xml/long_background_tasks.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:title="@string/long_background_tasks_title">
+
+    <com.android.settings.widget.FilterTouchesRestrictedSwitchPreference
+        android:key="long_background_tasks_switch"
+        android:title="@string/long_background_tasks_switch_title" />
+
+    <com.android.settingslib.widget.FooterPreference
+        android:key="long_background_tasks_description"
+        android:title="@string/long_background_tasks_footer_title"
+        android:selectable="false" />
+
+</PreferenceScreen>
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 3dd6e18..0d2ee51 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -108,6 +108,16 @@
         settings:controller="com.android.settings.applications.specialaccess.DataSaverController" />
 
     <Preference
+        android:key="long_background_tasks"
+        android:title="@string/long_background_tasks_title"
+        android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
+        settings:keywords="@string/keywords_long_background_tasks">
+        <extra
+            android:name="classname"
+            android:value="com.android.settings.Settings$LongBackgroundTasksActivity" />
+    </Preference>
+
+    <Preference
         android:key="manage_external_sources"
         android:title="@string/install_other_apps"
         android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java
index 224ba13..7635041 100644
--- a/src/com/android/settings/ResetNetwork.java
+++ b/src/com/android/settings/ResetNetwork.java
@@ -24,8 +24,6 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.telephony.SubscriptionInfo;
@@ -46,12 +44,10 @@
 
 import com.android.settings.core.InstrumentedFragment;
 import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
+import com.android.settings.network.ResetNetworkRestrictionViewBuilder;
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.password.ConfirmLockPattern;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
 import java.util.ArrayList;
@@ -115,7 +111,7 @@
         // confirmation prompt; otherwise, go back to the initial state.
         if (resultCode == Activity.RESULT_OK) {
             showFinalConfirmation();
-        } else {
+        } else if (mContentView != null) {
             establishInitialState(getActiveSubscriptionInfoList());
         }
     }
@@ -255,6 +251,10 @@
     public void onResume() {
         super.onResume();
 
+        if (mContentView == null) {
+            return;
+        }
+
         // update options if subcription has been changed
         List<SubscriptionInfo> updatedSubscriptions = getActiveSubscriptionInfoList();
         if ((mSubscriptions != null)
@@ -283,18 +283,10 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        final UserManager um = UserManager.get(getActivity());
-        final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
-                getActivity(), UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId());
-        if (!um.isAdminUser() || RestrictedLockUtilsInternal.hasBaseUserRestriction(getActivity(),
-                UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId())) {
-            return inflater.inflate(R.layout.network_reset_disallowed_screen, null);
-        } else if (admin != null) {
-            new ActionDisabledByAdminDialogHelper(getActivity())
-                    .prepareDialogBuilder(UserManager.DISALLOW_NETWORK_RESET, admin)
-                    .setOnDismissListener(__ -> getActivity().finish())
-                    .show();
-            return new View(getContext());
+        View view = (new ResetNetworkRestrictionViewBuilder(getActivity())).build();
+        if (view != null) {
+            Log.w(TAG, "Access deny.");
+            return view;
         }
 
         mContentView = inflater.inflate(R.layout.reset_network, null);
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index 30d159b..8926d5c 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -16,8 +16,6 @@
 
 package com.android.settings;
 
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.app.settings.SettingsEnums;
@@ -35,8 +33,6 @@
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.RecoverySystem;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
@@ -52,9 +48,8 @@
 import androidx.appcompat.app.AlertDialog;
 
 import com.android.settings.core.InstrumentedFragment;
-import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
+import com.android.settings.network.ResetNetworkRestrictionViewBuilder;
 import com.android.settings.network.apn.ApnSettings;
-import com.android.settingslib.RestrictedLockUtilsInternal;
 
 /**
  * Confirm and execute a reset of the network settings to a clean "just out of the box"
@@ -262,17 +257,10 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
-                mActivity, UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId());
-        if (RestrictedLockUtilsInternal.hasBaseUserRestriction(mActivity,
-                UserManager.DISALLOW_NETWORK_RESET, UserHandle.myUserId())) {
-            return inflater.inflate(R.layout.network_reset_disallowed_screen, null);
-        } else if (admin != null) {
-            new ActionDisabledByAdminDialogHelper(mActivity)
-                    .prepareDialogBuilder(UserManager.DISALLOW_NETWORK_RESET, admin)
-                    .setOnDismissListener(__ -> mActivity.finish())
-                    .show();
-            return new View(mActivity);
+        View view = (new ResetNetworkRestrictionViewBuilder(mActivity)).build();
+        if (view != null) {
+            Log.w(TAG, "Access deny.");
+            return view;
         }
         mContentView = inflater.inflate(R.layout.reset_network_confirm, null);
         establishFinalConfirmationState();
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index b95c9b0..e394e45 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -430,6 +430,11 @@
         }
     }
 
+    /** Actviity to manage apps with {@link android.Manifest.permission#RUN_LONG_JOBS} */
+    public static class LongBackgroundTasksActivity extends SettingsActivity { /* empty */ }
+    /** App specific version of {@link LongBackgroundTasksActivity} */
+    public static class LongBackgroundTasksAppActivity extends SettingsActivity { /* empty */ }
+
     /**
      * Activity for BugReportHandlerPicker.
      */
diff --git a/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragment.java b/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragment.java
index c3359e4..04db825 100644
--- a/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityDetailsSettingsFragment.java
@@ -41,6 +41,7 @@
 import com.android.settings.R;
 import com.android.settings.core.InstrumentedFragment;
 import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
 import java.util.List;
@@ -230,6 +231,10 @@
                     new ComponentName(packageName, tileServiceClassName).flattenToString());
         }
 
+        final int metricsCategory = FeatureFactory.getFactory(getActivity().getApplicationContext())
+                .getAccessibilityMetricsFeatureProvider()
+                .getDownloadedFeatureMetricsCategory(componentName);
+        extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
         extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
         extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, info.getAnimatedImageRes());
 
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 1008183..23f8fd3 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -87,6 +87,7 @@
     static final String EXTRA_ANIMATED_IMAGE_RES = "animated_image_res";
     static final String EXTRA_HTML_DESCRIPTION = "html_description";
     static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
+    static final String EXTRA_METRICS_CATEGORY = "metrics_category";
 
     // Timeout before we update the services if packages are added/removed
     // since the AccessibilityManagerService has to do that processing first
diff --git a/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java b/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java
index 1f8374d..80d1ce0 100644
--- a/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java
@@ -42,7 +42,6 @@
 
 import com.android.settings.R;
 import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
-import com.android.settings.overlay.FeatureFactory;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -58,15 +57,7 @@
 
     @Override
     public int getMetricsCategory() {
-        // Retrieve from getArguments() directly because this function will be executed from
-        // onAttach(), but variable mComponentName only available after onProcessArguments()
-        // which comes from onCreateView().
-        final ComponentName componentName = getArguments().getParcelable(
-                AccessibilitySettings.EXTRA_COMPONENT_NAME);
-
-        return FeatureFactory.getFactory(getActivity().getApplicationContext())
-                .getAccessibilityMetricsFeatureProvider()
-                .getDownloadedFeatureMetricsCategory(componentName);
+        return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
     }
 
     @Override
diff --git a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
index 4344acc..00339a1 100644
--- a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
+++ b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
@@ -37,6 +37,7 @@
 
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedPreference;
@@ -118,9 +119,12 @@
             final String htmlDescription = info.loadHtmlDescription(mPm);
             final String settingsClassName = info.getSettingsActivityName();
             final String tileServiceClassName = info.getTileServiceName();
+            final int metricsCategory = FeatureFactory.getFactory(mContext)
+                    .getAccessibilityMetricsFeatureProvider()
+                    .getDownloadedFeatureMetricsCategory(componentName);
 
             putBasicExtras(preference, prefKey, title, intro, description, imageRes,
-                    htmlDescription, componentName);
+                    htmlDescription, componentName, metricsCategory);
             putServiceExtras(preference, resolveInfo, serviceEnabled);
             putSettingsExtras(preference, packageName, settingsClassName);
             putTileServiceExtras(preference, packageName, tileServiceClassName);
@@ -178,9 +182,12 @@
             final String htmlDescription = info.loadHtmlDescription(mPm);
             final String settingsClassName = info.getSettingsActivityName();
             final String tileServiceClassName = info.getTileServiceName();
+            final int metricsCategory = FeatureFactory.getFactory(mContext)
+                    .getAccessibilityMetricsFeatureProvider()
+                    .getDownloadedFeatureMetricsCategory(componentName);
 
             putBasicExtras(preference, prefKey, title, intro, description, imageRes,
-                    htmlDescription, componentName);
+                    htmlDescription, componentName, metricsCategory);
             putSettingsExtras(preference, componentName.getPackageName(), settingsClassName);
             putTileServiceExtras(preference, componentName.getPackageName(),
                     tileServiceClassName);
@@ -265,7 +272,7 @@
     /** Puts the basic extras into {@link RestrictedPreference}'s getExtras(). */
     private void putBasicExtras(RestrictedPreference preference, String prefKey,
             CharSequence title, CharSequence intro, CharSequence summary, int imageRes,
-            String htmlDescription, ComponentName componentName) {
+            String htmlDescription, ComponentName componentName, int metricsCategory) {
         final Bundle extras = preference.getExtras();
         extras.putString(AccessibilitySettings.EXTRA_PREFERENCE_KEY, prefKey);
         extras.putCharSequence(AccessibilitySettings.EXTRA_TITLE, title);
@@ -274,6 +281,7 @@
         extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
         extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, imageRes);
         extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
+        extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
     }
 
     /**
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index f1c0202..5941170 100644
--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -49,7 +49,6 @@
 import com.android.settings.R;
 import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
-import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
 import java.util.List;
@@ -71,15 +70,7 @@
 
     @Override
     public int getMetricsCategory() {
-        // Retrieve from getArguments() directly because this function will be executed from
-        // onAttach(), but variable mComponentName only available after onProcessArguments()
-        // which comes from onCreateView().
-        final ComponentName componentName = getArguments().getParcelable(
-                AccessibilitySettings.EXTRA_COMPONENT_NAME);
-
-        return FeatureFactory.getFactory(getActivity().getApplicationContext())
-                .getAccessibilityMetricsFeatureProvider()
-                .getDownloadedFeatureMetricsCategory(componentName);
+        return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
     }
 
     @Override
diff --git a/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java b/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java
new file mode 100644
index 0000000..d286c5e
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.app.job.JobScheduler;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import libcore.util.EmptyArray;
+
+import java.util.List;
+
+/**
+ * Connects app op info to the ApplicationsState. Extends {@link AppStateAppOpsBridge} to tailor
+ * to the semantics of {@link Manifest.permission#RUN_LONG_JOBS}.
+ * Also provides app filters that can use the info.
+ */
+public class AppStateLongBackgroundTasksBridge extends AppStateBaseBridge {
+    private static final String PERMISSION = Manifest.permission.RUN_LONG_JOBS;
+    private static final String TAG = "LongBackgroundTasksBridge";
+
+    @VisibleForTesting
+    JobScheduler mJobScheduler;
+    @VisibleForTesting
+    String[] mRequesterPackages;
+
+    public AppStateLongBackgroundTasksBridge(Context context, ApplicationsState appState,
+            Callback callback) {
+        super(appState, callback);
+
+        mJobScheduler = context.getSystemService(JobScheduler.class);
+        final IPackageManager iPm = AppGlobals.getPackageManager();
+        try {
+            mRequesterPackages = iPm.getAppOpPermissionPackages(PERMISSION, context.getUserId());
+        } catch (RemoteException re) {
+            Log.e(TAG, "Cannot reach package manager", re);
+            mRequesterPackages = EmptyArray.STRING;
+        }
+    }
+
+    /**
+     * Returns information regarding {@link Manifest.permission#RUN_LONG_JOBS} for the given
+     * package and uid.
+     */
+    public LongBackgroundTasksState createPermissionState(String packageName, int uid) {
+        final int userId = UserHandle.getUserId(uid);
+
+        final boolean permissionRequested = ArrayUtils.contains(mRequesterPackages, packageName);
+        final boolean permissionGranted = mJobScheduler.hasRunLongJobsPermission(packageName,
+                userId);
+        return new LongBackgroundTasksState(permissionRequested, permissionGranted);
+    }
+
+    @Override
+    protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        app.extraInfo = createPermissionState(pkg, uid);
+    }
+
+    @Override
+    protected void loadAllExtraInfo() {
+        final List<AppEntry> allApps = mAppSession.getAllApps();
+        for (int i = 0; i < allApps.size(); i++) {
+            final AppEntry currentEntry = allApps.get(i);
+            updateExtraInfo(currentEntry, currentEntry.info.packageName, currentEntry.info.uid);
+        }
+    }
+
+    public static final AppFilter FILTER_LONG_JOBS_APPS = new AppFilter() {
+
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public boolean filterApp(AppEntry info) {
+            if (info.extraInfo instanceof LongBackgroundTasksState) {
+                final LongBackgroundTasksState state = (LongBackgroundTasksState) info.extraInfo;
+                return state.shouldBeVisible();
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Class to denote the state of an app regarding
+     * {@link Manifest.permission#RUN_LONG_JOBS}.
+     */
+    public static class LongBackgroundTasksState {
+        private boolean mPermissionRequested;
+        private boolean mPermissionGranted;
+
+        LongBackgroundTasksState(boolean permissionRequested, boolean permissionGranted) {
+            mPermissionRequested = permissionRequested;
+            mPermissionGranted = permissionGranted;
+        }
+
+        /** Should the app associated with this state appear on the Settings screen */
+        public boolean shouldBeVisible() {
+            return mPermissionRequested;
+        }
+
+        /** Is the permission granted to the app associated with this state */
+        public boolean isAllowed() {
+            return mPermissionGranted;
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 7049b56..4a00260 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -215,10 +215,15 @@
         alarmsAndReminders.setPackageName(packageName);
         alarmsAndReminders.setParentFragment(this);
 
+        final LongBackgroundTasksDetailsPreferenceController longBackgroundTasks =
+                use(LongBackgroundTasksDetailsPreferenceController.class);
+        longBackgroundTasks.setPackageName(packageName);
+        longBackgroundTasks.setParentFragment(this);
+
         final AdvancedAppInfoPreferenceCategoryController advancedAppInfo =
                 use(AdvancedAppInfoPreferenceCategoryController.class);
         advancedAppInfo.setChildren(Arrays.asList(writeSystemSettings, drawOverlay, pip,
-                externalSource, acrossProfiles, alarmsAndReminders));
+                externalSource, acrossProfiles, alarmsAndReminders, longBackgroundTasks));
         advancedAppInfo.setAppEntry(mAppEntry);
 
         final AppLocalePreferenceController appLocale =
diff --git a/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java
new file mode 100644
index 0000000..1e5d11a
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.applications.appinfo;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+
+import android.app.AppOpsManager;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.applications.AppInfoWithHeader;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
+import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+/**
+ * App specific activity to show details about
+ * {@link android.Manifest.permission#RUN_LONG_JOBS}.
+ */
+public class LongBackgroundTasksDetails extends AppInfoWithHeader
+        implements OnPreferenceChangeListener {
+
+    private static final String KEY_SWITCH = "long_background_tasks_switch";
+    private static final String UNCOMMITTED_STATE_KEY = "uncommitted_state";
+
+    private AppStateLongBackgroundTasksBridge mAppBridge;
+    private AppOpsManager mAppOpsManager;
+    private RestrictedSwitchPreference mSwitchPref;
+    private AppStateLongBackgroundTasksBridge.LongBackgroundTasksState mPermissionState;
+    private volatile Boolean mUncommittedState;
+
+    /**
+     * Returns the string that states whether the app has access to
+     * {@link android.Manifest.permission#RUN_LONG_JOBS}.
+     */
+    public static CharSequence getSummary(Context context, AppEntry entry) {
+        final AppStateLongBackgroundTasksBridge.LongBackgroundTasksState state =
+                new AppStateLongBackgroundTasksBridge(context, /*appState=*/null,
+                        /*callback=*/null).createPermissionState(entry.info.packageName,
+                        entry.info.uid);
+
+        return context.getString(state.isAllowed() ? R.string.app_permission_summary_allowed
+                : R.string.app_permission_summary_not_allowed);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Context context = getActivity();
+        mAppBridge = new AppStateLongBackgroundTasksBridge(context, mState, /*callback=*/null);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+
+        if (savedInstanceState != null) {
+            mUncommittedState = (Boolean) savedInstanceState.get(UNCOMMITTED_STATE_KEY);
+            if (mUncommittedState != null && isAppSpecific()) {
+                setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED);
+            }
+        }
+        addPreferencesFromResource(R.xml.long_background_tasks);
+        mSwitchPref = findPreference(KEY_SWITCH);
+        mSwitchPref.setOnPreferenceChangeListener(this);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mUncommittedState != null) {
+            outState.putObject(UNCOMMITTED_STATE_KEY, mUncommittedState);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mSwitchPref) {
+            mUncommittedState = (Boolean) newValue;
+            if (isAppSpecific()) {
+                setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED);
+            }
+            refreshUi();
+            return true;
+        }
+        return false;
+    }
+
+    private void setCanRunLongJobs(boolean newState) {
+        final int uid = mPackageInfo.applicationInfo.uid;
+        mAppOpsManager.setUidMode(AppOpsManager.OPSTR_RUN_LONG_JOBS, uid,
+                newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
+    }
+
+    private void logPermissionChange(boolean newState, String packageName) {
+        mMetricsFeatureProvider.action(
+                mMetricsFeatureProvider.getAttribution(getActivity()),
+                SettingsEnums.ACTION_LONG_BACKGROUND_TASKS_TOGGLE,
+                getMetricsCategory(),
+                packageName,
+                newState ? 1 : 0);
+    }
+
+    private boolean isAppSpecific() {
+        return Settings.LongBackgroundTasksAppActivity.class.getName().equals(
+                getIntent().getComponent().getClassName());
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (getActivity().isChangingConfigurations()) {
+            return;
+        }
+        if (mPermissionState != null && mUncommittedState != null
+                && mUncommittedState != mPermissionState.isAllowed()) {
+            setCanRunLongJobs(mUncommittedState);
+            logPermissionChange(mUncommittedState, mPackageName);
+            mUncommittedState = null;
+        }
+    }
+
+    @Override
+    protected boolean refreshUi() {
+        if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
+            return false;
+        }
+        mPermissionState = mAppBridge.createPermissionState(mPackageName,
+                mPackageInfo.applicationInfo.uid);
+        mSwitchPref.setEnabled(mPermissionState.shouldBeVisible());
+        mSwitchPref.setChecked(
+                mUncommittedState != null ? mUncommittedState : mPermissionState.isAllowed());
+        return true;
+    }
+
+    @Override
+    protected AlertDialog createDialog(int id, int errorCode) {
+        return null;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.LONG_BACKGROUND_TASKS;
+    }
+}
diff --git a/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java
new file mode 100644
index 0000000..a41280b
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
+
+/**
+ * Preference controller for
+ * {@link LongBackgroundTasksDetails} Settings fragment.
+ */
+public class LongBackgroundTasksDetailsPreferenceController extends
+        AppInfoPreferenceControllerBase {
+
+    private String mPackageName;
+
+    public LongBackgroundTasksDetailsPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return isCandidate() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        preference.setSummary(getPreferenceSummary());
+    }
+
+    @Override
+    protected Class<? extends SettingsPreferenceFragment> getDetailFragmentClass() {
+        return LongBackgroundTasksDetails.class;
+    }
+
+    @VisibleForTesting
+    CharSequence getPreferenceSummary() {
+        return LongBackgroundTasksDetails.getSummary(mContext, mParent.getAppEntry());
+    }
+
+    @VisibleForTesting
+    boolean isCandidate() {
+        final PackageInfo packageInfo = mParent.getPackageInfo();
+        if (packageInfo == null) {
+            return false;
+        }
+        final AppStateLongBackgroundTasksBridge.LongBackgroundTasksState appState =
+                new AppStateLongBackgroundTasksBridge(
+                        mContext, /*appState=*/null, /*callback=*/null)
+                        .createPermissionState(mPackageName, packageInfo.applicationInfo.uid);
+        return appState.shouldBeVisible();
+    }
+
+    void setPackageName(String packageName) {
+        mPackageName = packageName;
+    }
+}
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index 15cf8e7..b48bdbb 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -23,6 +23,7 @@
 import com.android.settings.applications.AppStateAppBatteryUsageBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
 import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
@@ -61,6 +62,7 @@
                 FILTER_APPS_BATTERY_UNRESTRICTED,
                 FILTER_APPS_BATTERY_OPTIMIZED,
                 FILTER_APPS_BATTERY_RESTRICTED,
+                FILTER_LONG_BACKGROUND_TASKS,
             })
     @interface FilterType {}
 
@@ -89,8 +91,9 @@
     public static final int FILTER_APPS_BATTERY_UNRESTRICTED = 21;
     public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
     public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
-    // Next id: 24. If you add an entry here, please change NUM_FILTER_ENTRIES.
-    private static final int NUM_FILTER_ENTRIES = 24;
+    public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
+    // Next id: 25. If you add an entry here, please change NUM_FILTER_ENTRIES.
+    private static final int NUM_FILTER_ENTRIES = 25;
 
     private static AppFilterRegistry sRegistry;
 
@@ -242,6 +245,12 @@
                         AppStateAppBatteryUsageBridge.FILTER_BATTERY_RESTRICTED_APPS,
                         FILTER_APPS_BATTERY_RESTRICTED,
                         R.string.filter_battery_restricted_title);
+
+        // Apps that can run long background tasks
+        mFilters[FILTER_LONG_BACKGROUND_TASKS] = new AppFilterItem(
+                AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
+                FILTER_LONG_BACKGROUND_TASKS,
+                R.string.long_background_tasks_title);
     }
 
 
@@ -280,6 +289,8 @@
                 return FILTER_APPS_LOCALE;
             case ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION:
                 return FILTER_APPS_BATTERY_OPTIMIZED;
+            case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return FILTER_LONG_BACKGROUND_TASKS;
             default:
                 return FILTER_APPS_ALL;
         }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index a41230a..e129954 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -94,6 +94,7 @@
 import com.android.settings.Settings.ChangeWifiStateActivity;
 import com.android.settings.Settings.GamesStorageActivity;
 import com.android.settings.Settings.HighPowerApplicationsActivity;
+import com.android.settings.Settings.LongBackgroundTasksActivity;
 import com.android.settings.Settings.ManageExternalSourcesActivity;
 import com.android.settings.Settings.ManageExternalStorageActivity;
 import com.android.settings.Settings.MediaManagementAppsActivity;
@@ -112,6 +113,7 @@
 import com.android.settings.applications.AppStateBaseBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
 import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
@@ -128,6 +130,7 @@
 import com.android.settings.applications.appinfo.AppLocaleDetails;
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
+import com.android.settings.applications.appinfo.LongBackgroundTasksDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
 import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
@@ -256,6 +259,7 @@
     public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;
     public static final int LIST_TYPE_APPS_LOCALE = 14;
     public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
+    public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
 
     // List types that should show instant apps.
     public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -402,6 +406,8 @@
             mListType = LIST_TYPE_APPS_LOCALE;
         } else if (className.equals(AppBatteryUsageActivity.class.getName())) {
             mListType = LIST_TYPE_BATTERY_OPTIMIZATION;
+        } else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
+            mListType = LIST_TYPE_LONG_BACKGROUND_TASKS;
         } else {
             mListType = LIST_TYPE_MAIN;
         }
@@ -598,6 +604,8 @@
                 return SettingsEnums.APPS_LOCALE_LIST;
             case LIST_TYPE_BATTERY_OPTIMIZATION:
                 return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return SettingsEnums.LONG_BACKGROUND_TASKS;
             default:
                 return SettingsEnums.PAGE_UNKNOWN;
         }
@@ -735,6 +743,10 @@
                         getActivity(), this, mCurrentPkgName,
                         UserHandle.getUserHandleForUid(mCurrentUid));
                 break;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                startAppInfoFragment(LongBackgroundTasksDetails.class,
+                        R.string.long_background_tasks_label);
+                break;
             // TODO: Figure out if there is a way where we can spin up the profile's settings
             // process ahead of time, to avoid a long load of data when user clicks on a managed
             // app. Maybe when they load the list of apps that contains managed profile apps.
@@ -828,6 +840,8 @@
                 return R.string.help_uri_alarms_and_reminders;
             case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
                 return R.string.help_uri_media_management_apps;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return R.string.help_uri_long_background_tasks;
             default:
             case LIST_TYPE_MAIN:
                 return R.string.help_uri_apps;
@@ -1030,6 +1044,8 @@
             screenTitle = R.string.app_locales_picker_menu_title;
         } else if (className.equals(AppBatteryUsageActivity.class.getName())) {
             screenTitle = R.string.app_battery_usage_title;
+        } else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
+            screenTitle = R.string.long_background_tasks_title;
         } else {
             if (screenTitle == -1) {
                 screenTitle = R.string.all_apps;
@@ -1233,6 +1249,8 @@
                         mManageApplications.mUserManager);
             } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
                 mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
+            } else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
+                mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
             } else {
                 mExtraInfoBridge = null;
             }
@@ -1762,6 +1780,9 @@
                 case LIST_TYPE_BATTERY_OPTIMIZATION:
                     holder.setSummary(null);
                     break;
+                case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                    holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
+                    break;
                 default:
                     holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
                     break;
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index 112385f..fbc09d2 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -26,7 +26,6 @@
 import android.hardware.SensorPrivacyManager;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.face.FaceManager;
-import android.hardware.face.FaceSensorPropertiesInternal;
 import android.os.Bundle;
 import android.text.Html;
 import android.text.method.LinkMovementMethod;
@@ -56,8 +55,6 @@
 import com.google.android.setupcompat.util.WizardManagerHelper;
 import com.google.android.setupdesign.span.LinkSpan;
 
-import java.util.List;
-
 /**
  * Provides introductory info about face unlock and prompts the user to agree before starting face
  * enrollment.
@@ -311,20 +308,12 @@
     }
 
     private boolean maxFacesEnrolled() {
-        final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
         if (mFaceManager != null) {
-            final List<FaceSensorPropertiesInternal> props =
-                    mFaceManager.getSensorPropertiesInternal();
             // This will need to be updated for devices with multiple face sensors.
-            final int max = props.get(0).maxEnrollmentsPerUser;
             final int numEnrolledFaces = mFaceManager.getEnrolledFaces(mUserId).size();
-            final int maxFacesEnrollableIfSUW = getApplicationContext().getResources()
+            final int maxFacesEnrollable = getApplicationContext().getResources()
                     .getInteger(R.integer.suw_max_faces_enrollable);
-            if (isSetupWizard) {
-                return numEnrolledFaces >= maxFacesEnrollableIfSUW;
-            } else {
-                return numEnrolledFaces >= max;
-            }
+            return numEnrolledFaces >= maxFacesEnrollable;
         } else {
             return false;
         }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index bacb65e..3ab2f92 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -178,6 +178,8 @@
     private boolean mHaveShownUdfpsTipLottie;
     private boolean mHaveShownUdfpsLeftEdgeLottie;
     private boolean mHaveShownUdfpsRightEdgeLottie;
+    private boolean mHaveShownUdfpsCenterLottie;
+    private boolean mHaveShownUdfpsGuideLottie;
     private boolean mHaveShownSfpsNoAnimationLottie;
     private boolean mHaveShownSfpsCenterLottie;
     private boolean mHaveShownSfpsTipLottie;
@@ -508,18 +510,31 @@
         switch (getCurrentStage()) {
             case STAGE_CENTER:
                 setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
-                setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
+                if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
+                    setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
+                } else if (!mHaveShownUdfpsCenterLottie && mIllustrationLottie != null) {
+                    mHaveShownUdfpsCenterLottie = true;
+                    // Note: Update string reference when differentiate in between udfps & sfps
+                    mIllustrationLottie.setContentDescription(
+                            getString(R.string.security_settings_sfps_enroll_finger_center_title)
+                    );
+                    configureEnrollmentStage("", R.raw.udfps_center_hint_lottie);
+                }
                 break;
 
             case STAGE_GUIDED:
                 setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
-                if (mIsAccessibilityEnabled) {
+                if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
                     setDescriptionText(R.string.security_settings_udfps_enroll_repeat_a11y_message);
-                } else {
-                    setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message);
+                } else if (!mHaveShownUdfpsGuideLottie && mIllustrationLottie != null) {
+                    mHaveShownUdfpsGuideLottie = true;
+                    mIllustrationLottie.setContentDescription(
+                            getString(R.string.security_settings_fingerprint_enroll_repeat_message)
+                    );
+                    // TODO(b/228100413) Could customize guided lottie animation
+                    configureEnrollmentStage("", R.raw.udfps_center_hint_lottie);
                 }
                 break;
-
             case STAGE_FINGERTIP:
                 setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);
                 if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {
@@ -530,7 +545,6 @@
                     configureEnrollmentStage("", R.raw.udfps_tip_hint_lottie);
                 }
                 break;
-
             case STAGE_LEFT_EDGE:
                 setHeaderText(R.string.security_settings_udfps_enroll_left_edge_title);
                 if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index ce8739b..4cab05b 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -448,7 +448,8 @@
                 mFooterColumns.add(column2);
             } else {
                 final FooterColumn column = new FooterColumn();
-                column.mTitle = getText(R.string.security_settings_fingerprint_v2_home_screen_text);
+                column.mTitle = getText(
+                        R.string.security_settings_fingerprint_enroll_introduction_v2_message);
                 column.mLearnMoreClickListener = learnMoreClickListener;
                 mFooterColumns.add(column);
             }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
index 18db774..32b8300 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
@@ -16,13 +16,17 @@
 
 package com.android.settings.biometrics.fingerprint;
 
+import static android.util.FeatureFlagUtils.SETTINGS_BIOMETRICS2_ENROLLMENT;
+
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.fingerprint.FingerprintManager;
+import android.util.FeatureFlagUtils;
 
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
 /**
@@ -79,7 +83,9 @@
      */
     public String getSettingsClassName() {
         return !hasEnrolled() && isAvailable()
-            ? FingerprintEnrollIntroductionInternal.class.getName()
+            ? (FeatureFlagUtils.isEnabled(mContext, SETTINGS_BIOMETRICS2_ENROLLMENT)
+                ? FingerprintEnrollmentActivity.class.getName()
+                : FingerprintEnrollIntroductionInternal.class.getName())
             : FingerprintSettings.class.getName();
     }
 
diff --git a/src/com/android/settings/biometrics2/OWNERS b/src/com/android/settings/biometrics2/OWNERS
new file mode 100644
index 0000000..a257ed8
--- /dev/null
+++ b/src/com/android/settings/biometrics2/OWNERS
@@ -0,0 +1 @@
+include /src/com/android/settings/biometrics/OWNERS
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
index e788da5..2308f2e 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
@@ -89,7 +89,7 @@
             @Nullable Bundle savedInstanceState) {
 
         final Context context = inflater.getContext();
-        mView = inflater.inflate(R.layout.fingerprint_enroll_introduction, container);
+        mView = inflater.inflate(R.layout.fingerprint_enroll_introduction, container, false);
 
         final ImageView iconFingerprint = mView.findViewById(R.id.icon_fingerprint);
         final ImageView iconDeviceLocked = mView.findViewById(R.id.icon_device_locked);
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index b55b024..7904fdb 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -48,6 +48,7 @@
 import com.android.settings.applications.appinfo.AppLocaleDetails;
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
+import com.android.settings.applications.appinfo.LongBackgroundTasksDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
 import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
@@ -357,7 +358,8 @@
             TurnScreenOnSettings.class.getName(),
             TurnScreenOnDetails.class.getName(),
             NfcAndPaymentFragment.class.getName(),
-            ColorAndMotionFragment.class.getName()
+            ColorAndMotionFragment.class.getName(),
+            LongBackgroundTasksDetails.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
index 31b73bc..d1c8029 100644
--- a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java
@@ -26,7 +26,6 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.util.SparseArray;
-import android.view.View;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.loader.app.LoaderManager;
@@ -210,9 +209,7 @@
             return;
         }
 
-        if (getView().findViewById(R.id.loading_container).getVisibility() == View.VISIBLE) {
-            setLoading(false /* loading */, true /* animate */);
-        }
+        setLoading(false /* loading */, false /* animate */);
 
         final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
         mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 368ba91..f31f2be 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -385,7 +385,7 @@
             return;
         }
 
-        setLoading(false /* loading */, true /* animate */);
+        setLoading(false /* loading */, false /* animate */);
 
         final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
         mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index 038490f..677e5f4 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -39,6 +39,7 @@
 import com.android.settings.network.telephony.MobileNetworkUtils;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.mobile.dataservice.DataServiceUtils;
 import com.android.settingslib.mobile.dataservice.MobileNetworkDatabase;
 import com.android.settingslib.mobile.dataservice.MobileNetworkInfoDao;
 import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
@@ -49,6 +50,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -98,21 +100,29 @@
 
     public static MobileNetworkRepository create(Context context,
             MobileNetworkCallback mobileNetworkCallback) {
-        return new MobileNetworkRepository(context, mobileNetworkCallback);
+        return new MobileNetworkRepository(context, mobileNetworkCallback,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
-    private MobileNetworkRepository(Context context, MobileNetworkCallback mobileNetworkCallback) {
+    public static MobileNetworkRepository createBySubId(Context context,
+            MobileNetworkCallback mobileNetworkCallback, int subId) {
+        return new MobileNetworkRepository(context, mobileNetworkCallback, subId);
+    }
+
+    private MobileNetworkRepository(Context context, MobileNetworkCallback mobileNetworkCallback,
+            int subId) {
+        mSubId = subId;
         mContext = context;
-        mCallback = mobileNetworkCallback;
         mMobileNetworkDatabase = MobileNetworkDatabase.getInstance(context);
+        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+        mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_CREATED);
+        mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+        mCallback = mobileNetworkCallback;
         mSubscriptionInfoDao = mMobileNetworkDatabase.mSubscriptionInfoDao();
         mUiccInfoDao = mMobileNetworkDatabase.mUiccInfoDao();
         mMobileNetworkInfoDao = mMobileNetworkDatabase.mMobileNetworkInfoDao();
-        mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
         mAirplaneModeObserver = new AirplaneModeObserver(new Handler(Looper.getMainLooper()));
         mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
-        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
-        mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_CREATED);
         mFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         mFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
     }
@@ -205,6 +215,10 @@
         return mSubscriptionInfoDao.querySubInfoById(subId);
     }
 
+    public MobileNetworkInfoEntity queryMobileNetworkInfoBySubId(String subId) {
+        return mMobileNetworkInfoDao.queryMobileNetworkInfoBySubId(subId);
+    }
+
     public int getSubInfosCount() {
         return mSubscriptionInfoDao.count();
     }
@@ -222,26 +236,26 @@
         for (int i = 0; i < uiccSlotInfos.length; i++) {
             UiccSlotInfo curSlotInfo = uiccSlotInfos[i];
             if (curSlotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT) {
+                final int index = i;
                 mIsEuicc = curSlotInfo.getIsEuicc();
                 mCardState = curSlotInfo.getCardStateInfo();
                 mIsRemovable = curSlotInfo.isRemovable();
                 mCardId = subInfo.getCardId();
 
                 Collection<UiccPortInfo> uiccPortInfos = curSlotInfo.getPorts();
-                for (UiccPortInfo portInfo : uiccPortInfos) {
+                uiccPortInfos.forEach(portInfo -> {
                     if (portInfo.getPortIndex() == subInfo.getPortIndex()
                             && portInfo.getLogicalSlotIndex() == subInfo.getSimSlotIndex()) {
-                        mPhysicalSlotIndex = i;
+                        mPhysicalSlotIndex = index;
                         mLogicalSlotIndex = portInfo.getLogicalSlotIndex();
                         mIsActive = portInfo.isActive();
                         mPortIndex = portInfo.getPortIndex();
-                        break;
                     } else if (DEBUG) {
                         Log.d(TAG,
                                 "Can not get port index and physicalSlotIndex for subId "
                                         + mSubId);
                     }
-                }
+                });
                 if (mPhysicalSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
                     break;
                 }
@@ -398,7 +412,8 @@
                 MobileNetworkUtils.shouldDisplayNetworkSelectOptions(context, mSubId),
                 MobileNetworkUtils.isTdscdmaSupported(context, mSubId),
                 MobileNetworkUtils.activeNetworkIsCellular(context),
-                SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)
+                SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager),
+                mTelephonyManager.isDataRoamingEnabled()
         );
     }
 
@@ -446,9 +461,10 @@
             }
 
             if (!mSubscriptionInfoMap.isEmpty()) {
-                mSubscriptionInfoMap.forEach((key, value) -> {
-                    deleteAllInfoBySubId(String.valueOf(key));
-                });
+                Iterator<Integer> iterator = mSubscriptionInfoMap.keySet().iterator();
+                while (iterator.hasNext()) {
+                    deleteAllInfoBySubId(String.valueOf(iterator.next()));
+                }
             }
         }
     }
diff --git a/src/com/android/settings/network/ResetNetworkRestrictionViewBuilder.java b/src/com/android/settings/network/ResetNetworkRestrictionViewBuilder.java
new file mode 100644
index 0000000..4f730fb
--- /dev/null
+++ b/src/com/android/settings/network/ResetNetworkRestrictionViewBuilder.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import android.app.Activity;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * A builder for creating restriction View when constructing UI for resetting network
+ * configuration.
+ */
+public class ResetNetworkRestrictionViewBuilder extends NetworkResetRestrictionChecker {
+
+    @VisibleForTesting
+    static final String mRestriction = UserManager.DISALLOW_NETWORK_RESET;
+
+    protected Activity mActivity;
+    protected LayoutInflater mInflater;
+
+    /**
+     * Constructor of builder.
+     *
+     * @param activity Activity to present restriction View.
+     */
+    public ResetNetworkRestrictionViewBuilder(Activity activity) {
+        super(activity);
+        mActivity = activity;
+    }
+
+    /**
+     * Option for configuring LayoutInflater.
+     *
+     * @param inflater LayoutInflater
+     * @return this builder
+     */
+    public ResetNetworkRestrictionViewBuilder setLayoutInflater(LayoutInflater inflater) {
+        mInflater = inflater;
+        return this;
+    }
+
+    /**
+     * Try to provide a View if access to reset network is not allowed.
+     * @return a View which presenting information of restrictions.
+     *         {@code null} when no restriction on accessing.
+     */
+    public View build() {
+        if (hasUserRestriction()) {
+            return operationNotAllow();
+        }
+
+        // Not allow when this option is restricted.
+        EnforcedAdmin admin = getEnforceAdminByRestriction();
+        if (admin == null) {
+            return null;
+        }
+
+        createRestrictDialogBuilder(admin)
+                .setOnDismissListener(dialogInterface -> mActivity.finish())
+                .show();
+        return createEmptyView();
+    }
+
+    @VisibleForTesting
+    protected LayoutInflater getLayoutInflater() {
+        if (mInflater != null) {
+            return mInflater;
+        }
+        return mActivity.getLayoutInflater();
+    }
+
+    @VisibleForTesting
+    protected View operationNotAllow() {
+        return getLayoutInflater().inflate(R.layout.network_reset_disallowed_screen, null);
+    }
+
+    @VisibleForTesting
+    protected EnforcedAdmin getEnforceAdminByRestriction() {
+        return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+                mActivity, mRestriction, UserHandle.myUserId());
+    }
+
+    @VisibleForTesting
+    protected AlertDialog.Builder createRestrictDialogBuilder(EnforcedAdmin admin) {
+        return (new ActionDisabledByAdminDialogHelper(mActivity))
+                .prepareDialogBuilder(mRestriction, admin);
+    }
+
+    @VisibleForTesting
+    protected View createEmptyView() {
+        return new ViewStub(mActivity);
+    }
+}
diff --git a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
index da81213..f4543f5 100644
--- a/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
+++ b/src/com/android/settings/network/telephony/AutoDataSwitchPreferenceController.java
@@ -99,7 +99,7 @@
 
     @Override
     public boolean isChecked() {
-        return mManager.isMobileDataPolicyEnabled(
+        return mManager != null && mManager.isMobileDataPolicyEnabled(
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH);
     }
 
diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
index 2525fbd..1aca6b9 100644
--- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
@@ -135,6 +135,11 @@
     @Override
     public void updateState(Preference preference) {
         super.updateState(preference);
+
+        if (mBuilder == null) {
+            return;
+        }
+
         final ListPreference listPreference = (ListPreference) preference;
 
         mBuilder.setPreferenceEntries();
@@ -871,6 +876,8 @@
 
     @Override
     public void onSubscriptionsChanged() {
-        mBuilder.updateConfig();
+        if (mBuilder != null) {
+            mBuilder.updateConfig();
+        }
     }
 }
diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
index 85d6e73..5908ecd 100644
--- a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
@@ -96,7 +96,8 @@
 
     @Override
     public boolean isChecked() {
-        return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS);
+        return mTelephonyManager != null && mTelephonyManager.isDataEnabledForApn(
+                ApnSetting.TYPE_MMS);
     }
 
     private void refreshPreference() {
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index a0c9679..97ba8b8 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -23,7 +23,6 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -40,8 +39,8 @@
 import com.android.settings.SettingsActivity;
 import com.android.settings.datausage.BillingCyclePreferenceController;
 import com.android.settings.datausage.DataUsageSummaryPreferenceController;
-import com.android.settings.network.ActiveSubscriptionsListener;
 import com.android.settings.network.CarrierWifiTogglePreferenceController;
+import com.android.settings.network.MobileNetworkRepository;
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceController;
 import com.android.settings.network.telephony.cdma.CdmaSystemSelectPreferenceController;
@@ -50,15 +49,26 @@
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.wifi.WifiPickerTrackerHelper;
 import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.mobile.dataservice.DataServiceUtils;
+import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
+import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
+import com.android.settingslib.mobile.dataservice.UiccInfoEntity;
 import com.android.settingslib.search.SearchIndexable;
 import com.android.settingslib.utils.ThreadUtils;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.function.Consumer;
 
 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
-public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
+public class MobileNetworkSettings extends AbstractMobileNetworkSettings implements
+        MobileNetworkRepository.MobileNetworkCallback {
 
     private static final String LOG_TAG = "NetworkSettings";
     public static final int REQUEST_CODE_EXIT_ECM = 17;
@@ -66,10 +76,14 @@
     @VisibleForTesting
     static final String KEY_CLICKED_PREF = "key_clicked_pref";
 
+    private static final String KEY_ROAMING_PREF = "button_roaming_key";
+
     //String keys for preference lookup
     private static final String BUTTON_CDMA_SYSTEM_SELECT_KEY = "cdma_system_select_key";
     private static final String BUTTON_CDMA_SUBSCRIPTION_KEY = "cdma_subscription_key";
 
+    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
     private TelephonyManager mTelephonyManager;
     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -79,9 +93,11 @@
     private UserManager mUserManager;
     private String mClickedPrefKey;
 
-    private ActiveSubscriptionsListener mActiveSubscriptionsListener;
-    private boolean mDropFirstSubscriptionChangeNotify;
-    private int mActiveSubscriptionsListenerCount;
+    private MobileNetworkRepository mMobileNetworkRepository;
+    private List<SubscriptionInfoEntity> mSubInfoEntityList = new ArrayList<>();
+    private Map<Integer, SubscriptionInfoEntity> mSubscriptionInfoMap = new HashMap<>();
+    private SubscriptionInfoEntity mSubscriptionInfoEntity;
+    private MobileNetworkInfoEntity mMobileNetworkInfoEntity;
 
     public MobileNetworkSettings() {
         super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
@@ -138,12 +154,21 @@
                     MobileNetworkUtils.getSearchableSubscriptionId(context));
             Log.d(LOG_TAG, "display subId from getArguments(): " + mSubId);
         }
-
-        if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
+        mMobileNetworkRepository = MobileNetworkRepository.create(context, this);
+        mExecutor.execute(() -> {
+            mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById(
+                    String.valueOf(mSubId));
+            mMobileNetworkInfoEntity =
+                    mMobileNetworkRepository.queryMobileNetworkInfoBySubId(
+                            String.valueOf(mSubId));
+        });
+        if (mSubId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             return Arrays.asList();
         }
         return Arrays.asList(
                 new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),
+                        this, mSubId),
+                new RoamingPreferenceController(context, KEY_ROAMING_PREF, getSettingsLifecycle(),
                         this, mSubId));
     }
 
@@ -151,28 +176,38 @@
     public void onAttach(Context context) {
         super.onAttach(context);
 
-        Intent intent = getIntent();
-        SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);
-        if (info == null) {
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             Log.d(LOG_TAG, "Invalid subId request " + mSubId);
             return;
         }
 
-        int oldSubId = mSubId;
-        updateSubscriptions(info);
-        // If the subscription has changed or the new intent does not contain the opt in action,
-        // remove the old discovery dialog. If the activity is being recreated, we will see
-        // onCreate -> onNewIntent, so the dialog will first be recreated for the old subscription
-        // and then removed.
-        if (!MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
-            removeContactDiscoveryDialog(oldSubId);
-        }
+        Intent intent = getIntent();
+        if (intent != null) {
+            int updateSubscriptionIndex = intent.getIntExtra(Settings.EXTRA_SUB_ID,
+                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
-        // evaluate showing the new discovery dialog if this intent contains an action to show the
-        // opt-in.
-        if (MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
-            showContactDiscoveryDialog(
-                    SubscriptionUtil.getSubscriptionOrDefault(context, mSubId));
+            if (updateSubscriptionIndex != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+                int oldSubId = mSubId;
+                mSubId = updateSubscriptionIndex;
+                // If the subscription has changed or the new intent does not contain the opt in
+                // action,
+                // remove the old discovery dialog. If the activity is being recreated, we will see
+                // onCreate -> onNewIntent, so the dialog will first be recreated for the old
+                // subscription
+                // and then removed.
+                if (updateSubscriptionIndex != oldSubId
+                        || !MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
+                    removeContactDiscoveryDialog(oldSubId);
+                }
+
+                // evaluate showing the new discovery dialog if this intent contains an action to
+                // show the
+                // opt-in.
+                if (MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
+                    showContactDiscoveryDialog();
+                }
+            }
+
         }
 
         final DataUsageSummaryPreferenceController dataUsageSummaryPreferenceController =
@@ -194,7 +229,13 @@
         use(MobileDataPreferenceController.class).setWifiPickerTrackerHelper(
                 new WifiPickerTrackerHelper(getSettingsLifecycle(), context,
                         null /* WifiPickerTrackerCallback */));
-        use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
+
+        final RoamingPreferenceController roamingPreferenceController =
+                use(RoamingPreferenceController.class);
+        if (roamingPreferenceController != null) {
+            roamingPreferenceController.init(getFragmentManager(), mSubId,
+                    mMobileNetworkInfoEntity);
+        }
         use(ApnPreferenceController.class).init(mSubId);
         use(CarrierPreferenceController.class).init(mSubId);
         use(DataUsagePreferenceController.class).init(mSubId);
@@ -258,68 +299,36 @@
     @Override
     public void onResume() {
         super.onResume();
+        mMobileNetworkRepository.addRegister(this);
         // TODO: remove log after fixing b/182326102
         Log.d(LOG_TAG, "onResume() subId=" + mSubId);
-        if (mActiveSubscriptionsListener == null) {
-            mActiveSubscriptionsListener = new ActiveSubscriptionsListener(
-                    getContext().getMainLooper(), getContext(), mSubId) {
-                public void onChanged() {
-                    onSubscriptionDetailChanged();
-                }
-            };
-            mDropFirstSubscriptionChangeNotify = true;
-        }
-        mActiveSubscriptionsListener.start();
     }
 
     private void onSubscriptionDetailChanged() {
-        if (mDropFirstSubscriptionChangeNotify) {
-            mDropFirstSubscriptionChangeNotify = false;
-            Log.d(LOG_TAG, "Callback during onResume()");
-            return;
-        }
 
-        final SubscriptionInfo subInfo = SubscriptionUtil
-                .getSubscriptionOrDefault(getContext(), mSubId);
-
-        if (subInfo != null) {
+        if (mSubscriptionInfoEntity != null) {
             /**
              * Update the title when SIM stats got changed
              */
             final Consumer<Activity> renameTitle = activity -> {
                 if (activity != null && !activity.isFinishing()) {
                     if (activity instanceof SettingsActivity) {
-                        final CharSequence displayName = SubscriptionUtil
-                                .getUniqueSubscriptionDisplayName(subInfo, activity);
-                        ((SettingsActivity)activity).setTitle(displayName);
+                        ((SettingsActivity) activity).setTitle(mSubscriptionInfoEntity.uniqueName);
                     }
                 }
             };
 
-            ThreadUtils.postOnMainThread(() -> renameTitle.accept(getActivity()));
+            ThreadUtils.postOnMainThread(() -> {
+                renameTitle.accept(getActivity());
+                redrawPreferenceControllers();
+            });
         }
-
-        mActiveSubscriptionsListenerCount++;
-        if (mActiveSubscriptionsListenerCount != 1) {
-            return;
-        }
-
-        ThreadUtils.postOnMainThread(() -> {
-            if (subInfo == null) {
-                finishFragment();
-                return;
-            }
-            mActiveSubscriptionsListenerCount = 0;
-            redrawPreferenceControllers();
-        });
     }
 
     @Override
     public void onDestroy() {
-        if (mActiveSubscriptionsListener != null) {
-            mActiveSubscriptionsListener.stop();
-        }
         super.onDestroy();
+        mMobileNetworkRepository.removeRegister();
     }
 
     @VisibleForTesting
@@ -375,7 +384,7 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
+        if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             final MenuItem item = menu.add(Menu.NONE, R.id.edit_sim_name, Menu.NONE,
                     R.string.mobile_network_sim_name);
             item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
@@ -386,7 +395,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem menuItem) {
-        if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
+        if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             if (menuItem.getItemId() == R.id.edit_sim_name) {
                 RenameMobileNetworkDialogFragment.newInstance(mSubId).show(
                         getFragmentManager(), RenameMobileNetworkDialogFragment.TAG);
@@ -422,18 +431,18 @@
         }
     }
 
-    private void showContactDiscoveryDialog(SubscriptionInfo info) {
-        if (info == null) {
-            Log.d(LOG_TAG, "Invalid subId request " + mSubId);
+    private void showContactDiscoveryDialog() {
+        ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(mSubId);
+
+        if (mSubscriptionInfoEntity == null) {
+            Log.d(LOG_TAG, "Zoey, showContactDiscoveryDialog, Invalid subId request " + mSubId);
             onDestroy();
             return;
         }
 
-        CharSequence carrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(info,
-                getContext());
-        ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(mSubId);
         if (fragment == null) {
-            fragment = ContactDiscoveryDialogFragment.newInstance(mSubId, carrierName);
+            fragment = ContactDiscoveryDialogFragment.newInstance(mSubId,
+                    mSubscriptionInfoEntity.uniqueName);
         }
         // Only try to show the dialog if it has not already been added, otherwise we may
         // accidentally add it multiple times, causing multiple dialogs.
@@ -443,12 +452,53 @@
         }
     }
 
-    private void updateSubscriptions(SubscriptionInfo subscription) {
-        if (subscription == null) {
-            return;
-        }
-        final int subscriptionIndex = subscription.getSubscriptionId();
+    @Override
+    public void onAvailableSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
+    }
 
-        mSubId = subscriptionIndex;
+    @Override
+    public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
+        if (DataServiceUtils.shouldUpdateEntityList(mSubInfoEntityList, subInfoEntityList)) {
+
+            // Check the current subId is existed or not, if so, finish it.
+            if (!mSubscriptionInfoMap.isEmpty()) {
+
+                // Check each subInfo and remove it in the map based on the new list.
+                for (SubscriptionInfoEntity entity : subInfoEntityList) {
+                    mSubscriptionInfoMap.remove(Integer.parseInt(entity.subId));
+                }
+
+                Iterator<Integer> iterator = mSubscriptionInfoMap.keySet().iterator();
+                while (iterator.hasNext()) {
+                    if (iterator.next() == mSubId) {
+                        finishFragment();
+                        return;
+                    }
+                }
+            }
+
+            mSubInfoEntityList = subInfoEntityList;
+            mSubInfoEntityList.forEach(entity -> {
+                int subId = Integer.parseInt(entity.subId);
+                mSubscriptionInfoMap.put(subId, entity);
+                if (subId == mSubId) {
+                    mSubscriptionInfoEntity = entity;
+                    onSubscriptionDetailChanged();
+                }
+            });
+        }
+    }
+
+    @Override
+    public void onAllUiccInfoChanged(List<UiccInfoEntity> uiccInfoEntityList) {
+    }
+
+    @Override
+    public void onAllMobileNetworkInfoChanged(
+            List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList) {
+    }
+
+    @Override
+    public void onAirplaneModeChanged(boolean enabled) {
     }
 }
diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java
index eb77312..2ed7d79 100644
--- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.network.telephony;
 
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
 import android.content.Context;
 import android.os.PersistableBundle;
 import android.provider.Settings;
@@ -25,21 +28,31 @@
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.network.GlobalSettingsChangeListener;
+import com.android.settings.network.MobileNetworkRepository;
 import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.mobile.dataservice.DataServiceUtils;
+import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
+import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
+import com.android.settingslib.mobile.dataservice.UiccInfoEntity;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Preference controller for "Roaming"
  */
 public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements
-        LifecycleObserver, OnStart, OnStop {
+        LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback {
 
     private static final String TAG = "RoamingController";
     private static final String DIALOG_TAG = "MobileDataDialog";
@@ -47,6 +60,9 @@
     private RestrictedSwitchPreference mSwitchPreference;
     private TelephonyManager mTelephonyManager;
     private CarrierConfigManager mCarrierConfigManager;
+    protected MobileNetworkRepository mMobileNetworkRepository;
+    protected LifecycleOwner mLifecycleOwner;
+    private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>();
 
     /**
      * There're 2 listeners both activated at the same time.
@@ -59,10 +75,18 @@
 
     @VisibleForTesting
     FragmentManager mFragmentManager;
+    MobileNetworkInfoEntity mMobileNetworkInfoEntity;
 
-    public RoamingPreferenceController(Context context, String key) {
+    public RoamingPreferenceController(Context context, String key, Lifecycle lifecycle,
+            LifecycleOwner lifecycleOwner, int subId) {
         super(context, key);
+        mSubId = subId;
         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+        mMobileNetworkRepository = MobileNetworkRepository.createBySubId(context, this, mSubId);
+        mLifecycleOwner = lifecycleOwner;
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
     }
 
     @Override
@@ -75,8 +99,9 @@
         return AVAILABLE;
     }
 
-    @Override
+    @OnLifecycleEvent(ON_START)
     public void onStart() {
+        mMobileNetworkRepository.addRegister(mLifecycleOwner);
         if (mListener == null) {
             mListener = new GlobalSettingsChangeListener(mContext,
                     Settings.Global.DATA_ROAMING) {
@@ -100,8 +125,9 @@
         };
     }
 
-    @Override
+    @OnLifecycleEvent(ON_STOP)
     public void onStop() {
+        mMobileNetworkRepository.removeRegister();
         stopMonitor();
         stopMonitorSubIdSpecific();
     }
@@ -114,7 +140,7 @@
 
     @Override
     public int getAvailabilityStatus(int subId) {
-        return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
+        return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
                 ? AVAILABLE
                 : AVAILABLE_UNSEARCHABLE;
     }
@@ -135,19 +161,26 @@
     @Override
     public void updateState(Preference preference) {
         super.updateState(preference);
-        final RestrictedSwitchPreference switchPreference = (RestrictedSwitchPreference) preference;
-        if (!switchPreference.isDisabledByAdmin()) {
-            switchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-            switchPreference.setChecked(isChecked());
+        mSwitchPreference = (RestrictedSwitchPreference) preference;
+        update();
+    }
+
+    private void update() {
+        if (mSwitchPreference == null) {
+            return;
+        }
+        if (!mSwitchPreference.isDisabledByAdmin()) {
+            mSwitchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+            mSwitchPreference.setChecked(isChecked());
         }
     }
 
     @VisibleForTesting
     boolean isDialogNeeded() {
-        final boolean isRoamingEnabled = mTelephonyManager.isDataRoamingEnabled();
+        final boolean isRoamingEnabled = mMobileNetworkInfoEntity == null ? false
+                : mMobileNetworkInfoEntity.isDataRoamingEnabled;
         final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
                 mSubId);
-
         // Need dialog if we need to turn on roaming and the roaming charge indication is allowed
         if (!isRoamingEnabled && (carrierConfig == null || !carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL))) {
@@ -158,12 +191,14 @@
 
     @Override
     public boolean isChecked() {
-        return mTelephonyManager.isDataRoamingEnabled();
+        return mMobileNetworkInfoEntity == null ? false
+                : mMobileNetworkInfoEntity.isDataRoamingEnabled;
     }
 
-    public void init(FragmentManager fragmentManager, int subId) {
+    public void init(FragmentManager fragmentManager, int subId, MobileNetworkInfoEntity entity) {
         mFragmentManager = fragmentManager;
         mSubId = subId;
+        mMobileNetworkInfoEntity = entity;
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             return;
@@ -197,4 +232,42 @@
             mListenerForSubId = null;
         }
     }
+
+    @VisibleForTesting
+    public void setMobileNetworkInfoEntity(MobileNetworkInfoEntity mobileNetworkInfoEntity) {
+        mMobileNetworkInfoEntity = mobileNetworkInfoEntity;
+    }
+
+    @Override
+    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+    }
+
+    @Override
+    public void onAvailableSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
+    }
+
+    @Override
+    public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> subInfoEntityList) {
+    }
+
+    @Override
+    public void onAllUiccInfoChanged(List<UiccInfoEntity> uiccInfoEntityList) {
+    }
+
+    @Override
+    public void onAllMobileNetworkInfoChanged(
+            List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList) {
+        if (DataServiceUtils.shouldUpdateEntityList(mMobileNetworkInfoEntityList,
+                mobileNetworkInfoEntityList)) {
+            mMobileNetworkInfoEntityList = mobileNetworkInfoEntityList;
+            mMobileNetworkInfoEntityList.forEach(entity -> {
+                if (Integer.parseInt(entity.subId) == mSubId) {
+                    mMobileNetworkInfoEntity = entity;
+                    update();
+                    refreshSummary(mSwitchPreference);
+                    return;
+                }
+            });
+        }
+    }
 }
diff --git a/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java b/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
index 5dd4453..1b9103f 100644
--- a/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
+++ b/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceController.java
@@ -18,6 +18,7 @@
 
 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA;
 import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA;
+import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_UNKNOWN;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -43,7 +44,10 @@
         super.updateState(preference);
         final ListPreference listPreference = (ListPreference) preference;
         listPreference.setVisible(getAvailabilityStatus() == AVAILABLE);
-        final int mode = mTelephonyManager.getCdmaRoamingMode();
+        boolean hasTelephonyMgr = mTelephonyManager != null;
+        final int mode =
+                hasTelephonyMgr ? mTelephonyManager.getCdmaRoamingMode()
+                        : TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT;
         if (mode != TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT) {
             if (mode == TelephonyManager.CDMA_ROAMING_MODE_HOME
                     || mode == TelephonyManager.CDMA_ROAMING_MODE_ANY) {
@@ -53,9 +57,11 @@
             }
         }
 
-        final int settingsNetworkMode = MobileNetworkUtils.getNetworkTypeFromRaf(
-                (int) mTelephonyManager.getAllowedNetworkTypesForReason(
-                        TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+        final int settingsNetworkMode =
+                hasTelephonyMgr ? MobileNetworkUtils.getNetworkTypeFromRaf(
+                        (int) mTelephonyManager.getAllowedNetworkTypesForReason(
+                                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER))
+                        : NETWORK_MODE_UNKNOWN;
         final boolean enableList = settingsNetworkMode != NETWORK_MODE_LTE_GSM_WCDMA
                 && settingsNetworkMode != NETWORK_MODE_NR_LTE_GSM_WCDMA;
         listPreference.setEnabled(enableList);
diff --git a/src/com/android/settings/security/MemtagHelper.java b/src/com/android/settings/security/MemtagHelper.java
index ecd6ea6..c891eb2 100644
--- a/src/com/android/settings/security/MemtagHelper.java
+++ b/src/com/android/settings/security/MemtagHelper.java
@@ -46,7 +46,7 @@
         if (MemtagHelper.isForcedOff()) {
             return BasePreferenceController.DISABLED_DEPENDENT_SETTING;
         }
-        return SystemProperties.getBoolean("ro.arm64.memtag.bootctl_supported", false)
+        return SystemProperties.getBoolean("ro.arm64.memtag.bootctl_settings_toggle", false)
                 ? BasePreferenceController.AVAILABLE
                 : BasePreferenceController.UNSUPPORTED_ON_DEVICE;
     }
diff --git a/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
index d483dd1..a1035dc 100644
--- a/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
+++ b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
@@ -57,10 +57,6 @@
     }
 
     private int getSubId(int slotIndex) {
-        int[] subId = SubscriptionManager.getSubId(slotIndex);
-        if (subId != null && subId.length > 0) {
-            return subId[0];
-        }
-        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        return SubscriptionManager.getSubscriptionId(slotIndex);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceControllerTest.java
new file mode 100644
index 0000000..1b361d2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceControllerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongBackgroundTasksDetailsPreferenceControllerTest {
+
+    @Mock
+    private AppInfoDashboardFragment mFragment;
+    @Mock
+    private Preference mPreference;
+
+    private Context mContext;
+    private LongBackgroundTasksDetailsPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        mController = spy(new LongBackgroundTasksDetailsPreferenceController(mContext, "test_key"));
+        mController.setPackageName("Package1");
+        mController.setParentFragment(mFragment);
+        final String key = mController.getPreferenceKey();
+        when(mPreference.getKey()).thenReturn(key);
+    }
+
+    @Test
+    public void getAvailabilityStatus_notCandidate_shouldReturnUnavailable() {
+        doReturn(false).when(mController).isCandidate();
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_isCandidate_shouldReturnAvailable() {
+        doReturn(true).when(mController).isCandidate();
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.AVAILABLE);
+    }
+
+    @Test
+    public void getDetailFragmentClass_shouldReturnAlarmsAndRemindersDetails() {
+        assertThat(mController.getDetailFragmentClass())
+                .isEqualTo(LongBackgroundTasksDetails.class);
+    }
+
+    @Test
+    public void updateState_shouldSetSummary() {
+        final String summary = "test summary";
+        doReturn(summary).when(mController).getPreferenceSummary();
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setSummary(summary);
+    }
+
+    @Test
+    public void isCandidate_nullPackageInfo_shouldNotCrash() {
+        mController.isCandidate();
+        // no crash
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsTest.java
new file mode 100644
index 0000000..7d159b9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class LongBackgroundTasksDetailsTest {
+
+    @Mock
+    private RestrictedSwitchPreference mSwitchPref;
+    @Mock
+    private PackageInfo mPackageInfo;
+    @Mock
+    private AppStateLongBackgroundTasksBridge mAppStateBridge;
+    @Mock
+    private AppStateLongBackgroundTasksBridge.LongBackgroundTasksState mPermissionState;
+
+    private LongBackgroundTasksDetails mFragment = new LongBackgroundTasksDetails();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        ReflectionHelpers.setField(mFragment, "mSwitchPref", mSwitchPref);
+        ReflectionHelpers.setField(mFragment, "mAppBridge", mAppStateBridge);
+    }
+
+    @Test
+    public void refreshUi_noPackageInfo_shouldReturnFalseAndNoCrash() {
+        mFragment.refreshUi();
+
+        assertThat(mFragment.refreshUi()).isFalse();
+        // should not crash
+    }
+
+    @Test
+    public void refreshUi_noApplicationInfo_shouldReturnFalseAndNoCrash() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+
+        mFragment.refreshUi();
+
+        assertThat(mFragment.refreshUi()).isFalse();
+        // should not crash
+    }
+
+    @Test
+    public void refreshUi_hasApplicationInfo_shouldReturnTrue() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+
+        mFragment.refreshUi();
+
+        assertThat(mFragment.refreshUi()).isTrue();
+    }
+
+    @Test
+    public void refreshUi_switchPreferenceEnabled() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+        when(mPermissionState.shouldBeVisible()).thenReturn(false);
+
+        mFragment.refreshUi();
+        verify(mSwitchPref).setEnabled(false);
+
+        when(mPermissionState.shouldBeVisible()).thenReturn(true);
+
+        mFragment.refreshUi();
+        verify(mSwitchPref).setEnabled(true);
+    }
+
+    @Test
+    public void refreshUi_switchPreferenceChecked() {
+        ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+        mPackageInfo.applicationInfo = new ApplicationInfo();
+        when(mAppStateBridge.createPermissionState(nullable(String.class), anyInt()))
+                .thenReturn(mPermissionState);
+
+        when(mPermissionState.isAllowed()).thenReturn(true);
+        mFragment.refreshUi();
+        verify(mSwitchPref).setChecked(true);
+
+        when(mPermissionState.isAllowed()).thenReturn(false);
+        mFragment.refreshUi();
+        verify(mSwitchPref).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
index 2e5cc02..a6c019b 100644
--- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
@@ -22,13 +22,16 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
 
 import android.content.Intent;
+import android.hardware.face.Face;
 import android.hardware.face.FaceManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.settings.R;
 import com.android.settings.biometrics.BiometricUtils;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
@@ -47,6 +50,9 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowActivity;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {
         ShadowLockPatternUtils.class,
@@ -77,6 +83,34 @@
         mActivity.mOverrideFaceManager = mFaceManager;
     }
 
+    private void setFaceManagerToHave(int numEnrollments) {
+        List<Face> faces = new ArrayList<>();
+        for (int i = 0; i < numEnrollments; i++) {
+            faces.add(new Face("Face " + i /* name */, 1 /*faceId */, 1 /* deviceId */));
+        }
+        when(mFaceManager.getEnrolledFaces(anyInt())).thenReturn(faces);
+    }
+
+    @Test
+    public void intro_CheckCanEnroll() {
+        setFaceManagerToHave(0 /* numEnrollments */);
+        setupActivity(new Intent());
+        mController.create();
+        int result = mActivity.checkMaxEnrolled();
+
+        assertThat(result).isEqualTo(0);
+    }
+
+    @Test
+    public void intro_CheckMaxEnrolled() {
+        setFaceManagerToHave(1 /* numEnrollments */);
+        setupActivity(new Intent());
+        mController.create();
+        int result = mActivity.checkMaxEnrolled();
+
+        assertThat(result).isEqualTo(R.string.face_intro_error_max);
+    }
+
     @Test
     public void testOnCreate() {
         setupActivity(new Intent());
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 289bfab..185af9e 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -31,13 +31,12 @@
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.mock;
-
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -188,6 +187,38 @@
     }
 
     @Test
+    public void fingerprintUdfpsOverlayEnrollment_PlaysAllAnimationsAssetsCorrectly() {
+        initializeActivityFor(TYPE_UDFPS_OPTICAL);
+
+        int totalEnrollSteps = 25;
+        int initStageSteps = -1, initStageRemaining = 0;
+
+        when(mSidecar.getEnrollmentSteps()).thenReturn(initStageSteps);
+        when(mSidecar.getEnrollmentRemaining()).thenReturn(initStageRemaining);
+
+        mActivity.onEnrollmentProgressChange(initStageSteps, initStageRemaining);
+
+        when(mSidecar.getEnrollmentSteps()).thenReturn(totalEnrollSteps);
+
+        for (int remaining = totalEnrollSteps; remaining > 0; remaining--) {
+            when(mSidecar.getEnrollmentRemaining()).thenReturn(remaining);
+            mActivity.onEnrollmentProgressChange(totalEnrollSteps, remaining);
+        }
+
+        List<Integer> expectedLottieAssetOrder = List.of(
+                R.raw.udfps_center_hint_lottie,
+                R.raw.udfps_tip_hint_lottie,
+                R.raw.udfps_left_edge_hint_lottie,
+                R.raw.udfps_right_edge_hint_lottie
+        );
+
+        ArgumentCaptor<Integer> lottieAssetCaptor = ArgumentCaptor.forClass(Integer.class);
+        verify(mIllustrationLottie, times(4)).setAnimation(lottieAssetCaptor.capture());
+        List<Integer> observedLottieAssetOrder = lottieAssetCaptor.getAllValues();
+        assertThat(observedLottieAssetOrder).isEqualTo(expectedLottieAssetOrder);
+    }
+
+    @Test
     public void fingerprintSfpsEnroll_PlaysAllAnimationsAssetsCorrectly() {
         initializeActivityFor(TYPE_POWER_BUTTON);
 
@@ -354,4 +385,4 @@
             return mContext;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobServiceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobServiceTest.java
index 76a9b06..4c276ba 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobServiceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobServiceTest.java
@@ -71,7 +71,8 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
-        mJobScheduler = spy(new JobSchedulerImpl(IJobScheduler.Stub.asInterface(new Binder())));
+        mJobScheduler = spy(new JobSchedulerImpl(mContext,
+                IJobScheduler.Stub.asInterface(new Binder())));
         when(mContext.getSystemService(JobScheduler.class)).thenReturn(mJobScheduler);
     }
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobServiceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobServiceTest.java
index c6aaa32..3807be6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobServiceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobServiceTest.java
@@ -69,7 +69,8 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
-        mJobScheduler = spy(new JobSchedulerImpl(IJobScheduler.Stub.asInterface(new Binder())));
+        mJobScheduler = spy(new JobSchedulerImpl(mContext,
+                IJobScheduler.Stub.asInterface(new Binder())));
         when(mContext.getSystemService(JobScheduler.class)).thenReturn(mJobScheduler);
 
         mJobService = spy(new AnomalyConfigJobService());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java
index dd90dc8..faa3275 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java
@@ -113,7 +113,8 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = spy(RuntimeEnvironment.application);
-        mJobScheduler = spy(new JobSchedulerImpl(IJobScheduler.Stub.asInterface(new Binder())));
+        mJobScheduler = spy(new JobSchedulerImpl(mContext,
+                IJobScheduler.Stub.asInterface(new Binder())));
         when(mContext.getSystemService(JobScheduler.class)).thenReturn(mJobScheduler);
 
         mPolicy = new BatteryTipPolicy(mContext);
diff --git a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
index 13bc3db..ff5c0d8 100644
--- a/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
+++ b/tests/unit/src/com/android/settings/applications/manageapplications/AppFilterRegistryTest.java
@@ -26,10 +26,12 @@
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_USAGE_ACCESS;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WITH_OVERLAY;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WRITE_SETTINGS;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_LONG_BACKGROUND_TASKS;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MANAGE_SOURCES;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS;
@@ -77,5 +79,8 @@
         assertThat(registry.getDefaultFilterType(LIST_TYPE_STORAGE)).isEqualTo(FILTER_APPS_ALL);
 
         assertThat(registry.getDefaultFilterType(LIST_TYPE_GAMES)).isEqualTo(FILTER_APPS_ALL);
+
+        assertThat(registry.getDefaultFilterType(LIST_TYPE_LONG_BACKGROUND_TASKS))
+                .isEqualTo(FILTER_LONG_BACKGROUND_TASKS);
     }
 }
diff --git a/tests/unit/src/com/android/settings/network/ResetNetworkRestrictionViewBuilderTest.java b/tests/unit/src/com/android/settings/network/ResetNetworkRestrictionViewBuilderTest.java
new file mode 100644
index 0000000..fba4928
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/ResetNetworkRestrictionViewBuilderTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.UserManager;
+import android.view.View;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class ResetNetworkRestrictionViewBuilderTest {
+
+    @Mock
+    private Activity mActivity;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private View mView;
+    @Mock
+    private AlertDialog.Builder mAlertDialogBuilder;
+
+    private ResetNetworkRestrictionViewBuilder mBuilder;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(mUserManager).when(mActivity).getSystemService(Context.USER_SERVICE);
+    }
+
+    @Test
+    public void build_getNull_whenNoRestriction() {
+        mBuilder = new ResetNetworkRestrictionViewBuilder(mActivity) {
+            @Override
+            protected boolean hasUserRestriction() { return false; }
+            @Override
+            protected EnforcedAdmin getEnforceAdminByRestriction() { return null; }
+        };
+
+        assertThat(mBuilder.build()).isNull();
+    }
+
+    @Test
+    public void build_getView_whenUserRestriction() {
+        mBuilder = new ResetNetworkRestrictionViewBuilder(mActivity) {
+            @Override
+            protected boolean hasUserRestriction() { return true; }
+            @Override
+            protected View operationNotAllow() { return mView; }
+        };
+
+        assertThat(mBuilder.build()).isNotNull();
+    }
+
+    @Test
+    public void build_getView_whenEnforceAdminRestriction() {
+        doReturn(mAlertDialogBuilder).when(mAlertDialogBuilder).setOnDismissListener(any());
+
+        String restriction = ResetNetworkRestrictionViewBuilder.mRestriction;
+        EnforcedAdmin admin = RestrictedLockUtils.EnforcedAdmin
+                .createDefaultEnforcedAdminWithRestriction(restriction);
+
+        mBuilder = new ResetNetworkRestrictionViewBuilder(mActivity) {
+            @Override
+            protected boolean hasUserRestriction() { return false; }
+            @Override
+            protected EnforcedAdmin getEnforceAdminByRestriction() { return admin; }
+            @Override
+            protected AlertDialog.Builder createRestrictDialogBuilder(EnforcedAdmin admin) {
+                return mAlertDialogBuilder;
+            }
+            @Override
+            protected View createEmptyView() { return mView; }
+        };
+
+        assertThat(mBuilder.build()).isNotNull();
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
index 7ff95fb..d221280 100644
--- a/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
@@ -23,12 +23,14 @@
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.Looper;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -36,12 +38,16 @@
 
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.settings.core.BasePreferenceController;
 import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -65,15 +71,25 @@
     private FragmentTransaction mFragmentTransaction;
     @Mock
     private CarrierConfigManager mCarrierConfigManager;
+    @Mock
+    private Lifecycle mLifecycle;
+    @Mock
+    private LifecycleOwner mLifecycleOwner;
 
+    private LifecycleRegistry mLifecycleRegistry;
     private RoamingPreferenceController mController;
     private RestrictedSwitchPreference mPreference;
     private Context mContext;
+    private MobileNetworkInfoEntity mMobileNetworkInfoEntity;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
         mContext = spy(ApplicationProvider.getApplicationContext());
         doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
         doReturn(mSubscriptionManager).when(mContext).getSystemService(
@@ -87,11 +103,21 @@
         doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();
 
         mPreference = spy(new RestrictedSwitchPreference(mContext));
-        mController = spy(new RoamingPreferenceController(mContext, "roaming"));
-        mController.init(mFragmentManager, SUB_ID);
+        mController = spy(
+                new RoamingPreferenceController(mContext, "roaming", mLifecycle, mLifecycleOwner,
+                        SUB_ID));
+        mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
+        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
+        mController.init(mFragmentManager, SUB_ID, mMobileNetworkInfoEntity);
         mPreference.setKey(mController.getPreferenceKey());
     }
 
+    private MobileNetworkInfoEntity setupMobileNetworkInfoEntity(String subId,
+            boolean isDataRoaming) {
+        return new MobileNetworkInfoEntity(subId, false, false, true, false, false, false, false,
+                false, false, false, isDataRoaming);
+    }
+
     @Test
     public void getAvailabilityStatus_validSubId_returnAvailable() {
         assertThat(mController.getAvailabilityStatus()).isEqualTo(
@@ -100,9 +126,11 @@
 
     @Test
     public void getAvailabilityStatus_invalidSubId_returnUnsearchable() {
-        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                mMobileNetworkInfoEntity);
 
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+        assertThat(mController.getAvailabilityStatus(
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(
                 BasePreferenceController.AVAILABLE_UNSEARCHABLE);
     }
 
@@ -111,14 +139,16 @@
         final PersistableBundle bundle = new PersistableBundle();
         bundle.putBoolean(CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
-        doReturn(false).when(mTelephonyManager).isDataRoamingEnabled();
+        mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
+        mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
 
         assertThat(mController.isDialogNeeded()).isTrue();
     }
 
     @Test
     public void isDialogNeeded_roamingEnabled_returnFalse() {
-        doReturn(true).when(mTelephonyManager).isDataRoamingEnabled();
+        mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
+        mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
 
         assertThat(mController.isDialogNeeded()).isFalse();
     }
@@ -126,10 +156,10 @@
     @Test
     @UiThreadTest
     public void setChecked_needDialog_showDialog() {
-        doReturn(false).when(mTelephonyManager).isDataRoamingEnabled();
+        mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
+        mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
         doReturn(null).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
 
-
         mController.setChecked(true);
 
         verify(mFragmentManager).beginTransaction();
@@ -137,7 +167,11 @@
 
     @Test
     public void updateState_invalidSubId_disabled() {
-        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(
+                String.valueOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID), false);
+        mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
+        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                mMobileNetworkInfoEntity);
 
         mController.updateState(mPreference);
 
@@ -146,7 +180,8 @@
 
     @Test
     public void updateState_validSubId_enabled() {
-        doReturn(true).when(mTelephonyManager).isDataRoamingEnabled();
+        mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
+        mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
 
         mController.updateState(mPreference);
 
@@ -191,7 +226,7 @@
     @Test
     public void getAvailabilityStatus_forceHomeNetworkIsTrue_shouldReturnConditionallyAvailable() {
         final PersistableBundle bundle = new PersistableBundle();
-        bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, false);
+        bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, true);
         doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
 
         assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);