summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Olekar <olekarg@google.com>2021-09-17 16:02:23 +0000
committerGanesh Olekar <olekarg@google.com>2022-02-03 17:44:13 +0000
commitd209f63b29715e3e1d47f10dbeb2d98e67344817 (patch)
treee2c5b84b91ab71c8ba2945a271c61484dd556bf8
parent6d24f7f84f7296e9cd2391de01adf2870b2e59bc (diff)
downloadPermission-d209f63b29715e3e1d47f10dbeb2d98e67344817.tar.gz
Add warning banners to the permission pages if the sensor is blocked
Test: Added tests to check warning banners are displayed when sensors are blocked Test: atest SensorBlockedBannerTest -c Bug: 197757242 Change-Id: I96b72c72c09dba1428ac0c5b6f83b741713577e4 Merged-In: Iaca65d1e98965723d4461b2972917fc508f2e085 Merged-In: Ic770e4a56df7a6afce7b4ebe809979d6d177807d Merged-In: If695ac98448999838bc34f0bb9c703e15ee15475 Merged-In: Ic81b7a14a3bcfa0379891cd46c4bf05c0ad986b2 Merged-In: I5664b7895cd307088c66c078c9ef57bbb2f9a5ca Merged-In: Ifdd99cbc9385f43d162fc2a1102c32fb0ccd1644 Merged-in: Iba3f9d776a166e4ab119c765596dbd51af26a869
-rw-r--r--PermissionController/AndroidManifest.xml1
-rw-r--r--PermissionController/res/drawable/ic_camera_blocked.xml25
-rw-r--r--PermissionController/res/drawable/ic_location_blocked.xml26
-rw-r--r--PermissionController/res/drawable/ic_mic_blocked.xml25
-rw-r--r--PermissionController/res/layout/app_permission.xml1
-rw-r--r--PermissionController/res/layout/warning_banner_preference_card.xml53
-rw-r--r--PermissionController/res/values-night-v31/colors.xml20
-rw-r--r--PermissionController/res/values-v31/colors.xml20
-rw-r--r--PermissionController/res/values/overlayable.xml12
-rw-r--r--PermissionController/res/values/strings.xml13
-rw-r--r--PermissionController/res/values/styles.xml83
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java55
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java68
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt73
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java61
15 files changed, 532 insertions, 4 deletions
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index a6fee5833..6c9cf207c 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 000000000..775974e48
--- /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 000000000..cdfc85336
--- /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 000000000..21fc7aa8b
--- /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 222dcf8b7..48de3864d 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 000000000..611d24b82
--- /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 000000000..e5e451870
--- /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 000000000..1e4d8c1c8
--- /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 47e9cd615..10561a933 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 a3650709a..cdaa61c07 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -1342,4 +1342,17 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo
<!-- 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 4478b01a1..a7424bfbc 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 000000000..6c76d906b
--- /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 4491557d3..50c64df02 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.Bundle;
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 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
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 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
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 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
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 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
}
}
+ @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 @@ public final class PermissionAppsFragment extends SettingsWithLargeHeader implem
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 c7a13dbab..46b0d2cfb 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.AllPackageInfosLiveData
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.PermissionAppsViewMo
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 @@ class PermissionAppsViewModel(
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 @@ class PermissionAppsViewModel(
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 @@ class PermissionAppsViewModelFactory(
@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 155ab5ab9..74328747e 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.content.res.Resources.Theme;
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 android.view.MenuItem;
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 @@ public final class Utils {
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 @@ public final class Utils {
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 @@ public final class Utils {
.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 @@ public final class Utils {
|| 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);
+ }
}