Snap for 7814173 from 4471035b62809f3e9d61f1216c86cd5c94aa379b to mainline-resolv-release

Change-Id: Iac681de54fbb3d98bbcd966140e097d176af3ec6
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index a6fee58..6c9cf20 100644
--- a/PermissionController/AndroidManifest.xml
+++ b/PermissionController/AndroidManifest.xml
@@ -46,6 +46,7 @@
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+    <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
     <!-- TODO(b/170896938): make this privileged(signature may only work on pixel) -->
     <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
     <uses-permission android:name="android.permission.START_VIEW_PERMISSION_USAGE" />
diff --git a/PermissionController/res/drawable/ic_camera_blocked.xml b/PermissionController/res/drawable/ic_camera_blocked.xml
new file mode 100644
index 0000000..775974e
--- /dev/null
+++ b/PermissionController/res/drawable/ic_camera_blocked.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M18,10.48V6c0,-1.1 -0.9,-2 -2,-2H6.83l2,2H16v7.17l2,2v-1.65l4,3.98v-11l-4,3.98zM16,16L6,6 4,4 2.81,2.81 1.39,4.22l0.85,0.85C2.09,5.35 2,5.66 2,6v12c0,1.1 0.9,2 2,2h12c0.34,0 0.65,-0.09 0.93,-0.24l2.85,2.85 1.41,-1.41L18,18l-2,-2zM4,18V6.83L15.17,18H4z"/>
+</vector>
diff --git a/PermissionController/res/drawable/ic_location_blocked.xml b/PermissionController/res/drawable/ic_location_blocked.xml
new file mode 100644
index 0000000..cdfc853
--- /dev/null
+++ b/PermissionController/res/drawable/ic_location_blocked.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21.19,21.19l-4.92,-4.92 -1.45,-1.45 -7.51,-7.51 -1.53,-1.53 -2.97,-2.97 -1.42,1.41 3.7,3.7C5.04,8.27 5,8.63 5,9c0,5.25 7,13 7,13s1.52,-1.69 3.15,-4.02l4.63,4.63 1.41,-1.42zM12,18.88c-1.87,-2.39 -4.41,-6.15 -4.91,-8.95l6.62,6.62c-0.58,0.84 -1.17,1.64 -1.71,2.33zM12,4c2.76,0 5,2.24 5,5 0,1.16 -0.48,2.56 -1.18,3.99l1.48,1.48C18.28,12.62 19,10.68 19,9c0,-3.87 -3.13,-7 -7,-7 -1.98,0 -3.76,0.82 -5.03,2.14l1.42,1.42C9.3,4.6 10.58,4 12,4zM10.15,7.33l3.52,3.52c0.5,-0.46 0.83,-1.11 0.83,-1.85 0,-1.38 -1.12,-2.5 -2.5,-2.5 -0.73,0 -1.39,0.32 -1.85,0.83z"/>
+</vector>
\ No newline at end of file
diff --git a/PermissionController/res/drawable/ic_mic_blocked.xml b/PermissionController/res/drawable/ic_mic_blocked.xml
new file mode 100644
index 0000000..21fc7aa
--- /dev/null
+++ b/PermissionController/res/drawable/ic_mic_blocked.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path android:fillColor="@android:color/white"
+          android:pathData="M11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5.17l1.82,1.82c0.11,-0.31 0.18,-0.64 0.18,-0.99V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v1.17l2,2V5zM2.81,2.81L1.39,4.22l11.65,11.65c-0.33,0.08 -0.68,0.13 -1.04,0.13 -2.76,0 -5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c0.57,-0.08 1.12,-0.24 1.64,-0.46l5.14,5.14 1.41,-1.41L2.81,2.81zM19,11h-2c0,0.91 -0.26,1.75 -0.69,2.48l1.46,1.46C18.54,13.82 19,12.47 19,11z"/>
+</vector>
diff --git a/PermissionController/res/layout/warning_banner_preference_card.xml b/PermissionController/res/layout/warning_banner_preference_card.xml
new file mode 100644
index 0000000..af533ba
--- /dev/null
+++ b/PermissionController/res/layout/warning_banner_preference_card.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              style="@style/WarningBannerMainContainer" >
+
+    <androidx.cardview.widget.CardView
+        style="@style/WarningBannerCardView" >
+
+        <RelativeLayout
+            style="@style/WarningBannerDimensions" >
+
+            <androidx.preference.internal.PreferenceImageView
+                android:id="@android:id/icon"
+                style="@style/WarningBannerIcon" />
+
+            <TextView android:id="@android:id/title"
+                      android:layout_below="@android:id/icon"
+                      style="@style/WarningBannerTitle" />
+
+            <TextView android:id="@android:id/summary"
+                      android:layout_below="@android:id/title"
+                      android:layout_alignStart="@android:id/title"
+                      style="@style/WarningBannerSummary" />
+
+            <Button
+                android:id="@+id/button_id"
+                android:layout_below="@android:id/summary"
+                style="@style/WarningBannerButton" />
+
+        </RelativeLayout>
+
+    </androidx.cardview.widget.CardView>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@android:id/widget_frame"
+                  style="@style/WarningBannerWidgetFrame" />
+
+</LinearLayout>
diff --git a/PermissionController/res/values-es-rUS/strings.xml b/PermissionController/res/values-es-rUS/strings.xml
index 0525dcc..e895158 100644
--- a/PermissionController/res/values-es-rUS/strings.xml
+++ b/PermissionController/res/values-es-rUS/strings.xml
@@ -345,7 +345,7 @@
     <string name="no_apps_allowed" msgid="7718822655254468631">"No se le otorgó permiso a ninguna app"</string>
     <string name="no_apps_allowed_full" msgid="8011716991498934104">"Ninguna app tiene el permiso para todos los archivos"</string>
     <string name="no_apps_allowed_scoped" msgid="4908850477787659501">"Ninguna app tiene el permiso solo para contenido multimedia"</string>
-    <string name="no_apps_denied" msgid="7663435886986784743">"No se le rechazó el permiso a ninguna app"</string>
+    <string name="no_apps_denied" msgid="7663435886986784743">"No hay permisos rechazados"</string>
     <string name="car_permission_selected" msgid="180837028920791596">"Seleccionado"</string>
     <string name="settings" msgid="5409109923158713323">"Configuración"</string>
     <string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"<xliff:g id="SERVICE_NAME">%s</xliff:g> tiene acceso completo a tu dispositivo"</string>
diff --git a/PermissionController/res/values-es/strings.xml b/PermissionController/res/values-es/strings.xml
index 838be63..8fb0991 100644
--- a/PermissionController/res/values-es/strings.xml
+++ b/PermissionController/res/values-es/strings.xml
@@ -218,7 +218,7 @@
     <string name="app_permission_footer_app_permissions_link" msgid="4926890342636587393">"Ver todos los permisos de <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="app_permission_footer_permission_apps_link" msgid="3941988129992794327">"Ver todas las aplicaciones con este permiso"</string>
     <string name="assistant_mic_label" msgid="1011432357152323896">"Mostrar el uso del micrófono del Asistente"</string>
-    <string name="auto_revoke_label" msgid="5068393642936571656">"Quitar permisos si la aplicación no se utiliza"</string>
+    <string name="auto_revoke_label" msgid="5068393642936571656">"Quitar permisos si la aplicación no se usa"</string>
     <string name="unused_apps_label" msgid="2595428768404901064">"Quitar permisos y liberar espacio"</string>
     <string name="auto_revoke_summary" msgid="5867548789805911683">"Para proteger tus datos, se quitarán los permisos de esta aplicación si no la usas durante unos meses."</string>
     <string name="auto_revoke_summary_with_permissions" msgid="389712086597285013">"Para proteger tus datos, si la aplicación no se ha utilizado durante unos meses, se quitarán los siguientes permisos: <xliff:g id="PERMS">%1$s</xliff:g>"</string>
diff --git a/PermissionController/res/values-ja/strings.xml b/PermissionController/res/values-ja/strings.xml
index c6372d0..e1ec61a 100644
--- a/PermissionController/res/values-ja/strings.xml
+++ b/PermissionController/res/values-ja/strings.xml
@@ -54,7 +54,7 @@
     <string name="no_unused_apps" msgid="12809387670415295">"使用されていないアプリなし"</string>
     <string name="app_disable_dlg_positive" msgid="7418444149981904940">"アプリを無効にする"</string>
     <string name="app_disable_dlg_text" msgid="3126943217146120240">"このアプリを無効にすると、Android などの他のアプリが正しく動作しなくなるおそれがあります。このアプリはデバイスにプリインストールされているため、削除できません。無効にするには、このアプリをオフにし、デバイスにアプリが表示されないようにします。"</string>
-    <string name="app_permission_manager" msgid="3903811137630909550">"権限マネージャ"</string>
+    <string name="app_permission_manager" msgid="3903811137630909550">"権限マネージャー"</string>
     <string name="never_ask_again" msgid="4728762438198560329">"今後表示しない"</string>
     <string name="no_permissions" msgid="3881676756371148563">"権限がありません"</string>
     <string name="additional_permissions" msgid="5801285469338873430">"その他の権限"</string>
diff --git a/PermissionController/res/values-night-v31/colors.xml b/PermissionController/res/values-night-v31/colors.xml
new file mode 100644
index 0000000..e5e4518
--- /dev/null
+++ b/PermissionController/res/values-night-v31/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <color name="warning_surface">#333124</color>
+    <color name="warning_onsurface">#FDD663</color>
+</resources>
\ No newline at end of file
diff --git a/PermissionController/res/values-v31/colors.xml b/PermissionController/res/values-v31/colors.xml
new file mode 100644
index 0000000..1e4d8c1
--- /dev/null
+++ b/PermissionController/res/values-v31/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<resources>
+    <color name="warning_surface">#F0E3A8</color>
+    <color name="warning_onsurface">#895900</color>
+</resources>
\ No newline at end of file
diff --git a/PermissionController/res/values-zh-rTW/strings.xml b/PermissionController/res/values-zh-rTW/strings.xml
index 8b0fea6..6a3a9ec 100644
--- a/PermissionController/res/values-zh-rTW/strings.xml
+++ b/PermissionController/res/values-zh-rTW/strings.xml
@@ -342,10 +342,10 @@
     <string name="app_perms_content_provider_all_files" msgid="3315281519230304799">"上次存取時間:過去 24 小時內 • 所有檔案"</string>
     <string name="no_permissions_allowed" msgid="6081976856354669209">"未授予任何權限"</string>
     <string name="no_permissions_denied" msgid="8159923922804043282">"未拒絕授予任何權限"</string>
-    <string name="no_apps_allowed" msgid="7718822655254468631">"未授權給任何應用程式"</string>
+    <string name="no_apps_allowed" msgid="7718822655254468631">"未允許任何應用程式"</string>
     <string name="no_apps_allowed_full" msgid="8011716991498934104">"未授予任何應用程式「允許存取所有檔案」的權限"</string>
     <string name="no_apps_allowed_scoped" msgid="4908850477787659501">"未授予任何應用程式「僅允許存取媒體檔案」的權限"</string>
-    <string name="no_apps_denied" msgid="7663435886986784743">"未拒絕授權給任何應用程式"</string>
+    <string name="no_apps_denied" msgid="7663435886986784743">"未拒絕任何應用程式"</string>
     <string name="car_permission_selected" msgid="180837028920791596">"已選取"</string>
     <string name="settings" msgid="5409109923158713323">"設定"</string>
     <string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"「<xliff:g id="SERVICE_NAME">%s</xliff:g>」可完整存取你的裝置"</string>
diff --git a/PermissionController/res/values/overlayable.xml b/PermissionController/res/values/overlayable.xml
index 47e9cd6..10561a9 100644
--- a/PermissionController/res/values/overlayable.xml
+++ b/PermissionController/res/values/overlayable.xml
@@ -279,6 +279,18 @@
             <item type="bool" name="config_useMaterial3PermissionGrantDialog" />
             <!-- END GENERAL CONFIGS -->
 
+            <!-- START WARNING BANNER PREFERENCE STYLE -->
+            <item type="style" name="WarningBannerMainContainer" />
+            <item type="style" name="WarningBannerCardView" />
+            <item type="style" name="WarningBannerIcon" />
+            <item type="style" name="WarningBannerDimensions" />
+            <item type="style" name="WarningBannerText" />
+            <item type="style" name="WarningBannerTitle" />
+            <item type="style" name="WarningBannerSummary" />
+            <item type="style" name="WarningBannerButton" />
+            <item type="style" name="WarningBannerWidgetFrame" />
+            <!-- END WARNING BANNER PREFERENCE STYLE -->
+
         </policy>
 
     </overlayable>
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index a365070..4fd9c64 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -1342,4 +1342,15 @@
     <!-- Info label for permissions for apps holding special exempted roles. [CHAR LIMIT=none] -->
     <string name="exempt_info_label"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is protected by Android. Because your data is processed on this device, this app’s permission usage isn’t shown on your privacy dashboard. </string>
 
+    <!-- Info label for the warning banner title if sensor is blocked [CHAR LIMIT=none] -->
+    <string name="blocked_sensor_title">Device <xliff:g id="sensor_name" example="camera">%1$s</xliff:g> is blocked</string>
+    <!-- Info label for the warning banner title if location is off [CHAR LIMIT=none] -->
+    <string name="blocked_location_title">Device <xliff:g id="sensor_name" example="location">%1$s</xliff:g> is off</string>
+    <!-- Info label to display that the sensor is blocked for apps and services [CHAR LIMIT=none] -->
+    <string name="blocked_sensor_summary">For apps and services</string>
+    <!-- Info label to display that the mic is blocked for apps and services [CHAR LIMIT=none] -->
+    <string name="blocked_mic_summary">Microphone data may still be shared when you call an emergency number.</string>
+    <!-- Label for the button to change the sensor status  [CHAR LIMIT=none] -->
+    <string name="blocked_sensor_button_label">Change</string>
+
 </resources>
diff --git a/PermissionController/res/values/styles.xml b/PermissionController/res/values/styles.xml
index 4478b01..e21557d 100644
--- a/PermissionController/res/values/styles.xml
+++ b/PermissionController/res/values/styles.xml
@@ -1094,4 +1094,83 @@
 
     <!-- END PRIVACY DASHBOARD -->
 
+    <!-- START WARNING BANNER -->
+
+    <style name="WarningBannerMainContainer">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:clipToPadding">false</item>
+        <item name="android:focusable">true</item>
+        <item name="android:gravity">center_vertical</item>
+        <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+        <item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
+        <item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
+    </style>
+
+    <style name="WarningBannerCardView"
+           xmlns:card_view="http://schemas.android.com/apk/res-auto"
+           xmlns:app="http://schemas.android.com/apk/res-auto" >
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="app:cardCornerRadius">20dp</item>
+        <item name="app:cardBackgroundColor">@color/warning_surface</item>
+        <item name="app:cardElevation">0dp</item>
+        <item name="card_view:contentPaddingBottom">8dp</item>
+        <item name="card_view:contentPaddingTop">20dp</item>
+        <item name="card_view:contentPaddingLeft">20dp</item>
+        <item name="card_view:contentPaddingRight">20dp</item>
+    </style>
+
+    <style name="WarningBannerIcon" parent="@style/ImageViewIcon">
+        <item name="android:layout_marginBottom">8dp</item>
+        <item name="android:tint">@color/warning_onsurface</item>
+    </style>
+
+    <style name="WarningBannerDimensions">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="WarningBannerText">
+        <item name="android:layout_marginBottom">8dp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="WarningBannerTitle" parent="@style/WarningBannerText">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textSize">20sp</item>
+        <item name="android:lineHeight">24sp</item>
+    </style>
+
+    <style name="WarningBannerSummary" parent="@style/WarningBannerText">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:lineHeight">20sp</item>
+    </style>
+
+    <style name="WarningBannerButton">
+        <item name="android:layout_height">36dp</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_alignParentBottom">true</item>
+        <item name="android:layout_alignParentEnd">true</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:lineHeight">20sp</item>
+        <item name="android:layout_marginBottom">8dp</item>
+        <item name="android:textColor">@color/warning_onsurface</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+    </style>
+
+    <style name="WarningBannerWidgetFrame">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:gravity">end|center_vertical</item>
+        <item name="android:paddingStart">16dp</item>
+        <item name="android:orientation">vertical</item>
+    </style>
+
+    <!-- END WARNING BANNER -->
+
 </resources>
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
index b96efef..8eff99b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
@@ -351,6 +351,11 @@
             // We are animating the top view, need to compensate for that in motion events.
             ev.setLocation(ev.getX(), ev.getY() - rootView.getTop());
         }
+        final int x = (int) ev.getX();
+        final int y = (int) ev.getY();
+        if ((x < 0) || (y < 0) || (x > (rootView.getWidth())) || (y > (rootView.getHeight()))) {
+            finishAfterTransition();
+        }
         return super.dispatchTouchEvent(ev);
     }
 
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
new file mode 100644
index 0000000..bb63cdd
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.permissioncontroller.permission.ui.handheld;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.permissioncontroller.R;
+
+
+/**
+ * A Preference representing a banner message represented as a CardView
+ */
+public class CardViewPreference extends Preference {
+
+    private String mAction;
+
+    public CardViewPreference(Context context, String action) {
+        super(context);
+        this.setLayoutResource(R.layout.warning_banner_preference_card);
+        mAction = action;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        Button button = (Button) holder.findViewById(R.id.button_id);
+        button.setText(R.string.blocked_sensor_button_label);
+        button.setVisibility(View.VISIBLE);
+        button.setOnClickListener(v -> {
+            getContext().startActivity(new Intent(mAction));
+        });
+    }
+
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
index 4491557..78fe098 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
@@ -45,6 +45,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Menu;
@@ -77,6 +78,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Random;
 
@@ -97,6 +99,7 @@
     private static final String LOG_TAG = "PermissionAppsFragment";
     private static final String STORAGE_ALLOWED_FULL = "allowed_storage_full";
     private static final String STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped";
+    private static final String BLOCKED_SENSOR_PREF_KEY = "sensor_card";
     private static final int SHOW_LOAD_DELAY_MS = 200;
     private static final int AGGREGATE_DATA_FILTER_BEGIN_DAYS = 1;
 
@@ -123,6 +126,7 @@
     private PermissionAppsViewModel mViewModel;
     private PermissionUsages mPermissionUsages;
     private List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
+    private Boolean mSensorStatus;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -173,6 +177,10 @@
             mPermissionUsages.load(null, null, filterTimeBeginMillis, Long.MAX_VALUE,
                     PermissionUsages.USAGE_FLAG_LAST, getActivity().getLoaderManager(),
                     false, false, this, false);
+
+            if (Utils.shouldDisplayCardIfBlocked(mPermGroupName)) {
+                mViewModel.getSensorStatusLiveData().observe(this, this::setSensorStatus);
+            }
         }
     }
 
@@ -243,6 +251,62 @@
         }
     }
 
+
+    private void setSensorStatus(Boolean sensorStatus) {
+        mSensorStatus = sensorStatus;
+        displaySensorCard();
+    }
+
+    private void displaySensorCard() {
+        if (Utils.shouldDisplayCardIfBlocked(mPermGroupName)) {
+            if (mSensorStatus) {
+                setSensorCard();
+            } else {
+                removeSensorCard();
+            }
+        }
+    }
+
+
+    private void setSensorCard() {
+        CardViewPreference sensorCard = findPreference(BLOCKED_SENSOR_PREF_KEY);
+        if (sensorCard == null) {
+            sensorCard = createSensorCard();
+            getPreferenceScreen().addPreference(sensorCard);
+        }
+        sensorCard.setVisible(true);
+    }
+
+    private CardViewPreference createSensorCard() {
+        String label = KotlinUtils.INSTANCE.getPermGroupLabel(getPreferenceManager().getContext(),
+                mPermGroupName).toString().toLowerCase(
+                Locale.ROOT);
+        boolean isLocation = Manifest.permission_group.LOCATION.equals(mPermGroupName);
+        Context context = getPreferenceManager().getContext();
+        String action = isLocation ? Settings.ACTION_LOCATION_SOURCE_SETTINGS
+                : Settings.ACTION_PRIVACY_SETTINGS;
+        CardViewPreference sensorCard = new CardViewPreference(context, action);
+        sensorCard.setKey(BLOCKED_SENSOR_PREF_KEY);
+        sensorCard.setIcon(Utils.getBlockedIcon(mPermGroupName));
+        int cardTitle =
+                isLocation ? R.string.blocked_location_title : R.string.blocked_sensor_title;
+        sensorCard.setTitle(context.getString(cardTitle, label));
+        boolean isMicrophone = Manifest.permission_group.MICROPHONE.equals(mPermGroupName);
+        int cardSummary =
+                isMicrophone ? R.string.blocked_mic_summary : R.string.blocked_sensor_summary;
+        sensorCard.setSummary(context.getString(cardSummary));
+        sensorCard.setVisible(true);
+        sensorCard.setOrder(-1);
+        return sensorCard;
+    }
+
+    private void removeSensorCard() {
+        CardViewPreference sensorCard = findPreference(BLOCKED_SENSOR_PREF_KEY);
+        if (sensorCard != null) {
+            sensorCard.setVisible(false);
+        }
+    }
+
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
@@ -285,8 +349,11 @@
         Map<String, Preference> existingPrefs = new ArrayMap<>();
 
         for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
-            PreferenceCategory category = (PreferenceCategory)
-                    getPreferenceScreen().getPreference(i);
+            Preference pref = getPreferenceScreen().getPreference(i);
+            if (BLOCKED_SENSOR_PREF_KEY.equals(pref.getKey())) {
+                continue;
+            }
+            PreferenceCategory category = (PreferenceCategory) pref;
             category.setOrderingAsAdded(true);
             int numPreferences = category.getPreferenceCount();
             for (int j = 0; j < numPreferences; j++) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
index c7a13db..ed97375 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
@@ -17,10 +17,14 @@
 package com.android.permissioncontroller.permission.ui.model
 
 import android.Manifest
+import android.Manifest.permission_group.LOCATION
 import android.app.Application
 import android.content.Intent
+import android.hardware.SensorPrivacyManager
+import android.os.Build
 import android.os.Bundle
 import android.os.UserHandle
+import androidx.annotation.RequiresApi
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.AbstractSavedStateViewModelFactory
 import androidx.lifecycle.MediatorLiveData
@@ -33,6 +37,7 @@
 import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData
 import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState
 import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
+import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
 import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState
 import com.android.permissioncontroller.permission.ui.Category
 import com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog
@@ -41,6 +46,7 @@
 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOULD_SHOW_SYSTEM_KEY
 import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOW_ALWAYS_ALLOWED
 import com.android.permissioncontroller.permission.utils.LocationUtils
+import com.android.permissioncontroller.permission.utils.Utils
 import com.android.permissioncontroller.permission.utils.navigateSafe
 
 /**
@@ -70,6 +76,11 @@
     val showAllowAlwaysStringLiveData = state.getLiveData(SHOW_ALWAYS_ALLOWED, false)
     val categorizedAppsLiveData = CategorizedAppsLiveData(groupName)
 
+    @RequiresApi(Build.VERSION_CODES.S)
+    fun getSensorStatusLiveData(): SensorStatusLiveData {
+        return SensorStatusLiveData()
+    }
+
     fun updateShowSystem(showSystem: Boolean) {
         if (showSystem != state.get(SHOULD_SHOW_SYSTEM_KEY)) {
             state.set(SHOULD_SHOW_SYSTEM_KEY, showSystem)
@@ -80,6 +91,68 @@
         get() = state.get(CREATION_LOGGED_KEY) ?: false
         set(value) = state.set(CREATION_LOGGED_KEY, value)
 
+    /**
+     * A LiveData that tracks the status (blocked or available) of a sensor
+     *
+     * @param permGroupName Permission group name for the sensor
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    inner class SensorStatusLiveData() : SmartUpdateMediatorLiveData<Boolean>() {
+        val sensorPrivacyManager = app.getSystemService(SensorPrivacyManager::class.java)!!
+        val sensor = Utils.getSensorCode(groupName)
+        val isLocation = LOCATION.equals(groupName)
+
+        init {
+            checkAndUpdateStatus()
+        }
+
+        fun checkAndUpdateStatus() {
+            var blocked: Boolean
+
+            if (isLocation) {
+                val userContext = Utils.getUserContext(app, android.os.Process.myUserHandle())
+                blocked = !LocationUtils.isLocationEnabled(userContext)
+            } else {
+                blocked = sensorPrivacyManager.isSensorPrivacyEnabled(sensor)
+            }
+
+            if (blocked) {
+                value = blocked
+            }
+        }
+
+        override fun onActive() {
+            super.onActive()
+            checkAndUpdateStatus()
+            if (isLocation) {
+                LocationUtils.addLocationListener(locListener)
+            } else {
+                sensorPrivacyManager.addSensorPrivacyListener(sensor, listener)
+            }
+        }
+
+        override fun onInactive() {
+            super.onInactive()
+            if (isLocation) {
+                LocationUtils.removeLocationListener(locListener)
+            } else {
+                sensorPrivacyManager.removeSensorPrivacyListener(sensor, listener)
+            }
+        }
+
+        private val listener = { sensor: Int, status: Boolean ->
+            value = status
+        }
+
+        private val locListener = { status: Boolean ->
+            value = !status
+        }
+
+        override fun onUpdate() {
+            // Do nothing
+        }
+    }
+
     inner class CategorizedAppsLiveData(groupName: String)
         : MediatorLiveData<@kotlin.jvm.JvmSuppressWildcards
     Map<Category, List<Pair<String, UserHandle>>>>() {
@@ -265,4 +338,4 @@
         @Suppress("UNCHECKED_CAST")
         return PermissionAppsViewModel(state, app, groupName) as T
     }
-}
\ No newline at end of file
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index e87407f..c7f7182 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
@@ -64,6 +64,7 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.hardware.SensorPrivacyManager;
 import android.os.Build;
 import android.os.Parcelable;
 import android.os.Process;
@@ -84,6 +85,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.StringRes;
 import androidx.core.text.BidiFormatter;
 import androidx.core.util.Preconditions;
@@ -192,6 +194,11 @@
     private static final ArrayMap<String, Integer> PERM_GROUP_UPGRADE_REQUEST_RES;
     private static final ArrayMap<String, Integer> PERM_GROUP_UPGRADE_REQUEST_DETAIL_RES;
 
+    /** Permission -> Sensor codes */
+    private static final ArrayMap<String, Integer> PERM_SENSOR_CODES;
+    /** Permission -> Icon res id */
+    private static final ArrayMap<String, Integer> PERM_BLOCKED_ICON;
+
     public static final int FLAGS_ALWAYS_USER_SENSITIVE =
             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
                     | FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
@@ -350,6 +357,17 @@
                 .put(MICROPHONE, R.string.permgroupupgraderequestdetail_microphone);
         PERM_GROUP_UPGRADE_REQUEST_DETAIL_RES
                 .put(CAMERA, R.string.permgroupupgraderequestdetail_camera);
+
+        PERM_SENSOR_CODES = new ArrayMap<>();
+        if (SdkLevel.isAtLeastS()) {
+            PERM_SENSOR_CODES.put(CAMERA, SensorPrivacyManager.Sensors.CAMERA);
+            PERM_SENSOR_CODES.put(MICROPHONE, SensorPrivacyManager.Sensors.MICROPHONE);
+        }
+
+        PERM_BLOCKED_ICON = new ArrayMap<>();
+        PERM_BLOCKED_ICON.put(CAMERA, R.drawable.ic_camera_blocked);
+        PERM_BLOCKED_ICON.put(MICROPHONE, R.drawable.ic_mic_blocked);
+        PERM_BLOCKED_ICON.put(LOCATION, R.drawable.ic_location_blocked);
     }
 
     private Utils() {
@@ -1235,4 +1253,27 @@
     public static boolean isStatusBarIndicatorPermission(@NonNull String permissionGroupName) {
         return CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName);
     }
+
+    /**
+     * Returns if a card should be shown if the sensor is blocked
+     **/
+    public static boolean shouldDisplayCardIfBlocked(@NonNull String permissionGroupName) {
+        return CAMERA.equals(permissionGroupName) || MICROPHONE.equals(permissionGroupName)
+                || LOCATION.equals(permissionGroupName);
+    }
+
+    /**
+     * Returns the sensor code for a permission
+     **/
+    @RequiresApi(Build.VERSION_CODES.S)
+    public static int getSensorCode(@NonNull String permissionGroupName) {
+        return PERM_SENSOR_CODES.getOrDefault(permissionGroupName, -1);
+    }
+
+    /**
+     * Returns the blocked icon code for a permission
+     **/
+    public static int getBlockedIcon(@NonNull String permissionGroupName) {
+        return PERM_BLOCKED_ICON.getOrDefault(permissionGroupName, -1);
+    }
 }