Show privacy icons in status bar
Adds PrivacyItemController to PhoneStatusBarPolicy so that we can show
microphone and camera privacy icons in the status bar.
Test: open camera to show the camera icon
Test: open a recording app to show microphone
Bug: 112331475
Change-Id: Ia14f838d715a2808db595c9da3be236d36cc6589
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6ae183b..d892ad2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -55,6 +55,8 @@
<item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_microphone</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_camera</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
</string-array>
@@ -87,6 +89,8 @@
<string translatable="false" name="status_bar_mobile">mobile</string>
<string translatable="false" name="status_bar_vpn">vpn</string>
<string translatable="false" name="status_bar_ethernet">ethernet</string>
+ <string translatable="false" name="status_bar_microphone">microphone</string>
+ <string translatable="false" name="status_bar_camera">camera</string>
<string translatable="false" name="status_bar_airplane">airplane</string>
<!-- Flag indicating whether the surface flinger has limited
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6276884..0862f3a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2808,6 +2808,8 @@
<java-symbol type="string" name="status_bar_mobile" />
<java-symbol type="string" name="status_bar_ethernet" />
<java-symbol type="string" name="status_bar_vpn" />
+ <java-symbol type="string" name="status_bar_microphone" />
+ <java-symbol type="string" name="status_bar_camera" />
<!-- Locale picker -->
<java-symbol type="id" name="locale_search_menu" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_camera.xml b/packages/SystemUI/res/drawable/stat_sys_camera.xml
new file mode 100644
index 0000000..eb3e963
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_camera.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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.
+*/
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="3dp"
+ android:insetRight="3dp">
+ <vector
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M20,5h-3.17L15,3H9L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM20,19H4V7h16V19zM12,9c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C16,10.79 14.21,9 12,9z"/>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_mic_none.xml b/packages/SystemUI/res/drawable/stat_sys_mic_none.xml
new file mode 100644
index 0000000..d6bdf9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_mic_none.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2018, 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="18dp"
+ android:height="18dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
+</vector>
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index f409902..3d9aa0f 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -23,9 +23,9 @@
typealias Privacy = PrivacyType
enum class PrivacyType(val nameId: Int, val iconId: Int) {
- TYPE_CAMERA(R.string.privacy_type_camera, com.android.internal.R.drawable.ic_camera),
+ TYPE_CAMERA(R.string.privacy_type_camera, R.drawable.stat_sys_camera),
TYPE_LOCATION(R.string.privacy_type_location, R.drawable.stat_sys_location),
- TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.ic_mic_26dp);
+ TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.stat_sys_mic_none);
fun getName(context: Context) = context.resources.getString(nameId)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 0e6efc8..c84f3db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -66,6 +66,8 @@
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.UiOffloadThread;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -101,7 +103,8 @@
*/
public class PhoneStatusBarPolicy implements Callback, Callbacks,
RotationLockControllerCallback, Listener, LocationChangeCallback,
- ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback {
+ ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback,
+ PrivacyItemController.Callback {
private static final String TAG = "PhoneStatusBarPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -120,6 +123,8 @@
private final String mSlotHeadset;
private final String mSlotDataSaver;
private final String mSlotLocation;
+ private final String mSlotMicrophone;
+ private final String mSlotCamera;
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -136,6 +141,7 @@
private final DeviceProvisionedController mProvisionedController;
private final KeyguardMonitor mKeyguardMonitor;
private final LocationController mLocationController;
+ private final PrivacyItemController mPrivacyItemController;
private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
@@ -169,6 +175,7 @@
mProvisionedController = Dependency.get(DeviceProvisionedController.class);
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mLocationController = Dependency.get(LocationController.class);
+ mPrivacyItemController = new PrivacyItemController(mContext, this);
mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -183,6 +190,8 @@
mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);
mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);
mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);
+ mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone);
+ mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera);
// listen for broadcasts
IntentFilter filter = new IntentFilter();
@@ -241,6 +250,12 @@
context.getString(R.string.accessibility_data_saver_on));
mIconController.setIconVisibility(mSlotDataSaver, false);
+ // privacy items
+ mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null);
+ mIconController.setIconVisibility(mSlotMicrophone, false);
+ mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null);
+ mIconController.setIconVisibility(mSlotCamera, false);
+
mRotationLockController.addCallback(this);
mBluetooth.addCallback(this);
mProvisionedController.addCallback(this);
@@ -251,6 +266,7 @@
mDataSaver.addCallback(this);
mKeyguardMonitor.addCallback(this);
mLocationController.addCallback(this);
+ mPrivacyItemController.setListening(true);
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
@@ -279,6 +295,7 @@
mDataSaver.removeCallback(this);
mKeyguardMonitor.removeCallback(this);
mLocationController.removeCallback(this);
+ mPrivacyItemController.setListening(false);
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
mContext.unregisterReceiver(mIntentReceiver);
@@ -798,6 +815,34 @@
mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
}
+ @Override // PrivacyItemController.Callback
+ public void privacyChanged(List<PrivacyItem> privacyItems) {
+ updatePrivacyItems(privacyItems);
+ }
+
+ private void updatePrivacyItems(List<PrivacyItem> items) {
+ boolean showCamera = false;
+ boolean showMicrophone = false;
+ boolean showLocation = false;
+ for (PrivacyItem item : items) {
+ switch (item.getPrivacyType()) {
+ case TYPE_CAMERA:
+ showCamera = true;
+ break;
+ case TYPE_LOCATION:
+ showLocation = true;
+ break;
+ case TYPE_MICROPHONE:
+ showMicrophone = true;
+ break;
+ }
+ }
+
+ mIconController.setIconVisibility(mSlotCamera, showCamera);
+ mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
+ mIconController.setIconVisibility(mSlotLocation, showLocation);
+ }
+
private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
@Override
public void onTaskStackChanged() {