Merge "Create a state for the camera and microhpone toggles"
This commit is contained in:
committed by
Android (Google) Code Review
commit
c4e6b081b2
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
String tagName = parser.getName();
|
||||
enabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
|
||||
mEnabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
|
||||
|
||||
XmlUtils.nextElement(parser);
|
||||
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
|
||||
String tagName = parser.getName();
|
||||
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,20 +188,33 @@ public final class SensorPrivacyService extends SystemService {
|
||||
*/
|
||||
private void persistSensorPrivacyState() {
|
||||
synchronized (mLock) {
|
||||
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, mEnabled);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void persistSensorPrivacyStateLocked() {
|
||||
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, 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);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Caught an exception persisting the sensor privacy state: ", e);
|
||||
mAtomicFile.failWrite(outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user