Snap for 8152310 from 923f6c29873fa839162fc830b0070bfbc2d25529 to mainline-media-swcodec-release

Change-Id: I759f1b0b2ce681564cdd861d89dd7a6599cf997c
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/app_permission.xml b/PermissionController/res/layout/app_permission.xml
index 222dcf8..48de386 100644
--- a/PermissionController/res/layout/app_permission.xml
+++ b/PermissionController/res/layout/app_permission.xml
@@ -174,7 +174,6 @@
                     android:src="@drawable/ic_info_outline"
                     android:layout_marginBottom="16dp"
                     android:layout_marginStart="24dp"
-                    android:contentDescription="Info"
                     style="@style/ImageViewIcon" />
 
                 <TextView
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..611d24b
--- /dev/null
+++ b/PermissionController/res/layout/warning_banner_preference_card.xml
@@ -0,0 +1,53 @@
+<?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"
+                android:focusable="true"
+                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-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/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..cdaa61c 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -1342,4 +1342,17 @@
     <!-- 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 camera is blocked [CHAR LIMIT=none] -->
+    <string name="blocked_camera_title">Device camera is blocked</string>
+    <!-- Info label for the warning banner title if microphone is blocked [CHAR LIMIT=none] -->
+    <string name="blocked_microphone_title">Device microphone is blocked</string>
+    <!-- Info label for the warning banner title if location is off [CHAR LIMIT=none] -->
+    <string name="blocked_location_title">Device location 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..a7424bf 100644
--- a/PermissionController/res/values/styles.xml
+++ b/PermissionController/res/values/styles.xml
@@ -1094,4 +1094,87 @@
 
     <!-- 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">
+        <item name="android:layout_width">24dp</item>
+        <item name="android:layout_height">24dp</item>
+        <item name="android:scaleType">fitCenter</item>
+        <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">48dp</item>
+        <item name="android:minWidth">48dp</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/handheld/CardViewPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
new file mode 100644
index 0000000..6c76d90
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
@@ -0,0 +1,55 @@
+/*
+ * 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.setContentDescription(getContext().getString(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..50c64df 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;
@@ -97,6 +98,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 +125,7 @@
     private PermissionAppsViewModel mViewModel;
     private PermissionUsages mPermissionUsages;
     private List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
+    private Boolean mSensorStatus;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -173,6 +176,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 +250,60 @@
         }
     }
 
+    @RequiresApi(Build.VERSION_CODES.S)
+    private void setSensorStatus(Boolean sensorStatus) {
+        mSensorStatus = sensorStatus;
+        displaySensorCard();
+    }
+
+    @RequiresApi(Build.VERSION_CODES.S)
+    private void displaySensorCard() {
+        if (Utils.shouldDisplayCardIfBlocked(mPermGroupName)) {
+            if (mSensorStatus) {
+                setSensorCard();
+            } else {
+                removeSensorCard();
+            }
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.S)
+    private void setSensorCard() {
+        CardViewPreference sensorCard = findPreference(BLOCKED_SENSOR_PREF_KEY);
+        if (sensorCard == null) {
+            sensorCard = createSensorCard();
+            getPreferenceScreen().addPreference(sensorCard);
+        }
+        sensorCard.setVisible(true);
+    }
+
+    @RequiresApi(Build.VERSION_CODES.S)
+    private CardViewPreference createSensorCard() {
+        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));
+        sensorCard.setTitle(Utils.getBlockedTitle(mPermGroupName));
+        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;
+    }
+
+    @RequiresApi(Build.VERSION_CODES.S)
+    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 +346,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..46b0d2c 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
@@ -42,6 +47,7 @@
 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.navigateSafe
+import com.android.permissioncontroller.permission.utils.Utils
 
 /**
  * ViewModel for the PermissionAppsFragment. Has a liveData with all of the UI info for each
@@ -70,6 +76,12 @@
     val showAllowAlwaysStringLiveData = state.getLiveData(SHOW_ALWAYS_ALLOWED, false)
     val categorizedAppsLiveData = CategorizedAppsLiveData(groupName)
 
+    @get:RequiresApi(Build.VERSION_CODES.S)
+    val sensorStatusLiveData: SensorStatusLiveData by lazy(LazyThreadSafetyMode.NONE)
+    @RequiresApi(Build.VERSION_CODES.S) {
+        SensorStatusLiveData()
+    }
+
     fun updateShowSystem(showSystem: Boolean) {
         if (showSystem != state.get(SHOULD_SHOW_SYSTEM_KEY)) {
             state.set(SHOULD_SHOW_SYSTEM_KEY, showSystem)
@@ -80,6 +92,65 @@
         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
+     */
+    @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) {
+                blocked = !LocationUtils.isLocationEnabled(app.getApplicationContext())
+            } 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 +336,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/ui/television/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
index 99d0c7f..8c11153 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
@@ -63,6 +63,7 @@
 import androidx.preference.PreferenceViewHolder;
 
 import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState;
 import com.android.permissioncontroller.permission.model.AppPermissionGroup;
 import com.android.permissioncontroller.permission.model.AppPermissions;
 import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
@@ -184,6 +185,9 @@
                 delayHandler.postDelayed(() -> setRadioButtonsState(buttonState), POST_DELAY_MS);
             }
         });
+        if (mIsStorageGroup) {
+            mViewModel.getFullStorageStateLiveData().observe(this, this::setSpecialStorageState);
+        }
     }
 
     @Override
@@ -252,6 +256,10 @@
         if (mViewModel.getButtonStateLiveData().getValue() != null) {
             setRadioButtonsState(mViewModel.getButtonStateLiveData().getValue());
         }
+        if (mViewModel.getFullStorageStateLiveData().isInitialized() && mIsStorageGroup) {
+            setSpecialStorageState(mViewModel.getFullStorageStateLiveData().getValue());
+        }
+
     }
 
     private void setRadioButtonsState(Map<ButtonType, ButtonState> states) {
@@ -372,6 +380,21 @@
         }
     }
 
+    private void setSpecialStorageState(FullStoragePackageState storageState) {
+        if (mAllowButton == null || !mIsStorageGroup) {
+            return;
+        }
+
+        mAllowAlwaysButton.setTitle(R.string.app_permission_button_allow_all_files);
+        mAllowForegroundButton.setTitle(R.string.app_permission_button_allow_media_only);
+
+
+        if (storageState != null && storageState.isLegacy()) {
+            mAllowButton.setTitle(R.string.app_permission_button_allow_all_files);
+            return;
+        }
+    }
+
     private void setResult(@GrantPermissionsViewHandler.Result int result) {
         Intent intent = new Intent()
                 .putExtra(EXTRA_RESULT_PERMISSION_INTERACTED, mPermGroupName)
@@ -428,6 +451,7 @@
         private static final String KEY = ConfirmDialog.class.getName() + ".arg.key";
         private static final String BUTTON = ConfirmDialog.class.getName() + ".arg.button";
         private static final String ONE_TIME = ConfirmDialog.class.getName() + ".arg.onetime";
+        private static int sCode =  APP_PERMISSION_FRAGMENT_ACTION_REPORTED__BUTTON_PRESSED__ALLOW;
 
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -446,6 +470,8 @@
                             (DialogInterface dialog, int which) -> {
                                 if (isGrantFileAccess) {
                                     fragment.mViewModel.setAllFilesAccess(true);
+                                    fragment.mViewModel.requestChange(false, fragment,
+                                            fragment, ChangeRequest.GRANT_BOTH, sCode);
                                 } else {
                                     fragment.mViewModel.onDenyAnyWay((ChangeRequest)
                                                     getArguments().getSerializable(CHANGE_REQUEST),
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index 155ab5a..7432874 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;
@@ -160,6 +162,9 @@
     private static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED =
             "location_access_check_enabled";
 
+    /** Whether or not warning banner is displayed when device sensors are off **/
+    public static final String PROPERTY_WARNING_BANNER_DISPLAY_ENABLED = "warning_banner_enabled";
+
     /** All permission whitelists. */
     public static final int FLAGS_PERMISSION_WHITELIST_ALL =
             PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
@@ -193,6 +198,13 @@
     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;
+    /** Permission -> Title res id */
+    private static final ArrayMap<String, Integer> PERM_BLOCKED_TITLE;
+
     public static final int FLAGS_ALWAYS_USER_SENSITIVE =
             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
                     | FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
@@ -351,6 +363,23 @@
                 .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);
+
+        PERM_BLOCKED_TITLE = new ArrayMap<>();
+        PERM_BLOCKED_TITLE.put(CAMERA, R.string.blocked_camera_title);
+        PERM_BLOCKED_TITLE.put(MICROPHONE, R.string.blocked_microphone_title);
+        PERM_BLOCKED_TITLE.put(LOCATION, R.string.blocked_location_title);
+
     }
 
     private Utils() {
@@ -1250,4 +1279,36 @@
                 || Manifest.permission_group.CAMERA.equals(groupName)
                 || Manifest.permission_group.MICROPHONE.equals(groupName);
     }
+
+    /**
+     * Returns if a card should be shown if the sensor is blocked
+     **/
+    public static boolean shouldDisplayCardIfBlocked(@NonNull String permissionGroupName) {
+        return DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_WARNING_BANNER_DISPLAY_ENABLED, true) && (
+                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);
+    }
+
+    /**
+     * Returns the blocked title code for a permission
+     **/
+    public static int getBlockedTitle(@NonNull String permissionGroupName) {
+        return PERM_BLOCKED_TITLE.getOrDefault(permissionGroupName, -1);
+    }
 }