diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index df5da6c6a5e3e..130939aa290c1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8561,38 +8561,6 @@ public final class Settings { public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE = "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 927c85f2db8e2..1b45683b4f115 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -590,6 +590,13 @@ enum Action { // 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 71e071c14557a..de0228636fe6a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -58,6 +58,7 @@ @string/status_bar_mobile @string/status_bar_airplane @string/status_bar_battery + @string/status_bar_sensors_off rotate @@ -92,6 +93,7 @@ microphone camera airplane + sensors_off diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 7322a5445e861..e0aff394c91b6 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -623,7 +623,6 @@ public class SettingsBackupTest { 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 @@ public class SettingsBackupTest { 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, @@ -661,7 +658,6 @@ public class SettingsBackupTest { 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, @@ -685,7 +681,6 @@ public class SettingsBackupTest { 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 faaddf6473c4b..0000000000000 --- a/packages/SystemUI/res/drawable/ic_signal_sensors.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - 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 0000000000000..ca8f9931f1481 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index b7d19007cac2f..70f2ccee7d606 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.NextAlarmController; 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 @@ public class Dependency extends SystemUI { @Inject Lazy mActivityManagerWrapper; @Inject Lazy mDevicePolicyManagerWrapper; @Inject Lazy mPackageManagerWrapper; + @Inject Lazy mSensorPrivacyController; @Inject public Dependency() { @@ -461,6 +463,7 @@ public class Dependency extends SystemUI { 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 3c6f081d03731..53050bf2dc3e0 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.RotationLockController; 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; @@ -222,6 +224,12 @@ public abstract class DependencyBinder { @Binds public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl); + /** + */ + @Binds + public abstract SensorPrivacyController provideSensorPrivacyControllerImpl( + SensorPrivacyControllerImpl controllerImpl); + /** */ @Binds 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 d26cee982b643..2956ad0600a70 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.LocationTile; 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 @@ public class QSFactoryImpl implements QSFactory { private final Provider mDataSaverTileProvider; private final Provider mNightDisplayTileProvider; private final Provider mNfcTileProvider; - private final Provider mSensorPrivacyTileProvider; private final Provider mMemoryTileProvider; private QSTileHost mHost; @@ -96,7 +94,6 @@ public class QSFactoryImpl implements QSFactory { Provider dataSaverTileProvider, Provider nightDisplayTileProvider, Provider nfcTileProvider, - Provider sensorPrivacyTileProvider, Provider memoryTileProvider) { mWifiTileProvider = wifiTileProvider; mBluetoothTileProvider = bluetoothTileProvider; @@ -115,7 +112,6 @@ public class QSFactoryImpl implements QSFactory { mDataSaverTileProvider = dataSaverTileProvider; mNightDisplayTileProvider = nightDisplayTileProvider; mNfcTileProvider = nfcTileProvider; - mSensorPrivacyTileProvider = sensorPrivacyTileProvider; mMemoryTileProvider = memoryTileProvider; } @@ -168,8 +164,6 @@ public class QSFactoryImpl implements QSFactory { 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 7ee37d567a55d..0000000000000 --- 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 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 4a86484393a96..b7a78738828ef 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.LocationController; 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 @@ public class PhoneStatusBarPolicy 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 @@ public class PhoneStatusBarPolicy 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 @@ public class PhoneStatusBarPolicy 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 @@ public class PhoneStatusBarPolicy 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 @@ public class PhoneStatusBarPolicy 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 @@ public class PhoneStatusBarPolicy mDataSaver.addCallback(this); mKeyguardMonitor.addCallback(this); mPrivacyItemController.addCallback(this); + mSensorPrivacyController.addCallback(mSensorPrivacyListener); SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this); } @@ -514,6 +525,16 @@ public class PhoneStatusBarPolicy } }; + 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 0000000000000..6d5ce60ef621d --- /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 { + + /** + * 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 0000000000000..5db66932d3c1b --- /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 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 6386c4cd6331d..0000000000000 --- 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 1cbcbe5a8bdb0..edeb049c0802e 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -18,20 +18,15 @@ package com.android.server; 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 @@ public final class SensorPrivacyService extends SystemService { } } mListeners.finishBroadcast(); - // Handle the state of all sensors managed by this service. - SensorState.handleSensorPrivacyToggled(mContext, enabled); } } @@ -306,121 +299,4 @@ public final class SensorPrivacyService extends SystemService { } } } - - /** - * 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())); - } - } }