Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92e6edf5 authored by Evan Severson's avatar Evan Severson Committed by Valentin Iftime
Browse files

Add hidden apis to allow checking of hardware mic/cam toggles

The service already supports a hardware type so this change introduces
new overloads which add a parameter to check between hardware/software
or any other future types.

Bug: 191745272
Test: Manual, CtsSensorPrivacyTestCases, SensorPrivacyServiceMockingTest

Change-Id: Icda09da03f5361997566a62e3a72b25a760ef3ca
parent a30e852c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -24,6 +24,6 @@ oneway interface ISensorPrivacyListener {
    // the ones in
    //   frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
    // =============== Beginning of transactions used on native side as well ======================
    void onSensorPrivacyChanged(boolean enabled);
    void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
    // =============== End of transactions used on native side as well ============================
}
+9 −12
Original line number Diff line number Diff line
@@ -24,34 +24,31 @@ interface ISensorPrivacyManager {
    // the ones in
    //   frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
    // =============== Beginning of transactions used on native side as well ======================
    boolean supportsSensorToggle(int sensor);
    boolean supportsSensorToggle(int toggleType, int sensor);

    void addSensorPrivacyListener(in ISensorPrivacyListener listener);

    void addIndividualSensorPrivacyListener(int userId, int sensor,
            in ISensorPrivacyListener listener);
    void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);

    void removeSensorPrivacyListener(in ISensorPrivacyListener listener);

    void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
    void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);

    boolean isSensorPrivacyEnabled();

    boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
    boolean isCombinedToggleSensorPrivacyEnabled(int sensor);

    boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);

    void setSensorPrivacy(boolean enable);

    void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
    void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);

    void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
    void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
    // =============== End of transactions used on native side as well ============================

    void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
    void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token,
            boolean suppress);

    void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);

    void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);

    void showSensorUseDialog(int sensor);
}
 No newline at end of file
+229 −71
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.service.SensorPrivacyToggleSourceProto;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;

@@ -73,8 +72,6 @@ public final class SensorPrivacyManager {
    public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName()
            + ".extra.all_sensors";

    private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>();

    /**
     * Sensor constants which are used in {@link SensorPrivacyManager}
     */
@@ -241,8 +238,55 @@ public final class SensorPrivacyManager {
        void onSensorPrivacyChanged(int sensor, boolean enabled);
    }

    /**
     * A class implementing this interface can register with the {@link
     * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy
     * state changes.
     *
     * @hide
     */
    public interface OnToggleSensorPrivacyChangedListener {

        /**
         * 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 SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) {
                mToggleType = toggleType;
                mSensor = sensor;
                mEnabled = enabled;
            }

            public @ToggleTypes.ToggleType int getToggleType() {
                return mToggleType;
            }

            public @Sensors.Sensor int getSensor() {
                return mSensor;
            }

            public boolean isEnabled() {
                return mEnabled;
            }
        }

        /**
         * Callback invoked when the sensor privacy state changes.
         *
         * @param params Parameters describing the new state
         */
        void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params);
    }

    private static final Object sInstanceLock = new Object();

    private final Object mLock = new Object();

    @GuardedBy("sInstanceLock")
    private static SensorPrivacyManager sInstance;

@@ -252,12 +296,46 @@ public final class SensorPrivacyManager {
    @NonNull
    private final ISensorPrivacyManager mService;

    @GuardedBy("mLock")
    private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>();

    @NonNull
    private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners;

    /** Registered listeners */
    @GuardedBy("mLock")
    @NonNull
    private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners =
            new ArrayMap<>();

    /** Listeners registered using the deprecated APIs and which
     * OnToggleSensorPrivacyChangedListener they're using. */
    @GuardedBy("mLock")
    @NonNull
    private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>,
            OnToggleSensorPrivacyChangedListener> 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++) {
                    OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i);
                    mToggleListeners.valueAt(i).execute(() -> listener
                            .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener
                                    .SensorPrivacyChangedParams(toggleType, sensor, enabled)));
                }
            }
        }
    };

    /** Whether the singleton ISensorPrivacyListener has been registered */
    @GuardedBy("mLock")
    @NonNull
    private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener>
            mIndividualListeners;
    private boolean mToggleListenerRegistered = false;

    /**
     * Private constructor to ensure only a single instance is created.
@@ -266,7 +344,6 @@ public final class SensorPrivacyManager {
        mContext = context;
        mService = service;
        mListeners = new ArrayMap<>();
        mIndividualListeners = new ArrayMap<>();
    }

    /**
@@ -295,19 +372,35 @@ public final class SensorPrivacyManager {
     * @return whether the toggle for the sensor is supported on this device.
     */
    public boolean supportsSensorToggle(@Sensors.Sensor int sensor) {
        return supportsSensorToggle(ToggleTypes.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.
     *
     * @hide
     */
    public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType,
            @Sensors.Sensor int sensor) {
        try {
            Boolean val = mToggleSupportCache.get(sensor);
            Pair key = new Pair(toggleType, sensor);
            synchronized (mLock) {
                Boolean val = mToggleSupportCache.get(key);
                if (val == null) {
                val = mService.supportsSensorToggle(sensor);
                mToggleSupportCache.put(sensor, val);
                    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.
     *
@@ -315,6 +408,8 @@ public final class SensorPrivacyManager {
     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
     *                       privacy changes.
     *
     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
     *
     * @hide
     */
    @SystemApi
@@ -325,6 +420,7 @@ public final class SensorPrivacyManager {
    }

    /**
     *
     * Registers a new listener to receive notification when the state of sensor privacy
     * changes.
     *
@@ -333,15 +429,18 @@ public final class SensorPrivacyManager {
     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
     *                 privacy changes.
     *
     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId,
            @NonNull OnSensorPrivacyChangedListener listener) {
        addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener);
        addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
    }

    /**
     *
     * Registers a new listener to receive notification when the state of sensor privacy
     * changes.
     *
@@ -350,67 +449,77 @@ public final class SensorPrivacyManager {
     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
     *                       privacy changes.
     *
     * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
            @NonNull OnSensorPrivacyChangedListener listener) {
        Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
        synchronized (mIndividualListeners) {
            ISensorPrivacyListener iListener = mIndividualListeners.get(key);
            if (iListener == null) {
                iListener = new ISensorPrivacyListener.Stub() {
                    @Override
                    public void onSensorPrivacyChanged(boolean enabled) {
                        executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));

        Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
        OnToggleSensorPrivacyChangedListener toggleListener = params -> {
            if (params.getSensor() == sensor) {
                listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled());
            }
        };
                mIndividualListeners.put(key, iListener);
            }

            try {
                mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
        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 OnToggleSensorPrivacyChangedListener to be notified when the state of
     *                 sensor privacy changes.
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) {
        addSensorPrivacyListener(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 userId the user's id
     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
     *                 privacy changes.
     * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
     *                 sensor privacy changes.
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
            @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) {
        synchronized (mIndividualListeners) {
            ISensorPrivacyListener iListener = mIndividualListeners.get(listener);
            if (iListener == null) {
                iListener = new ISensorPrivacyListener.Stub() {
                    @Override
                    public void onSensorPrivacyChanged(boolean enabled) {
                        executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
    public void addSensorPrivacyListener(@NonNull Executor executor,
            @NonNull OnToggleSensorPrivacyChangedListener listener) {
        synchronized (mLock) {
            addSensorPrivacyListenerLocked(executor, listener);
        }
                };
                mIndividualListeners.put(new Pair<>(listener, sensor), iListener);
    }

    @GuardedBy("mLock")
    private void addSensorPrivacyListenerLocked(@NonNull Executor executor,
            @NonNull OnToggleSensorPrivacyChangedListener listener) {
        if (!mToggleListenerRegistered) {
            try {
                mService.addIndividualSensorPrivacyListener(userId, sensor,
                        iListener);
                mService.addToggleSensorPrivacyListener(mIToggleListener);
                mToggleListenerRegistered = true;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
                e.rethrowFromSystemServer();
            }
        }
        if (mToggleListeners.containsKey(listener)) {
            throw new IllegalArgumentException("listener is already registered");
        }
        mToggleListeners.put(listener, executor);
    }

    /**
@@ -420,30 +529,60 @@ public final class SensorPrivacyManager {
     * @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when
     *                 sensor privacy changes.
     *
     * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with
     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or
     * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void removeSensorPrivacyListener(@Sensors.Sensor int sensor,
            @NonNull OnSensorPrivacyChangedListener listener) {
        synchronized (mListeners) {
            for (int i = 0; i < mIndividualListeners.size(); i++) {
                Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i);
                if (pair.second == sensor && pair.first.equals(listener)) {
                    try {
                        mService.removeIndividualSensorPrivacyListener(sensor,
                                mIndividualListeners.valueAt(i));
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
        Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
        synchronized (mLock) {
            OnToggleSensorPrivacyChangedListener 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 OnToggleSensorPrivacyChangedListener} to be unregistered from
     *                 notifications when sensor privacy changes.
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public void removeSensorPrivacyListener(
            @NonNull OnToggleSensorPrivacyChangedListener listener) {
        synchronized (mLock) {
            removeSensorPrivacyListenerLocked(listener);
        }
                    mIndividualListeners.removeAt(i--);
    }

    @GuardedBy("mLock")
    private void removeSensorPrivacyListenerLocked(
            @NonNull OnToggleSensorPrivacyChangedListener 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 for a specific sensor.
     * Returns whether sensor privacy is currently enabled by software control for a specific
     * sensor.
     *
     * @return true if sensor privacy is currently enabled, false otherwise.
     *
@@ -452,20 +591,38 @@ public final class SensorPrivacyManager {
    @SystemApi
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
        return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
        return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor);
    }

    /**
     * Returns whether sensor privacy is currently enabled for a specific sensor.
     *
     * @return true if sensor privacy is currently enabled, false otherwise.
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public boolean isSensorPrivacyEnabled(@ToggleTypes.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 the actual privacy state.
     *
     * @return true if sensor privacy is currently enabled, false otherwise.
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
    public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) {
    public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
        try {
            return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
            return mService.isCombinedToggleSensorPrivacyEnabled(sensor);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -524,7 +681,7 @@ public final class SensorPrivacyManager {
    public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
            boolean enable, @UserIdInt int userId) {
        try {
            mService.setIndividualSensorPrivacy(userId, source, sensor, enable);
            mService.setToggleSensorPrivacy(userId, source, sensor, enable);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -561,7 +718,7 @@ public final class SensorPrivacyManager {
    public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
            @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) {
        try {
            mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable);
            mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -592,7 +749,7 @@ public final class SensorPrivacyManager {
    public void suppressSensorPrivacyReminders(int sensor,
            boolean suppress, @UserIdInt int userId) {
        try {
            mService.suppressIndividualSensorPrivacyReminders(userId, sensor,
            mService.suppressToggleSensorPrivacyReminders(userId, sensor,
                    token, suppress);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -667,7 +824,8 @@ public final class SensorPrivacyManager {
            if (iListener == null) {
                iListener = new ISensorPrivacyListener.Stub() {
                    @Override
                    public void onSensorPrivacyChanged(boolean enabled) {
                    public void onSensorPrivacyChanged(int toggleType, int sensor,
                            boolean enabled) {
                        listener.onAllSensorPrivacyChanged(enabled);
                    }
                };
+5 −1
Original line number Diff line number Diff line
@@ -5470,10 +5470,14 @@
    <!-- On-device package for providing companion device associations. -->
    <string name="config_systemCompanionDeviceProvider" translatable="false"></string>

    <!-- Whether this device is supporting the microphone toggle -->
    <!-- Whether this device is supporting the software microphone toggle -->
    <bool name="config_supportsMicToggle">false</bool>
    <!-- Whether this device is supporting the camera toggle -->
    <bool name="config_supportsCamToggle">false</bool>
    <!-- Whether this device is supporting the hardware microphone toggle -->
    <bool name="config_supportsHardwareMicToggle">false</bool>
    <!-- Whether this device is supporting the hardware camera toggle -->
    <bool name="config_supportsHardwareCamToggle">false</bool>

    <!-- List containing the allowed install sources for accessibility service. -->
    <string-array name="config_accessibility_allowed_install_source" translatable="false"/>
+2 −0
Original line number Diff line number Diff line
@@ -4646,6 +4646,8 @@

  <java-symbol type="bool" name="config_supportsMicToggle" />
  <java-symbol type="bool" name="config_supportsCamToggle" />
  <java-symbol type="bool" name="config_supportsHardwareMicToggle" />
  <java-symbol type="bool" name="config_supportsHardwareCamToggle" />

  <java-symbol type="dimen" name="starting_surface_icon_size" />
  <java-symbol type="dimen" name="starting_surface_default_icon_size" />
Loading