Merge "Add Sensors Off QS tile and display status bar icon when active"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7c80a0b..7d66b90 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8587,38 +8587,6 @@
"packages_to_clear_data_before_full_restore";
/**
- * Indicates the location state should be maintained after sensor privacy is disabled.
- * @hide
- */
- public static final String MAINTAIN_LOCATION_AFTER_SP_DISABLED = "0";
-
- /**
- * Indicates location should be reenabled after sensor privacy is disabled.
- * @hide
- */
- public static final String REENABLE_LOCATION_AFTER_SP_DISABLED = "1";
-
- /**
- * Indicates the state of airplane mode should be maintained after sensor privacy is
- * disabled.
- * @hide
- */
- public static final String MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED = "0";
-
- /**
- * Indicates airplane mode should be disabled after sensor privacy is disabled.
- * @hide
- */
- public static final String DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED = "1";
-
- /**
- * The state of all sensors managed by SensorPrivacyService when sensor privacy is enabled.
- * @hide
- */
- public static final String SENSOR_PRIVACY_SENSOR_STATE =
- "sensor_privacy_sensor_state";
-
- /**
* Setting to determine whether to use the new notification priority handling features.
* @hide
*/
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index f037407..25caafb 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -590,6 +590,13 @@
// OS: P
DIALOG_SWITCH_HFP_DEVICES = 1416;
+ // OPEN: QS Sensor Privacy Mode tile shown
+ // ACTION: QS Sensor Privacy Mode tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ QS_SENSOR_PRIVACY = 1598;
+
// ACTION: Tap & Pay -> Default Application Setting -> Use Forground
ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 71e071c..de02286 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -58,6 +58,7 @@
<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_battery</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
</string-array>
<string translatable="false" name="status_bar_rotate">rotate</string>
@@ -92,6 +93,7 @@
<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>
+ <string translatable="false" name="status_bar_sensors_off">sensors_off</string>
<!-- Flag indicating whether the surface flinger has limited
alpha compositing functionality in hardware. If set, the window
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 764c9c4..ba964bb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2924,6 +2924,7 @@
<java-symbol type="string" name="status_bar_vpn" />
<java-symbol type="string" name="status_bar_microphone" />
<java-symbol type="string" name="status_bar_camera" />
+ <java-symbol type="string" name="status_bar_sensors_off" />
<!-- Locale picker -->
<java-symbol type="id" name="locale_search_menu" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6fb4744..85947bd 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -623,7 +623,6 @@
Settings.Secure.DEFAULT_INPUT_METHOD,
Settings.Secure.DEVICE_PAIRED,
Settings.Secure.DIALER_DEFAULT_APPLICATION,
- Settings.Secure.DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED,
Settings.Secure.DISABLED_PRINT_SERVICES,
Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
Settings.Secure.DISPLAY_DENSITY_FORCED,
@@ -647,8 +646,6 @@
Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
- Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED,
- Settings.Secure.MAINTAIN_LOCATION_AFTER_SP_DISABLED,
Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH,
Settings.Secure.MULTI_PRESS_TIMEOUT,
Settings.Secure.NFC_PAYMENT_FOREGROUND,
@@ -662,7 +659,6 @@
Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
Settings.Secure.PAYMENT_SERVICE_SEARCH_URI,
Settings.Secure.PRINT_SERVICE_SEARCH_URI,
- Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED,
Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, // Candidate?
Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY,
Settings.Secure.SEARCH_MAX_RESULTS_PER_SOURCE,
@@ -686,7 +682,6 @@
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
Settings.Secure.SELECTED_SPELL_CHECKER, // Intentionally removed in Q
Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, // Intentionally removed in Q
- Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE,
Settings.Secure.SETTINGS_CLASSNAME,
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, // candidate?
Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
diff --git a/packages/SystemUI/res/drawable/ic_signal_sensors.xml b/packages/SystemUI/res/drawable/ic_signal_sensors.xml
deleted file mode 100644
index faaddf6..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_sensors.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 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 android:height="48dp" android:viewportHeight="5"
- android:viewportWidth="5" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="#00000000"
- android:pathData="m4.762,0.661 l-4.233,4.233"
- android:strokeAlpha="1" android:strokeColor="#000000"
- android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth=".5"/>
- <path android:fillColor="#00000000"
- android:pathData="M0.265,2.778L1.058,2.778l0.529,-1.323 0.529,2.646 0.529,-3.175 0.529,2.646 0.529,-1.587 0.265,0.794h1.058"
- android:strokeAlpha="1" android:strokeColor="#000000"
- android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth=".33"/>
-</vector>
-
diff --git a/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml b/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml
new file mode 100644
index 0000000..ca8f993
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml
@@ -0,0 +1,41 @@
+<!--
+ Copyright (C) 2019 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:insetLeft="3dp"
+ android:insetRight="3dp"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M21.966,2 L2,22"
+ android:strokeLineCap="round"
+ android:strokeColor="#000000"
+ android:fillColor="#00000000"
+ android:strokeWidth="1.6521436"
+ android:strokeLineJoin="miter"
+ android:strokeAlpha="1"/>
+ <path
+ android:pathData="M0.752,12L4.496,12l2.496,-6.25 2.496,12.5 2.496,-15 2.496,12.5 2.496,-7.5 1.248,3.75h4.992"
+ android:strokeLineCap="round"
+ android:strokeColor="#000000"
+ android:fillColor="#00000000"
+ android:strokeWidth="1.25090861"
+ android:strokeLineJoin="round"
+ android:strokeAlpha="1"/>
+</vector>
+
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b7d1900..70f2cce 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -97,6 +97,7 @@
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -291,6 +292,7 @@
@Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
@Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
@Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
+ @Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
@Inject
public Dependency() {
@@ -461,6 +463,7 @@
mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
+ mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index 3c6f081..53050bf 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -60,6 +60,8 @@
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -225,5 +227,11 @@
/**
*/
@Binds
+ public abstract SensorPrivacyController provideSensorPrivacyControllerImpl(
+ SensorPrivacyControllerImpl controllerImpl);
+
+ /**
+ */
+ @Binds
public abstract QSHost provideQsHost(QSTileHost controllerImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index d26cee9..2956ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -41,7 +41,6 @@
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.qs.tiles.SensorPrivacyTile;
import com.android.systemui.qs.tiles.UserTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.WorkModeTile;
@@ -73,7 +72,6 @@
private final Provider<DataSaverTile> mDataSaverTileProvider;
private final Provider<NightDisplayTile> mNightDisplayTileProvider;
private final Provider<NfcTile> mNfcTileProvider;
- private final Provider<SensorPrivacyTile> mSensorPrivacyTileProvider;
private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
private QSTileHost mHost;
@@ -96,7 +94,6 @@
Provider<DataSaverTile> dataSaverTileProvider,
Provider<NightDisplayTile> nightDisplayTileProvider,
Provider<NfcTile> nfcTileProvider,
- Provider<SensorPrivacyTile> sensorPrivacyTileProvider,
Provider<GarbageMonitor.MemoryTile> memoryTileProvider) {
mWifiTileProvider = wifiTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
@@ -115,7 +112,6 @@
mDataSaverTileProvider = dataSaverTileProvider;
mNightDisplayTileProvider = nightDisplayTileProvider;
mNfcTileProvider = nfcTileProvider;
- mSensorPrivacyTileProvider = sensorPrivacyTileProvider;
mMemoryTileProvider = memoryTileProvider;
}
@@ -168,8 +164,6 @@
return mNightDisplayTileProvider.get();
case "nfc":
return mNfcTileProvider.get();
- case "sensorprivacy":
- return mSensorPrivacyTileProvider.get();
}
// Intent tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
deleted file mode 100644
index 7ee37d5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.systemui.qs.tiles;
-
-import android.content.Intent;
-import android.hardware.SensorPrivacyManager;
-import android.service.quicksettings.Tile;
-import android.widget.Switch;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QSTile.BooleanState;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-
-import javax.inject.Inject;
-
-/** Quick settings tile: SensorPrivacy mode **/
-public class SensorPrivacyTile extends QSTileImpl<BooleanState> implements
- SensorPrivacyManager.OnSensorPrivacyChangedListener {
- private static final String TAG = "SensorPrivacy";
- private final Icon mIcon =
- ResourceIcon.get(R.drawable.ic_signal_sensors);
- private final KeyguardMonitor mKeyguard;
- private final SensorPrivacyManager mSensorPrivacyManager;
- private final ActivityStarter mActivityStarter;
-
- @Inject
- public SensorPrivacyTile(QSHost host, SensorPrivacyManager sensorPrivacyManager,
- KeyguardMonitor keyguardMonitor, ActivityStarter activityStarter) {
- super(host);
-
- mSensorPrivacyManager = sensorPrivacyManager;
- mKeyguard = keyguardMonitor;
- mActivityStarter = activityStarter;
- }
-
- @Override
- public BooleanState newTileState() {
- return new BooleanState();
- }
-
- @Override
- public void handleClick() {
- final boolean wasEnabled = mState.value;
- // Don't allow disabling from the lockscreen.
- if (wasEnabled && mKeyguard.isSecure() && mKeyguard.isShowing()) {
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
- setEnabled(!wasEnabled);
- });
- return;
- }
-
- MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
- setEnabled(!wasEnabled);
- }
-
- private void setEnabled(boolean enabled) {
- mSensorPrivacyManager.setSensorPrivacy(enabled);
- }
-
- @Override
- public CharSequence getTileLabel() {
- return mContext.getString(R.string.sensor_privacy_mode);
- }
-
- @Override
- public Intent getLongClickIntent() {
- return new Intent();
- }
-
- @Override
- protected void handleUpdateState(BooleanState state, Object arg) {
- final boolean enabled = arg instanceof Boolean ? (Boolean) arg
- : mSensorPrivacyManager.isSensorPrivacyEnabled();
- state.value = enabled;
- state.label = mContext.getString(R.string.sensor_privacy_mode);
- state.icon = mIcon;
- state.state = enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.contentDescription = state.label;
- state.expandedAccessibilityClassName = Switch.class.getName();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_SENSOR_PRIVACY;
- }
-
- @Override
- protected String composeChangeAnnouncement() {
- if (mState.value) {
- return mContext
- .getString(R.string.accessibility_quick_settings_sensor_privacy_changed_on);
- } else {
- return mContext
- .getString(R.string.accessibility_quick_settings_sensor_privacy_changed_off);
- }
- }
-
- @Override
- protected void handleSetListening(boolean listening) {
- if (listening) {
- mSensorPrivacyManager.addSensorPrivacyListener(this);
- } else {
- mSensorPrivacyManager.removeSensorPrivacyListener(this);
- }
- }
-
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- refreshState(enabled);
- }
-}
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 4a86484..b7a7873 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -60,6 +60,7 @@
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -100,6 +101,7 @@
private final String mSlotLocation;
private final String mSlotMicrophone;
private final String mSlotCamera;
+ private final String mSlotSensorsOff;
private final Context mContext;
private final Handler mHandler = new Handler();
@@ -118,6 +120,7 @@
private final LocationController mLocationController;
private final PrivacyItemController mPrivacyItemController;
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+ private final SensorPrivacyController mSensorPrivacyController;
// Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there.
@@ -149,6 +152,7 @@
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mLocationController = Dependency.get(LocationController.class);
mPrivacyItemController = Dependency.get(PrivacyItemController.class);
+ mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -165,6 +169,7 @@
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);
+ mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off);
// listen for broadcasts
IntentFilter filter = new IntentFilter();
@@ -232,6 +237,11 @@
mContext.getString(R.string.accessibility_location_active));
mIconController.setIconVisibility(mSlotLocation, false);
+ // sensors off
+ mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off, null);
+ mIconController.setIconVisibility(mSlotSensorsOff,
+ mSensorPrivacyController.isSensorPrivacyEnabled());
+
mRotationLockController.addCallback(this);
mBluetooth.addCallback(this);
mProvisionedController.addCallback(this);
@@ -242,6 +252,7 @@
mDataSaver.addCallback(this);
mKeyguardMonitor.addCallback(this);
mPrivacyItemController.addCallback(this);
+ mSensorPrivacyController.addCallback(mSensorPrivacyListener);
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
}
@@ -514,6 +525,16 @@
}
};
+ private final SensorPrivacyController.OnSensorPrivacyChangedListener mSensorPrivacyListener =
+ new SensorPrivacyController.OnSensorPrivacyChangedListener() {
+ @Override
+ public void onSensorPrivacyChanged(boolean enabled) {
+ mHandler.post(() -> {
+ mIconController.setIconVisibility(mSlotSensorsOff, enabled);
+ });
+ }
+ };
+
@Override
public void appTransitionStarting(int displayId, long startTime, long duration,
boolean forced) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
new file mode 100644
index 0000000..6d5ce60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.policy;
+
+/**
+ * Interface for classes to control sensor privacy state and notification.
+ */
+public interface SensorPrivacyController extends
+ CallbackController<SensorPrivacyController.OnSensorPrivacyChangedListener> {
+
+ /**
+ * Returns whether sensor privacy is enabled.
+ */
+ boolean isSensorPrivacyEnabled();
+
+ /**
+ * Interface for classes to receive callbacks when sensor privacy state changes.
+ */
+ interface OnSensorPrivacyChangedListener {
+ void onSensorPrivacyChanged(boolean enabled);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
new file mode 100644
index 0000000..5db6693
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.hardware.SensorPrivacyManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controls sensor privacy state and notification.
+ */
+@Singleton
+public class SensorPrivacyControllerImpl implements SensorPrivacyController,
+ SensorPrivacyManager.OnSensorPrivacyChangedListener {
+ private SensorPrivacyManager mSensorPrivacyManager;
+ private final List<OnSensorPrivacyChangedListener> mListeners;
+ private Object mLock = new Object();
+ private boolean mSensorPrivacyEnabled;
+
+ /**
+ * Public constructor.
+ */
+ @Inject
+ public SensorPrivacyControllerImpl(Context context) {
+ mSensorPrivacyManager = (SensorPrivacyManager) context.getSystemService(
+ Context.SENSOR_PRIVACY_SERVICE);
+ mSensorPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled();
+ mSensorPrivacyManager.addSensorPrivacyListener(this);
+ mListeners = new ArrayList<>(1);
+ }
+
+ /**
+ * Returns whether sensor privacy is enabled.
+ */
+ public boolean isSensorPrivacyEnabled() {
+ synchronized (mLock) {
+ return mSensorPrivacyEnabled;
+ }
+ }
+
+ /**
+ * Adds the provided listener for callbacks when sensor privacy state changes.
+ */
+ public void addCallback(OnSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ notifyListenerLocked(listener);
+ }
+ }
+
+ /**
+ * Removes the provided listener from callbacks when sensor privacy state changes.
+ */
+ public void removeCallback(OnSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ mListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Callback invoked by the SensorPrivacyService when sensor privacy state changes.
+ */
+ public void onSensorPrivacyChanged(boolean enabled) {
+ synchronized (mLock) {
+ mSensorPrivacyEnabled = enabled;
+ for (OnSensorPrivacyChangedListener listener : mListeners) {
+ notifyListenerLocked(listener);
+ }
+ }
+ }
+
+ private void notifyListenerLocked(OnSensorPrivacyChangedListener listener) {
+ listener.onSensorPrivacyChanged(mSensorPrivacyEnabled);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
deleted file mode 100644
index 6386c4c..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.systemui.qs.tiles;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.SensorPrivacyManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class SensorPrivacyTileTest extends SysuiTestCase {
-
- @Mock
- private KeyguardMonitor mKeyguard;
- @Mock
- private QSTileHost mHost;
- @Mock
- SensorPrivacyManager mSensorPrivacyManager;
-
- private TestableLooper mTestableLooper;
-
- private SensorPrivacyTile mSensorPrivacyTile;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mTestableLooper = TestableLooper.get(this);
- mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
- mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
-
- mSensorPrivacyManager = mDependency.injectMockDependency(SensorPrivacyManager.class);
-
- when(mHost.getContext()).thenReturn(mContext);
-
- mSensorPrivacyTile = new SensorPrivacyTile(mHost, mSensorPrivacyManager, mKeyguard,
- mock(ActivityStarter.class));
- }
-
- @Test
- public void testSensorPrivacyListenerAdded_handleListeningTrue() {
- // To prevent access to privacy related features from apps with WRITE_SECURE_SETTINGS the
- // sensor privacy state is not stored in Settings; to receive notification apps must add
- // themselves as a listener with the SensorPrivacyManager. This test verifies when
- // setListening is called with a value of true the tile adds itself as a listener.
- mSensorPrivacyTile.handleSetListening(true);
- mTestableLooper.processAllMessages();
- verify(mSensorPrivacyManager).addSensorPrivacyListener(mSensorPrivacyTile);
- }
-
- @Test
- public void testSensorPrivacyListenerRemoved_handleListeningFalse() {
- // Similar to the test above verifies that the tile removes itself as a listener when
- // setListening is called with a value of false.
- mSensorPrivacyTile.handleSetListening(false);
- mTestableLooper.processAllMessages();
- verify(mSensorPrivacyManager).removeSensorPrivacyListener((mSensorPrivacyTile));
- }
-
- @Test
- public void testSensorPrivacyEnabled_handleClick() {
- // Verifies when the SensorPrivacy tile is clicked it invokes the SensorPrivacyManager to
- // set sensor privacy.
- mSensorPrivacyTile.getState().value = false;
- mSensorPrivacyTile.handleClick();
- mTestableLooper.processAllMessages();
- verify(mSensorPrivacyManager).setSensorPrivacy(true);
-
- mSensorPrivacyTile.getState().value = true;
- mSensorPrivacyTile.handleClick();
- mTestableLooper.processAllMessages();
- verify(mSensorPrivacyManager).setSensorPrivacy(false);
- }
-
- @Test
- public void testSensorPrivacyNotDisabled_keyguard() {
- // Verifies when the device is locked that sensor privacy cannot be disabled
- when(mKeyguard.isSecure()).thenReturn(true);
- when(mKeyguard.isShowing()).thenReturn(true);
- mSensorPrivacyTile.getState().value = true;
- mSensorPrivacyTile.handleClick();
- mTestableLooper.processAllMessages();
- verify(mSensorPrivacyManager, never()).setSensorPrivacy(false);
- }
-}
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 1cbcbe5..edeb049 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -18,20 +18,15 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import android.app.ActivityManager;
import android.content.Context;
import android.hardware.ISensorPrivacyListener;
import android.hardware.ISensorPrivacyManager;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
@@ -277,8 +272,6 @@
}
}
mListeners.finishBroadcast();
- // Handle the state of all sensors managed by this service.
- SensorState.handleSensorPrivacyToggled(mContext, enabled);
}
}
@@ -306,121 +299,4 @@
}
}
}
-
- /**
- * Maintains the state of the sensors when sensor privacy is enabled to return them to their
- * original state when sensor privacy is disabled.
- */
- private static final class SensorState {
-
- private static Object sLock = new Object();
- @GuardedBy("sLock")
- private static SensorState sPreviousState;
-
- private boolean mAirplaneEnabled;
- private boolean mLocationEnabled;
-
- SensorState(boolean airplaneEnabled, boolean locationEnabled) {
- mAirplaneEnabled = airplaneEnabled;
- mLocationEnabled = locationEnabled;
- }
-
- public static void handleSensorPrivacyToggled(Context context, boolean enabled) {
- synchronized (sLock) {
- SensorState state;
- if (enabled) {
- // if sensor privacy is being enabled then obtain the current state of the
- // sensors to be persisted and restored when sensor privacy is disabled.
- state = getCurrentSensorState(context);
- } else {
- // else obtain the previous sensor state to be restored, first from the saved
- // state if available, otherwise attempt to read it from Settings.
- if (sPreviousState != null) {
- state = sPreviousState;
- } else {
- state = getPersistedSensorState(context);
- }
- // if the previous state is not available then return without attempting to
- // modify the sensor state.
- if (state == null) {
- return;
- }
- }
- // The SensorState represents the state of the sensor before sensor privacy was
- // enabled; if airplane mode was not enabled then the state of airplane mode should
- // be the same as the state of sensor privacy.
- if (!state.mAirplaneEnabled) {
- setAirplaneMode(context, enabled);
- }
- // Similar to airplane mode the state of location should be the opposite of sensor
- // privacy mode, if it was enabled when sensor privacy was enabled then it should be
- // disabled. If location is disabled when sensor privacy is enabled then it will be
- // left disabled when sensor privacy is disabled.
- if (state.mLocationEnabled) {
- setLocationEnabled(context, !enabled);
- }
-
- // if sensor privacy is being enabled then persist the current state.
- if (enabled) {
- sPreviousState = state;
- persistState(context, sPreviousState);
- }
- }
- }
-
- public static SensorState getCurrentSensorState(Context context) {
- LocationManager locationManager = (LocationManager) context.getSystemService(
- Context.LOCATION_SERVICE);
- boolean airplaneEnabled = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
- boolean locationEnabled = locationManager.isLocationEnabled();
- return new SensorState(airplaneEnabled, locationEnabled);
- }
-
- public static void persistState(Context context, SensorState state) {
- StringBuilder stateValue = new StringBuilder();
- stateValue.append(state.mAirplaneEnabled
- ? Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED
- : Settings.Secure.DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED);
- stateValue.append(",");
- stateValue.append(
- state.mLocationEnabled ? Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED
- : Settings.Secure.MAINTAIN_LOCATION_AFTER_SP_DISABLED);
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE, stateValue.toString());
- }
-
- public static SensorState getPersistedSensorState(Context context) {
- String persistedState = Settings.Secure.getString(context.getContentResolver(),
- Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE);
- if (persistedState == null) {
- Log.e(TAG, "The persisted sensor state could not be obtained from Settings");
- return null;
- }
- String[] sensorStates = persistedState.split(",");
- if (sensorStates.length < 2) {
- Log.e(TAG, "The persisted sensor state does not contain the expected values: "
- + persistedState);
- return null;
- }
- boolean airplaneEnabled = sensorStates[0].equals(
- Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED);
- boolean locationEnabled = sensorStates[1].equals(
- Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED);
- return new SensorState(airplaneEnabled, locationEnabled);
- }
-
- private static void setAirplaneMode(Context context, boolean enable) {
- ConnectivityManager connectivityManager =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- connectivityManager.setAirplaneMode(enable);
- }
-
- private static void setLocationEnabled(Context context, boolean enable) {
- LocationManager locationManager = (LocationManager) context.getSystemService(
- Context.LOCATION_SERVICE);
- locationManager.setLocationEnabledForUser(enable,
- UserHandle.of(ActivityManager.getCurrentUser()));
- }
- }
}