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

Commit c4e6b081 authored by Evan Severson's avatar Evan Severson Committed by Android (Google) Code Review
Browse files

Merge "Create a state for the camera and microhpone toggles"

parents d676c44e 41d80b9b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -32,4 +32,12 @@ interface ISensorPrivacyManager {

    void setSensorPrivacy(boolean enable);
    // =============== End of transactions used on native side as well ============================

    // TODO(evanseverson) add to native interface
    boolean isIndividualSensorPrivacyEnabled(int sensor);

    // TODO(evanseverson) add to native interface
    void setIndividualSensorPrivacy(int sensor, boolean enable);

    // TODO(evanseverson) listeners
}
 No newline at end of file
+45 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.hardware;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
@@ -27,6 +28,9 @@ import android.util.ArrayMap;

import com.android.internal.annotations.GuardedBy;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * This class provides access to the sensor privacy services; sensor privacy allows the
 * user to disable access to all sensors on the device. This class provides methods to query the
@@ -38,6 +42,20 @@ import com.android.internal.annotations.GuardedBy;
@SystemService(Context.SENSOR_PRIVACY_SERVICE)
public final class SensorPrivacyManager {

    /** Microphone */
    public static final int INDIVIDUAL_SENSOR_MICROPHONE = 1;

    /** Camera */
    public static final int INDIVIDUAL_SENSOR_CAMERA = 2;

    @IntDef(prefix = "INDIVIDUAL_SENSOR_", value = {
            INDIVIDUAL_SENSOR_MICROPHONE,
            INDIVIDUAL_SENSOR_CAMERA
    })
    @Retention(RetentionPolicy.SOURCE)
    /** Individual sensors not listed in {@link Sensor} */
    @interface IndividualSensor {}

    /**
     * A class implementing this interface can register with the {@link
     * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy
@@ -168,4 +186,31 @@ public final class SensorPrivacyManager {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns whether sensor privacy is currently enabled for a specific sensor.
     *
     * @return true if sensor privacy is currently enabled, false otherwise.
     */
    public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
        try {
            return mService.isIndividualSensorPrivacyEnabled(sensor);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sets sensor privacy to the specified state for an individual sensor.
     *
     * @param enable the state to which sensor privacy should be set.
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
    public void setIndividualSensorPrivacy(@IndividualSensor int sensor, boolean enable) {
        try {
            mService.setIndividualSensorPrivacy(sensor, enable);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+65 −38
Original line number Diff line number Diff line
@@ -30,24 +30,22 @@ import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.NoSuchElementException;

/** @hide */
@@ -57,7 +55,9 @@ public final class SensorPrivacyService extends SystemService {

    private static final String SENSOR_PRIVACY_XML_FILE = "sensor_privacy.xml";
    private static final String XML_TAG_SENSOR_PRIVACY = "sensor-privacy";
    private static final String XML_TAG_INDIVIDUAL_SENSOR_PRIVACY = "individual-sensor-privacy";
    private static final String XML_ATTRIBUTE_ENABLED = "enabled";
    private static final String XML_ATTRIBUTE_SENSOR = "sensor";

    private final SensorPrivacyServiceImpl mSensorPrivacyServiceImpl;

@@ -80,6 +80,7 @@ public final class SensorPrivacyService extends SystemService {
        private final AtomicFile mAtomicFile;
        @GuardedBy("mLock")
        private boolean mEnabled;
        private SparseBooleanArray mIndividualEnabled = new SparseBooleanArray();

        SensorPrivacyServiceImpl(Context context) {
            mContext = context;
@@ -88,7 +89,7 @@ public final class SensorPrivacyService extends SystemService {
                    SENSOR_PRIVACY_XML_FILE);
            mAtomicFile = new AtomicFile(sensorPrivacyFile);
            synchronized (mLock) {
                mEnabled = readPersistedSensorPrivacyEnabledLocked();
                readPersistedSensorPrivacyStateLocked();
            }
        }

@@ -101,24 +102,19 @@ public final class SensorPrivacyService extends SystemService {
            enforceSensorPrivacyPermission();
            synchronized (mLock) {
                mEnabled = enable;
                FileOutputStream outputStream = null;
                try {
                    outputStream = mAtomicFile.startWrite();
                    TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
                    serializer.startDocument(null, true);
                    serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
                    serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enable);
                    serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
                    serializer.endDocument();
                    mAtomicFile.finishWrite(outputStream);
                } catch (IOException e) {
                    Log.e(TAG, "Caught an exception persisting the sensor privacy state: ", e);
                    mAtomicFile.failWrite(outputStream);
                }
                persistSensorPrivacyStateLocked();
            }
            mHandler.onSensorPrivacyChanged(enable);
        }

        public void setIndividualSensorPrivacy(int sensor, boolean enable) {
            enforceSensorPrivacyPermission();
            synchronized (mLock) {
                mIndividualEnabled.put(sensor, enable);
                persistSensorPrivacyState();
            }
        }

        /**
         * Enforces the caller contains the necessary permission to change the state of sensor
         * privacy.
@@ -143,30 +139,48 @@ public final class SensorPrivacyService extends SystemService {
            }
        }

        @Override
        public boolean isIndividualSensorPrivacyEnabled(int sensor) {
            synchronized (mLock) {
                return mIndividualEnabled.get(sensor, false);
            }
        }

        /**
         * Returns the state of sensor privacy from persistent storage.
         */
        private boolean readPersistedSensorPrivacyEnabledLocked() {
        private void readPersistedSensorPrivacyStateLocked() {
            // if the file does not exist then sensor privacy has not yet been enabled on
            // the device.
            if (!mAtomicFile.exists()) {
                return false;
                return;
            }
            boolean enabled;
            try (FileInputStream inputStream = mAtomicFile.openRead()) {
                TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
                XmlUtils.beginDocument(parser, XML_TAG_SENSOR_PRIVACY);
                parser.next();
                mEnabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);

                XmlUtils.nextElement(parser);
                while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
                    String tagName = parser.getName();
                enabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
                    if (XML_TAG_INDIVIDUAL_SENSOR_PRIVACY.equals(tagName)) {
                        int sensor = XmlUtils.readIntAttribute(parser, XML_ATTRIBUTE_SENSOR);
                        boolean enabled = XmlUtils.readBooleanAttribute(parser,
                                XML_ATTRIBUTE_ENABLED);
                        mIndividualEnabled.put(sensor, enabled);
                        XmlUtils.skipCurrentTag(parser);
                    } else {
                        XmlUtils.nextElement(parser);
                    }
                }

            } catch (IOException | XmlPullParserException e) {
                Log.e(TAG, "Caught an exception reading the state from storage: ", e);
                // Delete the file to prevent the same error on subsequent calls and assume sensor
                // privacy is not enabled.
                mAtomicFile.delete();
                enabled = false;
            }
            return enabled;
        }

        /**
@@ -174,6 +188,11 @@ public final class SensorPrivacyService extends SystemService {
         */
        private void persistSensorPrivacyState() {
            synchronized (mLock) {
                persistSensorPrivacyStateLocked();
            }
        }

        private void persistSensorPrivacyStateLocked() {
            FileOutputStream outputStream = null;
            try {
                outputStream = mAtomicFile.startWrite();
@@ -181,6 +200,15 @@ public final class SensorPrivacyService extends SystemService {
                serializer.startDocument(null, true);
                serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
                serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, mEnabled);
                int numIndividual = mIndividualEnabled.size();
                for (int i = 0; i < numIndividual; i++) {
                    serializer.startTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
                    int sensor = mIndividualEnabled.keyAt(i);
                    boolean enabled = mIndividualEnabled.valueAt(i);
                    serializer.attributeInt(null, XML_ATTRIBUTE_SENSOR, sensor);
                    serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled);
                    serializer.endTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
                }
                serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
                serializer.endDocument();
                mAtomicFile.finishWrite(outputStream);
@@ -189,7 +217,6 @@ public final class SensorPrivacyService extends SystemService {
                mAtomicFile.failWrite(outputStream);
            }
        }
        }

        /**
         * Registers a listener to be notified when the sensor privacy state changes.