cmsdk: Add persistent properties API
* Add support for reading and writing values from/to persistent storage. Requires the MANAGE_PERSISTENT_STORAGE permission, which should not be available for general use by applications. Change-Id: I8a793396d207f23fcda851c172372f2073778eec
This commit is contained in:
committed by
Gerrit Code Review
parent
087f2b536d
commit
7cef6f6945
@@ -38,6 +38,7 @@ import org.cyanogenmod.hardware.DisplayModeControl;
|
||||
import org.cyanogenmod.hardware.HighTouchSensitivity;
|
||||
import org.cyanogenmod.hardware.KeyDisabler;
|
||||
import org.cyanogenmod.hardware.LongTermOrbits;
|
||||
import org.cyanogenmod.hardware.PersistentStorage;
|
||||
import org.cyanogenmod.hardware.SerialNumber;
|
||||
import org.cyanogenmod.hardware.SunlightEnhancement;
|
||||
import org.cyanogenmod.hardware.TapToWake;
|
||||
@@ -79,6 +80,9 @@ public class CMHardwareService extends SystemService {
|
||||
public DisplayMode getCurrentDisplayMode();
|
||||
public DisplayMode getDefaultDisplayMode();
|
||||
public boolean setDisplayMode(DisplayMode mode, boolean makeDefault);
|
||||
|
||||
public boolean writePersistentBytes(String key, byte[] value);
|
||||
public byte[] readPersistentBytes(String key);
|
||||
}
|
||||
|
||||
private class LegacyCMHardware implements CMHardwareInterface {
|
||||
@@ -114,6 +118,8 @@ public class CMHardwareService extends SystemService {
|
||||
mSupportedFeatures |= CMHardwareManager.FEATURE_AUTO_CONTRAST;
|
||||
if (DisplayModeControl.isSupported())
|
||||
mSupportedFeatures |= CMHardwareManager.FEATURE_DISPLAY_MODES;
|
||||
if (PersistentStorage.isSupported())
|
||||
mSupportedFeatures |= CMHardwareManager.FEATURE_PERSISTENT_STORAGE;
|
||||
}
|
||||
|
||||
public int getSupportedFeatures() {
|
||||
@@ -293,6 +299,14 @@ public class CMHardwareService extends SystemService {
|
||||
public boolean setDisplayMode(DisplayMode mode, boolean makeDefault) {
|
||||
return DisplayModeControl.setMode(mode, makeDefault);
|
||||
}
|
||||
|
||||
public boolean writePersistentBytes(String key, byte[] value) {
|
||||
return PersistentStorage.set(key, value);
|
||||
}
|
||||
|
||||
public byte[] readPersistentBytes(String key) {
|
||||
return PersistentStorage.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
private CMHardwareInterface getImpl(Context context) {
|
||||
@@ -524,5 +538,27 @@ public class CMHardwareService extends SystemService {
|
||||
}
|
||||
return mCmHwImpl.setDisplayMode(mode, makeDefault);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePersistentBytes(String key, byte[] value) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
cyanogenmod.platform.Manifest.permission.MANAGE_PERSISTENT_STORAGE, null);
|
||||
if (!isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
|
||||
Log.e(TAG, "Persistent storage is not supported");
|
||||
return false;
|
||||
}
|
||||
return mCmHwImpl.writePersistentBytes(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readPersistentBytes(String key) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
cyanogenmod.platform.Manifest.permission.MANAGE_PERSISTENT_STORAGE, null);
|
||||
if (!isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
|
||||
Log.e(TAG, "Persistent storage is not supported");
|
||||
return null;
|
||||
}
|
||||
return mCmHwImpl.readPersistentBytes(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,6 +113,13 @@
|
||||
android:label="@string/permlab_read_alarms"
|
||||
android:description="@string/permdesc_read_alarms"/>
|
||||
|
||||
<!-- Allows an application to access persistent property storage
|
||||
<p>Not for use by third-party applications. -->
|
||||
<permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE"
|
||||
android:label="@string/permlab_managePersistentStorage"
|
||||
android:description="@string/permdesc_managePersistentStorage"
|
||||
android:protectionLevel="system|signature" />
|
||||
|
||||
<application android:process="system"
|
||||
android:persistent="true"
|
||||
android:hasCode="false"
|
||||
|
||||
@@ -66,6 +66,10 @@
|
||||
<string name="permlab_writeSecureSettings">modify CM secure system settings</string>
|
||||
<string name="permdesc_writeSecureSettings">Allows an app to modify CM secure system settings. Not for use by normal apps.</string>
|
||||
|
||||
<!-- Labels for the MANAGE_PERSISTENT_STORAGE permission. -->
|
||||
<string name="permlab_managePersistentStorage">manage persistent storage</string>
|
||||
<string name="permdesc_managePersistentStorage">Allows an app to read or write properties which may persist thru a factory reset.</string>
|
||||
|
||||
<!-- Label to show for a service that is running because it is observing the user's custom tiles. -->
|
||||
<string name="custom_tile_listener_binding_label">Custom tile listener</string>
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ import android.util.Log;
|
||||
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.IllegalArgumentException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -112,6 +114,11 @@ public final class CMHardwareManager {
|
||||
*/
|
||||
public static final int FEATURE_DISPLAY_MODES = 0x2000;
|
||||
|
||||
/**
|
||||
* Persistent storage
|
||||
*/
|
||||
public static final int FEATURE_PERSISTENT_STORAGE = 0x4000;
|
||||
|
||||
private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
|
||||
FEATURE_ADAPTIVE_BACKLIGHT,
|
||||
FEATURE_COLOR_ENHANCEMENT,
|
||||
@@ -412,6 +419,132 @@ public final class CMHardwareManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string to persistent storage, which persists thru factory reset
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @param value The UTF-8 encoded string to store
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean writePersistentString(String key, String value) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
return getService().writePersistentBytes(key,
|
||||
value == null ? null : value.getBytes("UTF-8"));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an integer to persistent storage, which persists thru factory reset
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @param value The integer to store
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean writePersistentInt(String key, int value) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
return getService().writePersistentBytes(key,
|
||||
ByteBuffer.allocate(4).putInt(value).array());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a byte array to persistent storage, which persists thru factory reset
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @param value The byte array to store, up to 4096 bytes
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean writePersistentBytes(String key, byte[] value) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
return getService().writePersistentBytes(key, value);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a string from persistent storage
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @return the stored UTF-8 encoded string, null if not found
|
||||
*/
|
||||
public String readPersistentString(String key) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
byte[] bytes = getService().readPersistentBytes(key);
|
||||
if (bytes != null) {
|
||||
return new String(bytes, "UTF-8");
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an integer from persistent storage
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @return the stored integer, zero if not found
|
||||
*/
|
||||
public int readPersistentInt(String key) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
byte[] bytes = getService().readPersistentBytes(key);
|
||||
if (bytes != null) {
|
||||
return ByteBuffer.wrap(bytes).getInt();
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte array from persistent storage
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @return the stored byte array, null if not found
|
||||
*/
|
||||
public byte[] readPersistentBytes(String key) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
return getService().readPersistentBytes(key);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Delete an object from persistent storage
|
||||
*
|
||||
* @param key String identifier for this item
|
||||
* @return true if an item was deleted
|
||||
*/
|
||||
public boolean deletePersistentObject(String key) {
|
||||
try {
|
||||
if (checkService()) {
|
||||
return getService().writePersistentBytes(key, null);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
|
||||
@@ -47,4 +47,7 @@ interface ICMHardwareService {
|
||||
DisplayMode getCurrentDisplayMode();
|
||||
DisplayMode getDefaultDisplayMode();
|
||||
boolean setDisplayMode(in DisplayMode mode, boolean makeDefault);
|
||||
|
||||
boolean writePersistentBytes(String key, in byte[] bytes);
|
||||
byte[] readPersistentBytes(String key);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<uses-permission android:name="cyanogenmod.permission.READ_MSIM_PHONE_STATE" />
|
||||
<uses-permission android:name="cyanogenmod.permission.HARDWARE_ABSTRACTION_ACCESS" />
|
||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_PROFILES" />
|
||||
<uses-permission android:name="cyanogenmod.permission.MANAGE_PERSISTENT_STORAGE" />
|
||||
|
||||
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
@@ -70,6 +71,7 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".customtiles.DummySettings"
|
||||
android:label="@string/app_name" />
|
||||
</application>
|
||||
|
||||
@@ -47,7 +47,8 @@ public class CMHardwareTest extends TestActivity {
|
||||
CMHardwareManager.FEATURE_TAP_TO_WAKE,
|
||||
CMHardwareManager.FEATURE_TOUCH_HOVERING,
|
||||
CMHardwareManager.FEATURE_AUTO_CONTRAST,
|
||||
CMHardwareManager.FEATURE_DISPLAY_MODES
|
||||
CMHardwareManager.FEATURE_DISPLAY_MODES,
|
||||
CMHardwareManager.FEATURE_PERSISTENT_STORAGE
|
||||
);
|
||||
|
||||
private static final List<Integer> BOOLEAN_FEATURES = Arrays.asList(
|
||||
@@ -127,6 +128,16 @@ public class CMHardwareTest extends TestActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean persistentStorageSupported() {
|
||||
if (mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE)) {
|
||||
return true;
|
||||
} else {
|
||||
Toast.makeText(CMHardwareTest.this, "Persistent storage not supported",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Test[] mTests = new Test[] {
|
||||
new Test("Test get supported features") {
|
||||
public void run() {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2015, The CyanogenMod 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 org.cyanogenmod.tests.hardware.unit;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import cyanogenmod.hardware.CMHardwareManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PersistentStorageTest extends AndroidTestCase {
|
||||
|
||||
private CMHardwareManager mHardwareManager;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mHardwareManager = CMHardwareManager.getInstance(mContext);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public boolean testPersistentString() {
|
||||
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
|
||||
|
||||
String testKey = UUID.randomUUID().toString();
|
||||
String testString = "IM IN UR STORAGE";
|
||||
|
||||
// write + read
|
||||
assertTrue(mHardwareManager.writePersistentString(testKey, testString));
|
||||
assertEquals(testString, mHardwareManager.readPersistentString(testKey));
|
||||
|
||||
// rewrite + read
|
||||
assertTrue(mHardwareManager.writePersistentString(testKey, testString + " AGAIN"));
|
||||
assertEquals(testString + " AGAIN", mHardwareManager.readPersistentString(testKey));
|
||||
|
||||
// erase + read
|
||||
assertTrue(mHardwareManager.deletePersistentObject(testKey));
|
||||
assertNull(mHardwareManager.readPersistentString(testKey));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public boolean testPersistentInteger() {
|
||||
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
|
||||
|
||||
String testKey = UUID.randomUUID().toString();
|
||||
int testInt = 49152;
|
||||
|
||||
// write + read
|
||||
assertTrue(mHardwareManager.writePersistentInt(testKey, testInt));
|
||||
assertEquals(testInt, mHardwareManager.readPersistentInt(testKey));
|
||||
|
||||
// rewrite + read
|
||||
assertTrue(mHardwareManager.writePersistentInt(testKey, testInt * 2));
|
||||
assertEquals(testInt * 2, mHardwareManager.readPersistentInt(testKey));
|
||||
|
||||
// erase + read
|
||||
assertTrue(mHardwareManager.deletePersistentObject(testKey));
|
||||
assertEquals(0, mHardwareManager.readPersistentInt(testKey));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public boolean testPersistentBytes() {
|
||||
assertTrue(mHardwareManager.isSupported(CMHardwareManager.FEATURE_PERSISTENT_STORAGE));
|
||||
|
||||
String testKey = UUID.randomUUID().toString();
|
||||
byte[] testArray = new byte[1024];
|
||||
byte[] testArray2 = new byte[4096];
|
||||
|
||||
new Random().nextBytes(testArray);
|
||||
new Random().nextBytes(testArray2);
|
||||
|
||||
// write + read
|
||||
assertTrue(mHardwareManager.writePersistentBytes(testKey, testArray));
|
||||
assertTrue(Arrays.equals(testArray, mHardwareManager.readPersistentBytes(testKey)));
|
||||
|
||||
// write + read
|
||||
assertTrue(mHardwareManager.writePersistentBytes(testKey, testArray2));
|
||||
assertTrue(Arrays.equals(testArray2, mHardwareManager.readPersistentBytes(testKey)));
|
||||
|
||||
// erase + read
|
||||
assertTrue(mHardwareManager.deletePersistentObject(testKey));
|
||||
assertNull(mHardwareManager.readPersistentBytes(testKey));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user