/* * 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 android.hardware; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UserIdInt; import android.content.Context; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.service.SensorPrivacyIndividualEnabledSensorProto; import android.service.SensorPrivacySensorProto; import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.camera.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; /** * This class provides information about the microphone and camera toggles. */ @SystemService(Context.SENSOR_PRIVACY_SERVICE) public final class SensorPrivacyManager { private static final String LOG_TAG = SensorPrivacyManager.class.getSimpleName(); /** * Unique Id of this manager to identify to the service * @hide */ private IBinder token = new Binder(); /** * An extra containing a sensor * @hide */ public static final String EXTRA_SENSOR = SensorPrivacyManager.class.getName() + ".extra.sensor"; /** * An extra containing the notification id that triggered the intent * @hide */ public static final String EXTRA_NOTIFICATION_ID = SensorPrivacyManager.class.getName() + ".extra.notification_id"; /** * An extra indicating if all sensors are affected * @hide */ public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName() + ".extra.all_sensors"; /** * An extra containing the sensor type * @hide */ public static final String EXTRA_TOGGLE_TYPE = SensorPrivacyManager.class.getName() + ".extra.toggle_type"; /** * Sensor constants which are used in {@link SensorPrivacyManager} */ public static class Sensors { private Sensors() {} /** * Constant for the microphone */ public static final int MICROPHONE = SensorPrivacySensorProto.MICROPHONE; /** * Constant for the camera */ public static final int CAMERA = SensorPrivacySensorProto.CAMERA; /** * Individual sensors not listed in {@link Sensors} * * @hide */ @IntDef(value = { MICROPHONE, CAMERA }) @Retention(RetentionPolicy.SOURCE) public @interface Sensor {} } /** * Source through which Privacy Sensor was toggled. * @hide */ @TestApi public static class Sources { private Sources() {} /** * Constant for the Quick Setting Tile. */ public static final int QS_TILE = SensorPrivacyToggleSourceProto.QS_TILE; /** * Constant for the Settings. */ public static final int SETTINGS = SensorPrivacyToggleSourceProto.SETTINGS; /** * Constant for Dialog. */ public static final int DIALOG = SensorPrivacyToggleSourceProto.DIALOG; /** * Constant for SHELL. */ public static final int SHELL = SensorPrivacyToggleSourceProto.SHELL; /** * Constant for OTHER. */ public static final int OTHER = SensorPrivacyToggleSourceProto.OTHER; /** * Constant for SAFETY_CENTER. */ public static final int SAFETY_CENTER = SensorPrivacyToggleSourceProto.SAFETY_CENTER; /** * Source for toggling sensors * * @hide */ @IntDef(value = { QS_TILE, SETTINGS, DIALOG, SHELL, OTHER, SAFETY_CENTER }) @Retention(RetentionPolicy.SOURCE) public @interface Source {} } /** * Constant for software toggle. */ public static final int TOGGLE_TYPE_SOFTWARE = SensorPrivacyIndividualEnabledSensorProto.SOFTWARE; /** * Constant for hardware toggle. */ public static final int TOGGLE_TYPE_HARDWARE = SensorPrivacyIndividualEnabledSensorProto.HARDWARE; /** * Types of toggles which can exist for sensor privacy * * @hide */ @IntDef(value = { TOGGLE_TYPE_SOFTWARE, TOGGLE_TYPE_HARDWARE }) @Retention(RetentionPolicy.SOURCE) public @interface ToggleType {} /** * Types of state which can exist for the sensor privacy toggle * @hide */ @SystemApi @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public static class StateTypes { private StateTypes() {} /** * Constant indicating privacy is enabled. */ public static final int ENABLED = SensorPrivacyIndividualEnabledSensorProto.ENABLED; /** * Constant indicating privacy is disabled. */ public static final int DISABLED = SensorPrivacyIndividualEnabledSensorProto.DISABLED; /** * Constant indicating privacy is enabled except for the automotive driver assistance apps * which are required by car manufacturer for driving. */ public static final int ENABLED_EXCEPT_ALLOWLISTED_APPS = SensorPrivacyIndividualEnabledSensorProto.ENABLED_EXCEPT_ALLOWLISTED_APPS; /** * Types of state which can exist for a sensor privacy toggle * * @hide */ @IntDef(value = { ENABLED, DISABLED, ENABLED_EXCEPT_ALLOWLISTED_APPS }) @Retention(RetentionPolicy.SOURCE) public @interface StateType {} } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy * state changes. * * @hide */ @SystemApi public interface OnSensorPrivacyChangedListener { /** * Callback invoked when the sensor privacy state changes. * * @param params Parameters describing the new state */ default void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params) { onSensorPrivacyChanged(params.mSensor, params.mEnabled); } /** * Callback invoked when the sensor privacy state changes. * * @param sensor the sensor whose state is changing * @param enabled true if sensor privacy is enabled, false otherwise. * * @deprecated Please use * {@link #onSensorPrivacyChanged(SensorPrivacyChangedParams)} */ @Deprecated void onSensorPrivacyChanged(int sensor, boolean enabled); /** * A class containing information about what the sensor privacy state has changed to. */ class SensorPrivacyChangedParams { private int mToggleType; private int mSensor; private boolean mEnabled; private int mState; @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) private SensorPrivacyChangedParams(int toggleType, int sensor, int state) { mToggleType = toggleType; mSensor = sensor; mState = state; if (state == StateTypes.ENABLED) { mEnabled = true; } else { mEnabled = false; } } private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) { mToggleType = toggleType; mSensor = sensor; mEnabled = enabled; } public @ToggleType int getToggleType() { return mToggleType; } public @Sensors.Sensor int getSensor() { return mSensor; } public boolean isEnabled() { return mEnabled; } @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public @StateTypes.StateType int getState() { return mState; } } } private static final Object sInstanceLock = new Object(); private final Object mLock = new Object(); @GuardedBy("sInstanceLock") private static SensorPrivacyManager sInstance; @NonNull private final Context mContext; @NonNull private final ISensorPrivacyManager mService; @GuardedBy("mLock") private final ArrayMap, Boolean> mToggleSupportCache = new ArrayMap<>(); @NonNull private final ArrayMap mListeners; /** Registered listeners */ @GuardedBy("mLock") @NonNull private final ArrayMap mToggleListeners = new ArrayMap<>(); /** Listeners registered using the deprecated APIs and which * OnSensorPrivacyChangedListener they're using. */ @GuardedBy("mLock") @NonNull private final ArrayMap, OnSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>(); /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local * listeners */ @NonNull private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { synchronized (mLock) { for (int i = 0; i < mToggleListeners.size(); i++) { OnSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i); if (Flags.cameraPrivacyAllowlist()) { int state = enabled ? StateTypes.ENABLED : StateTypes.DISABLED; mToggleListeners.valueAt(i).execute(() -> listener .onSensorPrivacyChanged(new OnSensorPrivacyChangedListener .SensorPrivacyChangedParams(toggleType, sensor, state))); } else { mToggleListeners.valueAt(i).execute(() -> listener .onSensorPrivacyChanged(new OnSensorPrivacyChangedListener .SensorPrivacyChangedParams(toggleType, sensor, enabled))); } } } } @Override @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void onSensorPrivacyStateChanged(@ToggleType int toggleType, @Sensors.Sensor int sensor, @StateTypes.StateType int state) { synchronized (mLock) { for (int i = 0; i < mToggleListeners.size(); i++) { OnSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i); mToggleListeners.valueAt(i).execute(() -> listener .onSensorPrivacyChanged(new OnSensorPrivacyChangedListener .SensorPrivacyChangedParams(toggleType, sensor, state))); } } } }; /** Whether the singleton ISensorPrivacyListener has been registered */ @GuardedBy("mLock") @NonNull private boolean mToggleListenerRegistered = false; private Boolean mRequiresAuthentication = null; /** * Private constructor to ensure only a single instance is created. */ private SensorPrivacyManager(Context context, ISensorPrivacyManager service) { mContext = context; mService = service; mListeners = new ArrayMap<>(); } /** * Returns the single instance of the SensorPrivacyManager. * * @hide */ public static SensorPrivacyManager getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { try { IBinder b = ServiceManager.getServiceOrThrow(Context.SENSOR_PRIVACY_SERVICE); ISensorPrivacyManager service = ISensorPrivacyManager.Stub.asInterface(b); sInstance = new SensorPrivacyManager(context, service); } catch (ServiceManager.ServiceNotFoundException e) { throw new IllegalStateException(e); } } return sInstance; } } /** * Returns the single instance of the SensorPrivacyManager. * * @hide */ public static SensorPrivacyManager getInstance(Context context, ISensorPrivacyManager service) { synchronized (sInstanceLock) { sInstance = new SensorPrivacyManager(context, service); return sInstance; } } /** * Checks if the given toggle is supported on this device * @param sensor The sensor to check * @return whether the toggle for the sensor is supported on this device. */ public boolean supportsSensorToggle(@Sensors.Sensor int sensor) { return supportsSensorToggle(TOGGLE_TYPE_SOFTWARE, sensor); } /** * Checks if the given toggle is supported on this device * @param sensor The sensor to check * @return whether the toggle for the sensor is supported on this device. * */ public boolean supportsSensorToggle(@ToggleType int toggleType, @Sensors.Sensor int sensor) { try { Pair key = new Pair(toggleType, sensor); synchronized (mLock) { Boolean val = mToggleSupportCache.get(key); if (val == null) { val = mService.supportsSensorToggle(toggleType, sensor); mToggleSupportCache.put(key, val); } return val; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param sensor the sensor to listen to changes to * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull OnSensorPrivacyChangedListener listener) { addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param sensor the sensor to listen to changes to * @param userId the user's id * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId, @NonNull OnSensorPrivacyChangedListener listener) { addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param sensor the sensor to listen to changes to * @param executor the executor to dispatch the callback on * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor * privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { Pair pair = new Pair(sensor, listener); OnSensorPrivacyChangedListener toggleListener = new OnSensorPrivacyChangedListener() { @Override public void onSensorPrivacyChanged(SensorPrivacyChangedParams params) { if (params.getSensor() == sensor) { listener.onSensorPrivacyChanged(params); } } @Override public void onSensorPrivacyChanged(int sensor, boolean enabled) { } }; synchronized (mLock) { mLegacyToggleListeners.put(pair, toggleListener); addSensorPrivacyListenerLocked(executor, toggleListener); } } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param listener the OnSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@NonNull OnSensorPrivacyChangedListener listener) { addSensorPrivacyListener(mContext.getMainExecutor(), listener); } /** * * Registers a new listener to receive notification when the state of sensor privacy * changes. * * @param executor the executor to dispatch the callback on * @param listener the OnSensorPrivacyChangedListener to be notified when the state of * sensor privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(@NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mLock) { addSensorPrivacyListenerLocked(executor, listener); } } @GuardedBy("mLock") private void addSensorPrivacyListenerLocked(@NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) { if (!mToggleListenerRegistered) { try { mService.addToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = true; } catch (RemoteException e) { e.rethrowFromSystemServer(); } } if (mToggleListeners.containsKey(listener)) { throw new IllegalArgumentException("listener is already registered"); } mToggleListeners.put(listener, executor); } /** * Unregisters the specified listener from receiving notifications when the state of any sensor * privacy changes. * * @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when * sensor privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull OnSensorPrivacyChangedListener listener) { Pair pair = new Pair(sensor, listener); synchronized (mLock) { OnSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener = mLegacyToggleListeners.remove(pair); if (onToggleSensorPrivacyChangedListener != null) { removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener); } } } /** * Unregisters the specified listener from receiving notifications when the state of any sensor * privacy changes. * * @param listener the {@link OnSensorPrivacyChangedListener} to be unregistered from * notifications when sensor privacy changes. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener( @NonNull OnSensorPrivacyChangedListener listener) { synchronized (mLock) { removeSensorPrivacyListenerLocked(listener); } } @GuardedBy("mLock") private void removeSensorPrivacyListenerLocked( @NonNull OnSensorPrivacyChangedListener listener) { mToggleListeners.remove(listener); if (mToggleListeners.size() == 0) { try { mService.removeToggleSensorPrivacyListener(mIToggleListener); mToggleListenerRegistered = false; } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } /** * Returns whether sensor privacy is currently enabled by software control for a specific * sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * * @deprecated Prefer to use {@link #isSensorPrivacyEnabled(int, int)} * * @hide */ @Deprecated @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) { return isSensorPrivacyEnabled(TOGGLE_TYPE_SOFTWARE, sensor); } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(@ToggleType int toggleType, @Sensors.Sensor int sensor) { try { return mService.isToggleSensorPrivacyEnabled(toggleType, sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether sensor privacy is currently enabled for a specific sensor. * Combines the state of the SW + HW toggles and returns true if either the * SOFTWARE or the HARDWARE toggles are enabled. * * @return true if sensor privacy is currently enabled, false otherwise. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean areAnySensorPrivacyTogglesEnabled(@Sensors.Sensor int sensor) { try { return mService.isCombinedToggleSensorPrivacyEnabled(sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns sensor privacy state for a specific sensor. * * @param toggleType The type of toggle to use * @param sensor The sensor to check * @return int sensor privacy state. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public @StateTypes.StateType int getSensorPrivacyState(@ToggleType int toggleType, @Sensors.Sensor int sensor) { try { return mService.getToggleSensorPrivacyState(toggleType, sensor); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns if camera privacy is enabled for a specific package. * * @param packageName The package to check * @return boolean camera privacy state. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public boolean isCameraPrivacyEnabled(@NonNull String packageName) { try { return mService.isCameraPrivacyEnabled(packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns camera privacy allowlist. * * @return List of automotive driver assistance packages for * privacy allowlisting. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public @NonNull List getCameraPrivacyAllowlist() { synchronized (mLock) { try { return mService.getCameraPrivacyAllowlist(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Sets camera privacy allowlist. * * @param allowlist List of automotive driver assistance packages for * privacy allowlisting. * * @hide */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void setCameraPrivacyAllowlist(@NonNull List allowlist) { synchronized (mLock) { try { mService.setCameraPrivacyAllowlist(allowlist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Sets sensor privacy to the specified state for an individual sensor. * * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) { setSensorPrivacy(resolveSourceFromCurrentContext(), sensor, enable, UserHandle.USER_CURRENT); } private @Sources.Source int resolveSourceFromCurrentContext() { String packageName = mContext.getOpPackageName(); if (Objects.equals(packageName, mContext.getPackageManager().getPermissionControllerPackageName())) { return Sources.SAFETY_CENTER; } return Sources.OTHER; } /** * Sets sensor privacy to the specified state for an individual sensor. * * @param sensor the sensor which to change the state for * @param state the state to which sensor privacy should be set. * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void setSensorPrivacyState(@Sensors.Sensor int sensor, @StateTypes.StateType int state) { setSensorPrivacyState(resolveSourceFromCurrentContext(), sensor, state); } /** * Sets sensor privacy to the specified state for an individual sensor. * * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * * @hide */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable) { setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT); } /** * Sets sensor privacy to the specified state for an individual sensor. * * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * @param userId the user's id * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setToggleSensorPrivacy(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets sensor privacy to the specified state for an individual sensor. * * @param source the source using which the sensor is toggled * @param sensor the sensor which to change the state for * @param state the state to which sensor privacy should be set. * * @hide */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void setSensorPrivacyState(@Sources.Source int source, @Sensors.Sensor int sensor, @StateTypes.StateType int state) { try { mService.setToggleSensorPrivacyState(mContext.getUserId(), source, sensor, state); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets sensor privacy to the specified state for an individual sensor for the profile group of * context's user. * * @param source the source using which the sensor is toggled. * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable) { setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT); } /** * Sets sensor privacy to the specified state for an individual sensor for the profile group of * context's user. * * @param source the source using which the sensor is toggled. * @param sensor the sensor which to change the state for * @param enable the state to which sensor privacy should be set. * @param userId the user's id * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) { try { mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets sensor privacy to the specified state for an individual sensor for the profile group of * context's user. * * @param source the source using which the sensor is toggled. * @param sensor the sensor which to change the state for * @param state the state to which sensor privacy should be set. * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void setSensorPrivacyStateForProfileGroup(@Sources.Source int source, @Sensors.Sensor int sensor, @StateTypes.StateType int state) { try { mService.setToggleSensorPrivacyStateForProfileGroup(mContext.getUserId(), source, sensor, state); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Don't show dialogs to turn off sensor privacy for this package. * * @param suppress Whether to suppress or re-enable. * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT); } /** * Don't show dialogs to turn off sensor privacy for this package. * * @param suppress Whether to suppress or re-enable. * @param userId the user's id * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void suppressSensorPrivacyReminders(int sensor, boolean suppress, @UserIdInt int userId) { try { mService.suppressToggleSensorPrivacyReminders(userId, sensor, token, suppress); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @return whether the device is required to be unlocked to change software state. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean requiresAuthentication() { if (mRequiresAuthentication == null) { try { mRequiresAuthentication = mService.requiresAuthentication(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return mRequiresAuthentication; } /** * If sensor privacy for the provided sensor is enabled then this call will show the user the * dialog which is shown when an application attempts to use that sensor. If privacy isn't * enabled then this does nothing. * * This call can only be made by the system uid. * * @throws SecurityException when called by someone other than system uid. * * @hide */ public void showSensorUseDialog(int sensor) { try { mService.showSensorUseDialog(sensor); } catch (RemoteException e) { Log.e(LOG_TAG, "Received exception while trying to show sensor use dialog", e); } } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the all-sensor privacy * state changes. * * @hide */ public interface OnAllSensorPrivacyChangedListener { /** * Callback invoked when the sensor privacy state changes. * * @param enabled true if sensor privacy is enabled, false otherwise. */ void onAllSensorPrivacyChanged(boolean enabled); } /** * Sets all-sensor privacy to the specified state. * * @param enable the state to which sensor privacy should be set. * * @hide */ @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setAllSensorPrivacy(boolean enable) { try { mService.setSensorPrivacy(enable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Registers a new listener to receive notification when the state of all-sensor privacy * changes. * * @param listener the OnSensorPrivacyChangedListener to be notified when the state of * all-sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addAllSensorPrivacyListener( @NonNull final OnAllSensorPrivacyChangedListener listener) { synchronized (mListeners) { ISensorPrivacyListener iListener = mListeners.get(listener); if (iListener == null) { iListener = new ISensorPrivacyListener.Stub() { @Override public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) { listener.onAllSensorPrivacyChanged(enabled); } @Override @FlaggedApi(Flags.FLAG_CAMERA_PRIVACY_ALLOWLIST) public void onSensorPrivacyStateChanged(int toggleType, int sensor, int state) { } }; mListeners.put(listener, iListener); } try { mService.addSensorPrivacyListener(iListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Unregisters the specified listener from receiving notifications when the state of all-sensor * privacy changes. * * @param listener the OnAllSensorPrivacyChangedListener to be unregistered from notifications * when all-sensor privacy changes. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeAllSensorPrivacyListener( @NonNull OnAllSensorPrivacyChangedListener listener) { synchronized (mListeners) { ISensorPrivacyListener iListener = mListeners.get(listener); if (iListener != null) { mListeners.remove(iListener); try { mService.removeSensorPrivacyListener(iListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } /** * Returns whether all-sensor privacy is currently enabled. * * @return true if all-sensor privacy is currently enabled, false otherwise. * * @hide */ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isAllSensorPrivacyEnabled() { try { return mService.isSensorPrivacyEnabled(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }