Add CMSettingsProvider and CMDatabaseHelper
issue-id: CYNGNOS-828 Change-Id: I01c08c0e432d6a941950a565e5ab6664664e2a7f
This commit is contained in:
parent
e949433c08
commit
0eb2999091
@ -163,7 +163,7 @@ LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:= build/tools/droiddoc/templates-sdk
|
|||||||
|
|
||||||
LOCAL_DROIDDOC_OPTIONS:= \
|
LOCAL_DROIDDOC_OPTIONS:= \
|
||||||
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_stubs_current_intermediates/src \
|
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_stubs_current_intermediates/src \
|
||||||
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.hardware:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.platform:org.cyanogenmod.platform \
|
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.hardware:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:org.cyanogenmod.platform \
|
||||||
-api $(INTERNAL_CM_PLATFORM_API_FILE) \
|
-api $(INTERNAL_CM_PLATFORM_API_FILE) \
|
||||||
-removedApi $(INTERNAL_CM_PLATFORM_REMOVED_API_FILE) \
|
-removedApi $(INTERNAL_CM_PLATFORM_REMOVED_API_FILE) \
|
||||||
-nodocs \
|
-nodocs \
|
||||||
@ -192,7 +192,7 @@ LOCAL_MODULE := cm-system-api-stubs
|
|||||||
|
|
||||||
LOCAL_DROIDDOC_OPTIONS:=\
|
LOCAL_DROIDDOC_OPTIONS:=\
|
||||||
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_system_stubs_current_intermediates/src \
|
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/cmsdk_system_stubs_current_intermediates/src \
|
||||||
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.hardware:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.platform:org.cyanogenmod.platform \
|
-stubpackages cyanogenmod.alarmclock:cyanogenmod.app:cyanogenmod.hardware:cyanogenmod.os:cyanogenmod.profiles:cyanogenmod.providers:cyanogenmod.platform:org.cyanogenmod.platform \
|
||||||
-showAnnotation android.annotation.SystemApi \
|
-showAnnotation android.annotation.SystemApi \
|
||||||
-api $(INTERNAL_CM_PLATFORM_SYSTEM_API_FILE) \
|
-api $(INTERNAL_CM_PLATFORM_SYSTEM_API_FILE) \
|
||||||
-removedApi $(INTERNAL_CM_PLATFORM_SYSTEM_REMOVED_API_FILE) \
|
-removedApi $(INTERNAL_CM_PLATFORM_SYSTEM_REMOVED_API_FILE) \
|
||||||
|
@ -442,6 +442,8 @@ package cyanogenmod.platform {
|
|||||||
field public static final java.lang.String MODIFY_SOUND_SETTINGS = "cyanogenmod.permission.MODIFY_SOUND_SETTINGS";
|
field public static final java.lang.String MODIFY_SOUND_SETTINGS = "cyanogenmod.permission.MODIFY_SOUND_SETTINGS";
|
||||||
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
||||||
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
||||||
|
field public static final java.lang.String WRITE_SECURE_SETTINGS = "cyanogenmod.permission.WRITE_SECURE_SETTINGS";
|
||||||
|
field public static final java.lang.String WRITE_SETTINGS = "cyanogenmod.permission.WRITE_SETTINGS";
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class R {
|
public final class R {
|
||||||
@ -566,3 +568,68 @@ package cyanogenmod.profiles {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package cyanogenmod.providers {
|
||||||
|
|
||||||
|
public final class CMSettings {
|
||||||
|
ctor public CMSettings();
|
||||||
|
field public static final java.lang.String AUTHORITY = "cmsettings";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CMSettings.CMSettingNotFoundException extends android.util.AndroidException {
|
||||||
|
ctor public CMSettings.CMSettingNotFoundException(java.lang.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.Global extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.Global();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_global_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.Secure extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.Secure();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String NAME_THEME_CONFIG = "name_theme_config";
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_secure_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.System extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.System();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_system_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,19 @@
|
|||||||
android:description="@string/permdesc_useHardwareFramework"
|
android:description="@string/permdesc_useHardwareFramework"
|
||||||
android:protectionLevel="system|signature" />
|
android:protectionLevel="system|signature" />
|
||||||
|
|
||||||
|
<!-- Allows an application to write to CM system settings -->
|
||||||
|
<permission android:name="cyanogenmod.permission.WRITE_SETTINGS"
|
||||||
|
android:label="@string/permlab_writeSettings"
|
||||||
|
android:description="@string/permdesc_writeSettings"
|
||||||
|
android:protectionLevel="normal" />
|
||||||
|
|
||||||
|
<!-- Allows an application to write to secure CM system settings.
|
||||||
|
<p>Not for use by third-party applications. -->
|
||||||
|
<permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS"
|
||||||
|
android:label="@string/permlab_writeSecureSettings"
|
||||||
|
android:description="@string/permdesc_writeSecureSettings"
|
||||||
|
android:protectionLevel="signature|system|development" />
|
||||||
|
|
||||||
<application android:process="system"
|
<application android:process="system"
|
||||||
android:persistent="true"
|
android:persistent="true"
|
||||||
android:hasCode="false"
|
android:hasCode="false"
|
||||||
|
@ -42,6 +42,13 @@
|
|||||||
<string name="permlab_useHardwareFramework">use hardware framework</string>
|
<string name="permlab_useHardwareFramework">use hardware framework</string>
|
||||||
<string name="permdesc_useHardwareFramework">Allows an app access to the CM hardware framework.</string>
|
<string name="permdesc_useHardwareFramework">Allows an app access to the CM hardware framework.</string>
|
||||||
|
|
||||||
|
<!-- Labels for the WRITE_SETTINGS permission -->
|
||||||
|
<string name="permlab_writeSettings">modify CM system settings</string>
|
||||||
|
<string name="permdesc_writeSettings">Allows an app to modify CM system settings.</string>
|
||||||
|
|
||||||
|
<!-- Labels for the WRITE_SECURE_SETTINGS permission -->
|
||||||
|
<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>
|
||||||
|
|
||||||
<!-- Label to show for a service that is running because it is observing the user's custom tiles. -->
|
<!-- 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>
|
<string name="custom_tile_listener_binding_label">Custom tile listener</string>
|
||||||
|
36
packages/CMSettingsProvider/Android.mk
Normal file
36
packages/CMSettingsProvider/Android.mk
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
src_dir := src
|
||||||
|
res_dir := res
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dir))
|
||||||
|
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := CMSettingsProvider
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
LOCAL_PRIVILEGED_MODULE := true
|
||||||
|
|
||||||
|
LOCAL_JAVA_LIBRARIES := \
|
||||||
|
org.cyanogenmod.platform.sdk
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
|
|
||||||
|
########################
|
||||||
|
include $(call all-makefiles-under,$(LOCAL_PATH))
|
42
packages/CMSettingsProvider/AndroidManifest.xml
Normal file
42
packages/CMSettingsProvider/AndroidManifest.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.cyanogenmod.cmsettings"
|
||||||
|
coreApp="true"
|
||||||
|
android:sharedUserId="android.uid.system">
|
||||||
|
<!-- It is necessary to be a system app in order to update table versions in SystemProperties for
|
||||||
|
CMSettings to know whether or not the client side cache is up to date. It is also necessary
|
||||||
|
to run in the system process in order to start the content provider prior to running migration
|
||||||
|
for CM settings on user starting -->
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
||||||
|
|
||||||
|
<application android:icon="@drawable/icon"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:process="system"
|
||||||
|
android:killAfterRestore="false"
|
||||||
|
android:allowClearUserData="false"
|
||||||
|
android:enabled="true">
|
||||||
|
|
||||||
|
<provider android:name="CMSettingsProvider" android:authorities="cmsettings"
|
||||||
|
android:multiprocess="false"
|
||||||
|
android:exported="true"
|
||||||
|
android:writePermission="cyanogenmod.permission.WRITE_SETTINGS"
|
||||||
|
android:singleUser="true"
|
||||||
|
android:initOrder="100" />
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</manifest>
|
BIN
packages/CMSettingsProvider/res/drawable/icon.png
Normal file
BIN
packages/CMSettingsProvider/res/drawable/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 990 B |
19
packages/CMSettingsProvider/res/values/strings.xml
Normal file
19
packages/CMSettingsProvider/res/values/strings.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2014-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.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">CMSettingsProvider</string>
|
||||||
|
</resources>
|
@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
* 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.cmsettings;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CMDatabaseHelper allows creation of a database to store CM specific settings for a user
|
||||||
|
* in System, Secure, and Global tables.
|
||||||
|
*/
|
||||||
|
public class CMDatabaseHelper extends SQLiteOpenHelper{
|
||||||
|
private static final String TAG = "CMDatabaseHelper";
|
||||||
|
private static final boolean LOCAL_LOGV = false;
|
||||||
|
|
||||||
|
private static final String DATABASE_NAME = "cmsettings.db";
|
||||||
|
private static final int DATABASE_VERSION = 1;
|
||||||
|
|
||||||
|
static class CMTableNames {
|
||||||
|
static final String TABLE_SYSTEM = "system";
|
||||||
|
static final String TABLE_SECURE = "secure";
|
||||||
|
static final String TABLE_GLOBAL = "global";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String CREATE_TABLE_SQL_FORMAT = "CREATE TABLE %s (" +
|
||||||
|
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||||
|
"name TEXT UNIQUE ON CONFLICT REPLACE," +
|
||||||
|
"value TEXT" +
|
||||||
|
");)";
|
||||||
|
|
||||||
|
private static final String CREATE_INDEX_SQL_FORMAT = "CREATE INDEX %sIndex%d ON %s (name);";
|
||||||
|
|
||||||
|
private int mUserHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the appropriate database path for a specific user
|
||||||
|
* @param userId The database path for this user
|
||||||
|
* @return The database path string
|
||||||
|
*/
|
||||||
|
static String dbNameForUser(final int userId) {
|
||||||
|
// The owner gets the unadorned db name;
|
||||||
|
if (userId == UserHandle.USER_OWNER) {
|
||||||
|
return DATABASE_NAME;
|
||||||
|
} else {
|
||||||
|
// Place the database in the user-specific data tree so that it's
|
||||||
|
// cleaned up automatically when the user is deleted.
|
||||||
|
File databaseFile = new File(
|
||||||
|
Environment.getUserSystemDirectory(userId), DATABASE_NAME);
|
||||||
|
return databaseFile.getPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link CMDatabaseHelper}
|
||||||
|
* @param context
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
public CMDatabaseHelper(Context context, int userId) {
|
||||||
|
super(context, dbNameForUser(userId), null, DATABASE_VERSION);
|
||||||
|
mUserHandle = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates System, Secure, and Global tables in the specified {@link SQLiteDatabase}
|
||||||
|
* @param db The database.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
createDbTable(db, CMTableNames.TABLE_SYSTEM);
|
||||||
|
createDbTable(db, CMTableNames.TABLE_SECURE);
|
||||||
|
|
||||||
|
if (mUserHandle == UserHandle.USER_OWNER) {
|
||||||
|
createDbTable(db, CMTableNames.TABLE_GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
|
||||||
|
if (LOCAL_LOGV) Log.v(TAG, "Successfully created tables for cm settings db");
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a table and index for the specified database and table name
|
||||||
|
* @param db
|
||||||
|
* @param tableName
|
||||||
|
*/
|
||||||
|
private void createDbTable(SQLiteDatabase db, String tableName) {
|
||||||
|
if (LOCAL_LOGV) Log.v(TAG, "Creating table and index for: " + tableName);
|
||||||
|
|
||||||
|
String createTableSql = String.format(CREATE_TABLE_SQL_FORMAT, tableName);
|
||||||
|
db.execSQL(createTableSql);
|
||||||
|
|
||||||
|
String createIndexSql = String.format(CREATE_INDEX_SQL_FORMAT, tableName, 1, tableName);
|
||||||
|
db.execSQL(createIndexSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,451 @@
|
|||||||
|
/**
|
||||||
|
* 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.cmsettings;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.UriMatcher;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.database.AbstractCursor;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteCantOpenDatabaseException;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import cyanogenmod.providers.CMSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CMSettingsProvider serves as a {@link ContentProvider} for CM specific settings
|
||||||
|
*/
|
||||||
|
public class CMSettingsProvider extends ContentProvider {
|
||||||
|
private static final String TAG = "CMSettingsProvider";
|
||||||
|
private static final boolean LOCAL_LOGV = false;
|
||||||
|
|
||||||
|
private static final boolean USER_CHECK_THROWS = true;
|
||||||
|
|
||||||
|
// Each defined user has their own settings
|
||||||
|
protected final SparseArray<CMDatabaseHelper> mDbHelpers = new SparseArray<CMDatabaseHelper>();
|
||||||
|
|
||||||
|
private static final int SYSTEM = 1;
|
||||||
|
private static final int SECURE = 2;
|
||||||
|
private static final int GLOBAL = 3;
|
||||||
|
|
||||||
|
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||||
|
|
||||||
|
static {
|
||||||
|
sUriMatcher.addURI(CMSettings.AUTHORITY, CMDatabaseHelper.CMTableNames.TABLE_SYSTEM,
|
||||||
|
SYSTEM);
|
||||||
|
sUriMatcher.addURI(CMSettings.AUTHORITY, CMDatabaseHelper.CMTableNames.TABLE_SECURE,
|
||||||
|
SECURE);
|
||||||
|
sUriMatcher.addURI(CMSettings.AUTHORITY, CMDatabaseHelper.CMTableNames.TABLE_GLOBAL,
|
||||||
|
GLOBAL);
|
||||||
|
// TODO add other paths for getting specific items
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserManager mUserManager;
|
||||||
|
private Uri.Builder mUriBuilder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreate() {
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, "Creating CMSettingsProvider");
|
||||||
|
|
||||||
|
mUserManager = UserManager.get(getContext());
|
||||||
|
|
||||||
|
establishDbTracking(UserHandle.USER_OWNER);
|
||||||
|
|
||||||
|
mUriBuilder = new Uri.Builder();
|
||||||
|
mUriBuilder.scheme(ContentResolver.SCHEME_CONTENT);
|
||||||
|
mUriBuilder.authority(CMSettings.AUTHORITY);
|
||||||
|
|
||||||
|
// TODO Add migration for cm settings
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
|
||||||
|
String sortOrder) {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new IllegalArgumentException("Uri cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
String tableName = getTableNameFromUri(uri);
|
||||||
|
checkWritePermissions(tableName);
|
||||||
|
|
||||||
|
int callingUserId = UserHandle.getCallingUserId();
|
||||||
|
CMDatabaseHelper dbHelper = getOrEstablishDatabase(getUserIdForTable(tableName,
|
||||||
|
callingUserId));
|
||||||
|
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||||
|
|
||||||
|
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||||
|
queryBuilder.setTables(tableName);
|
||||||
|
|
||||||
|
Cursor returnCursor = queryBuilder.query(db, projection, selection, selectionArgs, null,
|
||||||
|
null, sortOrder);
|
||||||
|
// the default Cursor interface does not support per-user observation
|
||||||
|
try {
|
||||||
|
AbstractCursor abstractCursor = (AbstractCursor) returnCursor;
|
||||||
|
abstractCursor.setNotificationUri(getContext().getContentResolver(), uri,
|
||||||
|
callingUserId);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// details of the concrete Cursor implementation have changed and this code has
|
||||||
|
// not been updated to match -- complain and fail hard.
|
||||||
|
Log.wtf(TAG, "Incompatible cursor derivation");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
// TODO: Implement
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int bulkInsert(Uri uri, ContentValues[] values) {
|
||||||
|
return bulkInsertForUser(UserHandle.getCallingUserId(), uri, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a bulk insert for a specific user.
|
||||||
|
* @param userId The user id to perform the bulk insert for.
|
||||||
|
* @param uri The content:// URI of the insertion request.
|
||||||
|
* @param values An array of sets of column_name/value pairs to add to the database.
|
||||||
|
* This must not be {@code null}.
|
||||||
|
* @return Number of rows inserted.
|
||||||
|
*/
|
||||||
|
int bulkInsertForUser(int userId, Uri uri, ContentValues[] values) {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new IllegalArgumentException("Uri cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values == null) {
|
||||||
|
throw new IllegalArgumentException("ContentValues cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
int numRowsAffected = 0;
|
||||||
|
|
||||||
|
String tableName = getTableNameFromUri(uri);
|
||||||
|
checkWritePermissions(tableName);
|
||||||
|
|
||||||
|
CMDatabaseHelper dbHelper = getOrEstablishDatabase(getUserIdForTable(tableName, userId));
|
||||||
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
|
|
||||||
|
db.beginTransaction();
|
||||||
|
try {
|
||||||
|
for (ContentValues value : values) {
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long rowId = db.insert(tableName, null, value);
|
||||||
|
|
||||||
|
if (rowId >= 0) {
|
||||||
|
numRowsAffected++;
|
||||||
|
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, tableName + " <- " + values);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numRowsAffected > 0) {
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
notifyChange(uri, tableName, userId);
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, tableName + ": " + numRowsAffected + " row(s) inserted");
|
||||||
|
}
|
||||||
|
|
||||||
|
return numRowsAffected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new IllegalArgumentException("Uri cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values == null) {
|
||||||
|
throw new IllegalArgumentException("ContentValues cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
String tableName = getTableNameFromUri(uri);
|
||||||
|
checkWritePermissions(tableName);
|
||||||
|
|
||||||
|
int callingUserId = UserHandle.getCallingUserId();
|
||||||
|
CMDatabaseHelper dbHelper = getOrEstablishDatabase(getUserIdForTable(tableName,
|
||||||
|
callingUserId));
|
||||||
|
|
||||||
|
long rowId = -1;
|
||||||
|
|
||||||
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
|
try {
|
||||||
|
rowId = db.insert(tableName, null, values);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri returnUri = null;
|
||||||
|
if (rowId != -1) {
|
||||||
|
returnUri = ContentUris.withAppendedId(uri, rowId);
|
||||||
|
notifyChange(returnUri, tableName, callingUserId);
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, "Inserted row id: " + rowId + " into tableName: " +
|
||||||
|
tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new IllegalArgumentException("Uri cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
int numRowsAffected = 0;
|
||||||
|
|
||||||
|
// Allow only selection by key; a null/empty selection string will cause all rows in the
|
||||||
|
// table to be deleted
|
||||||
|
if (!TextUtils.isEmpty(selection) && selectionArgs.length > 0) {
|
||||||
|
String tableName = getTableNameFromUri(uri);
|
||||||
|
checkWritePermissions(tableName);
|
||||||
|
|
||||||
|
int callingUserId = UserHandle.getCallingUserId();
|
||||||
|
CMDatabaseHelper dbHelper = getOrEstablishDatabase(getUserIdForTable(tableName,
|
||||||
|
callingUserId));
|
||||||
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
numRowsAffected = db.delete(tableName, selection, selectionArgs);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numRowsAffected > 0) {
|
||||||
|
notifyChange(uri, tableName, callingUserId);
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, tableName + ": " + numRowsAffected + " row(s) deleted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numRowsAffected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||||
|
if (uri == null) {
|
||||||
|
throw new IllegalArgumentException("Uri cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values == null) {
|
||||||
|
throw new IllegalArgumentException("ContentValues cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
String tableName = getTableNameFromUri(uri);
|
||||||
|
checkWritePermissions(tableName);
|
||||||
|
|
||||||
|
int callingUserId = UserHandle.getCallingUserId();
|
||||||
|
CMDatabaseHelper dbHelper = getOrEstablishDatabase(getUserIdForTable(tableName,
|
||||||
|
callingUserId));
|
||||||
|
|
||||||
|
int numRowsAffected = 0;
|
||||||
|
|
||||||
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
|
try {
|
||||||
|
numRowsAffected = db.update(tableName, values, selection, selectionArgs);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numRowsAffected > 0) {
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
if (LOCAL_LOGV) Log.d(TAG, tableName + ": " + numRowsAffected + " row(s) updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
return numRowsAffected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to get a {@link CMDatabaseHelper} for the specified user and if it does not exist, a
|
||||||
|
* new instance of {@link CMDatabaseHelper} is created for the specified user and returned.
|
||||||
|
* @param callingUser
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private CMDatabaseHelper getOrEstablishDatabase(int callingUser) {
|
||||||
|
if (callingUser >= android.os.Process.SYSTEM_UID) {
|
||||||
|
if (USER_CHECK_THROWS) {
|
||||||
|
throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
|
||||||
|
} else {
|
||||||
|
Log.wtf(TAG, "Establish db for uid rather than user: " + callingUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long oldId = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
CMDatabaseHelper dbHelper;
|
||||||
|
synchronized (this) {
|
||||||
|
dbHelper = mDbHelpers.get(callingUser);
|
||||||
|
}
|
||||||
|
if (null == dbHelper) {
|
||||||
|
establishDbTracking(callingUser);
|
||||||
|
synchronized (this) {
|
||||||
|
dbHelper = mDbHelpers.get(callingUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dbHelper;
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(oldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a {@link CMDatabaseHelper} exists for a user and if it doesn't, a new helper is
|
||||||
|
* created and added to the list of tracked database helpers
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
private void establishDbTracking(int userId) {
|
||||||
|
CMDatabaseHelper dbHelper;
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
dbHelper = mDbHelpers.get(userId);
|
||||||
|
if (LOCAL_LOGV) {
|
||||||
|
Log.i(TAG, "Checking cm settings db helper for user " + userId);
|
||||||
|
}
|
||||||
|
if (dbHelper == null) {
|
||||||
|
if (LOCAL_LOGV) {
|
||||||
|
Log.i(TAG, "Installing new cm settings db helper for user " + userId);
|
||||||
|
}
|
||||||
|
dbHelper = new CMDatabaseHelper(getContext(), userId);
|
||||||
|
mDbHelpers.append(userId, dbHelper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialization of the db *outside* the locks. It's possible that racing
|
||||||
|
// threads might wind up here, the second having read the cache entries
|
||||||
|
// written by the first, but that's benign: the SQLite helper implementation
|
||||||
|
// manages concurrency itself, and it's important that we not run the db
|
||||||
|
// initialization with any of our own locks held, so we're fine.
|
||||||
|
SQLiteDatabase db = null;
|
||||||
|
try {
|
||||||
|
db = dbHelper.getWritableDatabase();
|
||||||
|
} catch (SQLiteCantOpenDatabaseException ex){
|
||||||
|
Log.e(TAG, "Unable to open writable database for user: " + userId, ex);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure the caller has permission to write this data.
|
||||||
|
* @param tableName supplied by the caller
|
||||||
|
* @throws SecurityException if the caller is forbidden to write.
|
||||||
|
*/
|
||||||
|
private void checkWritePermissions(String tableName) {
|
||||||
|
if ((CMDatabaseHelper.CMTableNames.TABLE_SECURE.equals(tableName) ||
|
||||||
|
CMDatabaseHelper.CMTableNames.TABLE_GLOBAL.equals(tableName)) &&
|
||||||
|
getContext().checkCallingOrSelfPermission(
|
||||||
|
cyanogenmod.platform.Manifest.permission.WRITE_SECURE_SETTINGS) !=
|
||||||
|
PackageManager.PERMISSION_GRANTED) {
|
||||||
|
throw new SecurityException(
|
||||||
|
String.format("Permission denial: writing to cm secure settings requires %1$s",
|
||||||
|
cyanogenmod.platform.Manifest.permission.WRITE_SECURE_SETTINGS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilizes an {@link UriMatcher} to check for a valid combination of scheme, authority, and
|
||||||
|
* path and returns the corresponding table name
|
||||||
|
* @param uri
|
||||||
|
* @return Table name
|
||||||
|
*/
|
||||||
|
private String getTableNameFromUri(Uri uri) {
|
||||||
|
int code = sUriMatcher.match(uri);
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case SYSTEM:
|
||||||
|
return CMDatabaseHelper.CMTableNames.TABLE_SYSTEM;
|
||||||
|
case SECURE:
|
||||||
|
return CMDatabaseHelper.CMTableNames.TABLE_SECURE;
|
||||||
|
case GLOBAL:
|
||||||
|
return CMDatabaseHelper.CMTableNames.TABLE_GLOBAL;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid uri: " + uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the table is Global, the owner's user id is returned. Otherwise, the original user id
|
||||||
|
* is returned.
|
||||||
|
* @param tableName
|
||||||
|
* @param userId
|
||||||
|
* @return User id
|
||||||
|
*/
|
||||||
|
private int getUserIdForTable(String tableName, int userId) {
|
||||||
|
return CMDatabaseHelper.CMTableNames.TABLE_GLOBAL.equals(tableName) ?
|
||||||
|
UserHandle.USER_OWNER : userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify setting version for an updated table before notifying of change. The
|
||||||
|
* {@link CMSettings} class uses these to provide client-side caches.
|
||||||
|
* @param uri to send notifications for
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
private void notifyChange(Uri uri, String tableName, int userId) {
|
||||||
|
String property = null;
|
||||||
|
final boolean isGlobal = tableName.equals(CMDatabaseHelper.CMTableNames.TABLE_GLOBAL);
|
||||||
|
if (tableName.equals(CMDatabaseHelper.CMTableNames.TABLE_SYSTEM)) {
|
||||||
|
property = CMSettings.System.SYS_PROP_CM_SETTING_VERSION;
|
||||||
|
} else if (tableName.equals(CMDatabaseHelper.CMTableNames.TABLE_SECURE)) {
|
||||||
|
property = CMSettings.Secure.SYS_PROP_CM_SETTING_VERSION;
|
||||||
|
} else if (isGlobal) {
|
||||||
|
property = CMSettings.Global.SYS_PROP_CM_SETTING_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property != null) {
|
||||||
|
long version = SystemProperties.getLong(property, 0) + 1;
|
||||||
|
if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
|
||||||
|
SystemProperties.set(property, Long.toString(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
final int notifyTarget = isGlobal ? UserHandle.USER_ALL : userId;
|
||||||
|
final long oldId = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
getContext().getContentResolver().notifyChange(uri, null, true, notifyTarget);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(oldId);
|
||||||
|
}
|
||||||
|
if (LOCAL_LOGV) Log.v(TAG, "notifying for " + notifyTarget + ": " + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add caching
|
||||||
|
}
|
34
packages/CMSettingsProvider/tests/Android.mk
Normal file
34
packages/CMSettingsProvider/tests/Android.mk
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := CMSettingsProviderTests
|
||||||
|
LOCAL_INSTRUMENTATION_FOR := CMSettingsProvider
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
|
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||||
|
LOCAL_PROGUARD_ENABLED := disabled
|
||||||
|
|
||||||
|
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||||
|
org.cyanogenmod.platform.sdk
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
30
packages/CMSettingsProvider/tests/AndroidManifest.xml
Normal file
30
packages/CMSettingsProvider/tests/AndroidManifest.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.cyanogenmod.cmsettings.tests">
|
||||||
|
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS"/>
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS"/>
|
||||||
|
|
||||||
|
<instrumentation
|
||||||
|
android:name="android.test.InstrumentationTestRunner"
|
||||||
|
android:targetPackage="org.cyanogenmod.cmsettings.tests"
|
||||||
|
android:label="CM Settings Provider Tests" />
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<uses-library android:name="android.test.runner" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* 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.cmsettings.tests;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
import android.test.suitebuilder.annotation.MediumTest;
|
||||||
|
import android.util.Log;
|
||||||
|
import cyanogenmod.providers.CMSettings;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class CMSettingsProviderTest extends AndroidTestCase {
|
||||||
|
private static final String TAG = "CMSettingsProviderTest";
|
||||||
|
|
||||||
|
private static final LinkedHashMap<String, String> mMap = new LinkedHashMap<String, String>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
mMap.put("testKey1", "value1");
|
||||||
|
mMap.put("testKey2", "value2");
|
||||||
|
mMap.put("testKey3", "value3");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String[] PROJECTIONS = new String[] { "name", "value" };
|
||||||
|
|
||||||
|
private ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() {
|
||||||
|
mContentResolver = mContext.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
public void testBulkInsertSuccess() {
|
||||||
|
Log.d(TAG, "Starting bulk insert test");
|
||||||
|
|
||||||
|
ContentValues[] contentValues = new ContentValues[mMap.size()];
|
||||||
|
int count = 0;
|
||||||
|
for (Map.Entry<String, String> kVPair : mMap.entrySet()) {
|
||||||
|
ContentValues contentValue = new ContentValues();
|
||||||
|
contentValue.put(PROJECTIONS[0], kVPair.getKey());
|
||||||
|
contentValue.put(PROJECTIONS[1], kVPair.getValue());
|
||||||
|
contentValues[count++] = contentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
testBulkInsertForUri(CMSettings.System.CONTENT_URI, contentValues);
|
||||||
|
testBulkInsertForUri(CMSettings.Secure.CONTENT_URI, contentValues);
|
||||||
|
testBulkInsertForUri(CMSettings.Global.CONTENT_URI, contentValues);
|
||||||
|
|
||||||
|
Log.d(TAG, "Finished bulk insert test");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testBulkInsertForUri(Uri uri, ContentValues[] contentValues) {
|
||||||
|
int rowsInserted = mContentResolver.bulkInsert(uri, contentValues);
|
||||||
|
assertEquals(mMap.size(), rowsInserted);
|
||||||
|
|
||||||
|
Cursor queryCursor = mContentResolver.query(uri, PROJECTIONS, null, null, null);
|
||||||
|
try {
|
||||||
|
while (queryCursor.moveToNext()) {
|
||||||
|
assertEquals(PROJECTIONS.length, queryCursor.getColumnCount());
|
||||||
|
|
||||||
|
String actualKey = queryCursor.getString(0);
|
||||||
|
assertTrue(mMap.containsKey(actualKey));
|
||||||
|
|
||||||
|
assertEquals(mMap.get(actualKey), queryCursor.getString(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Test successful");
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
queryCursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Find a better way to cleanup database/use ProviderTestCase2 without process crash
|
||||||
|
for (String key : mMap.keySet()) {
|
||||||
|
mContentResolver.delete(uri, PROJECTIONS[0] + " = ?", new String[]{ key });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
public void testInsertUpdateDeleteSuccess() {
|
||||||
|
Log.d(TAG, "Starting insert/update/delete test");
|
||||||
|
|
||||||
|
testInsertUpdateDeleteForUri(CMSettings.System.CONTENT_URI);
|
||||||
|
testInsertUpdateDeleteForUri(CMSettings.Secure.CONTENT_URI);
|
||||||
|
testInsertUpdateDeleteForUri(CMSettings.Global.CONTENT_URI);
|
||||||
|
|
||||||
|
Log.d(TAG, "Finished insert/update/delete test");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testInsertUpdateDeleteForUri(Uri uri) {
|
||||||
|
String key1 = "testKey1";
|
||||||
|
String value1 = "value1";
|
||||||
|
String value2 = "value2";
|
||||||
|
|
||||||
|
// test insert
|
||||||
|
ContentValues contentValue = new ContentValues();
|
||||||
|
contentValue.put(PROJECTIONS[0], key1);
|
||||||
|
contentValue.put(PROJECTIONS[1], value1);
|
||||||
|
|
||||||
|
mContentResolver.insert(uri, contentValue);
|
||||||
|
|
||||||
|
// check insert
|
||||||
|
Cursor queryCursor = mContentResolver.query(uri, PROJECTIONS, null, null, null);
|
||||||
|
assertEquals(1, queryCursor.getCount());
|
||||||
|
|
||||||
|
queryCursor.moveToNext();
|
||||||
|
assertEquals(PROJECTIONS.length, queryCursor.getColumnCount());
|
||||||
|
|
||||||
|
String actualKey = queryCursor.getString(0);
|
||||||
|
assertEquals(key1, actualKey);
|
||||||
|
assertEquals(value1, queryCursor.getString(1));
|
||||||
|
|
||||||
|
// test update
|
||||||
|
contentValue.clear();
|
||||||
|
contentValue.put(PROJECTIONS[1], value2);
|
||||||
|
|
||||||
|
int rowsAffected = mContentResolver.update(uri, contentValue, PROJECTIONS[0] + " = ?",
|
||||||
|
new String[]{key1});
|
||||||
|
assertEquals(1, rowsAffected);
|
||||||
|
|
||||||
|
// check update
|
||||||
|
queryCursor = mContentResolver.query(uri, PROJECTIONS, null, null, null);
|
||||||
|
assertEquals(1, queryCursor.getCount());
|
||||||
|
|
||||||
|
queryCursor.moveToNext();
|
||||||
|
assertEquals(PROJECTIONS.length, queryCursor.getColumnCount());
|
||||||
|
|
||||||
|
actualKey = queryCursor.getString(0);
|
||||||
|
assertEquals(key1, actualKey);
|
||||||
|
assertEquals(value2, queryCursor.getString(1));
|
||||||
|
|
||||||
|
// test delete
|
||||||
|
rowsAffected = mContentResolver.delete(uri, PROJECTIONS[0] + " = ?", new String[]{key1});
|
||||||
|
assertEquals(1, rowsAffected);
|
||||||
|
|
||||||
|
// check delete
|
||||||
|
queryCursor = mContentResolver.query(uri, PROJECTIONS, null, null, null);
|
||||||
|
assertEquals(0, queryCursor.getCount());
|
||||||
|
}
|
||||||
|
}
|
1044
src/java/cyanogenmod/providers/CMSettings.java
Normal file
1044
src/java/cyanogenmod/providers/CMSettings.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -442,6 +442,8 @@ package cyanogenmod.platform {
|
|||||||
field public static final java.lang.String MODIFY_SOUND_SETTINGS = "cyanogenmod.permission.MODIFY_SOUND_SETTINGS";
|
field public static final java.lang.String MODIFY_SOUND_SETTINGS = "cyanogenmod.permission.MODIFY_SOUND_SETTINGS";
|
||||||
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
field public static final java.lang.String PUBLISH_CUSTOM_TILE = "cyanogenmod.permission.PUBLISH_CUSTOM_TILE";
|
||||||
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
field public static final java.lang.String READ_MSIM_PHONE_STATE = "cyanogenmod.permission.READ_MSIM_PHONE_STATE";
|
||||||
|
field public static final java.lang.String WRITE_SECURE_SETTINGS = "cyanogenmod.permission.WRITE_SECURE_SETTINGS";
|
||||||
|
field public static final java.lang.String WRITE_SETTINGS = "cyanogenmod.permission.WRITE_SETTINGS";
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class R {
|
public final class R {
|
||||||
@ -566,3 +568,68 @@ package cyanogenmod.profiles {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
package cyanogenmod.providers {
|
||||||
|
|
||||||
|
public final class CMSettings {
|
||||||
|
ctor public CMSettings();
|
||||||
|
field public static final java.lang.String AUTHORITY = "cmsettings";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CMSettings.CMSettingNotFoundException extends android.util.AndroidException {
|
||||||
|
ctor public CMSettings.CMSettingNotFoundException(java.lang.String);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.Global extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.Global();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_global_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.Secure extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.Secure();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String NAME_THEME_CONFIG = "name_theme_config";
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_secure_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class CMSettings.System extends android.provider.Settings.NameValueTable {
|
||||||
|
ctor public CMSettings.System();
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static float getFloat(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static int getInt(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static long getLong(android.content.ContentResolver, java.lang.String) throws cyanogenmod.providers.CMSettings.CMSettingNotFoundException;
|
||||||
|
method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
|
||||||
|
method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
|
||||||
|
method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
|
||||||
|
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
|
||||||
|
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
|
||||||
|
field public static final android.net.Uri CONTENT_URI;
|
||||||
|
field public static final java.lang.String SYS_PROP_CM_SETTING_VERSION = "sys.cm_settings_system_version";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
<uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />
|
<uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS"/>
|
||||||
|
<uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS"/>
|
||||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_NETWORK_SETTINGS" />
|
<uses-permission android:name="cyanogenmod.permission.MODIFY_NETWORK_SETTINGS" />
|
||||||
<uses-permission android:name="cyanogenmod.permission.MODIFY_SOUND_SETTINGS" />
|
<uses-permission android:name="cyanogenmod.permission.MODIFY_SOUND_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.REBOOT" />
|
<uses-permission android:name="android.permission.REBOOT" />
|
||||||
|
118
tests/src/org/cyanogenmod/tests/providers/CMSettingsTest.java
Normal file
118
tests/src/org/cyanogenmod/tests/providers/CMSettingsTest.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* 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.providers;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
import android.test.suitebuilder.annotation.MediumTest;
|
||||||
|
import cyanogenmod.providers.CMSettings;
|
||||||
|
|
||||||
|
public class CMSettingsTest extends AndroidTestCase{
|
||||||
|
private ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() {
|
||||||
|
mContentResolver = getContext().getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
public void testPutAndGetSystemString() {
|
||||||
|
final String key = "key";
|
||||||
|
|
||||||
|
// put
|
||||||
|
final String expectedValue = "systemTestValue1";
|
||||||
|
boolean isPutSuccessful = CMSettings.System.putString(mContentResolver, key, expectedValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
String actualValue = CMSettings.System.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedValue, actualValue);
|
||||||
|
|
||||||
|
// replace
|
||||||
|
final String expectedReplaceValue = "systemTestValue2";
|
||||||
|
isPutSuccessful = CMSettings.System.putString(mContentResolver, key, expectedReplaceValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
actualValue = CMSettings.System.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedReplaceValue, actualValue);
|
||||||
|
|
||||||
|
// delete to clean up
|
||||||
|
int rowsAffected = mContentResolver.delete(CMSettings.System.CONTENT_URI, Settings.NameValueTable.NAME + " = ?",
|
||||||
|
new String[]{ key });
|
||||||
|
assertEquals(1, rowsAffected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
public void testPutAndGetSecureString() {
|
||||||
|
final String key = "key";
|
||||||
|
|
||||||
|
// put
|
||||||
|
final String expectedValue = "secureTestValue1";
|
||||||
|
boolean isPutSuccessful = CMSettings.Secure.putString(mContentResolver, key, expectedValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
String actualValue = CMSettings.Secure.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedValue, actualValue);
|
||||||
|
|
||||||
|
// replace
|
||||||
|
final String expectedReplaceValue = "secureTestValue2";
|
||||||
|
isPutSuccessful = CMSettings.Secure.putString(mContentResolver, key, expectedReplaceValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
actualValue = CMSettings.Secure.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedReplaceValue, actualValue);
|
||||||
|
|
||||||
|
// delete to clean up
|
||||||
|
int rowsAffected = mContentResolver.delete(CMSettings.Secure.CONTENT_URI, Settings.NameValueTable.NAME + " = ?",
|
||||||
|
new String[]{ key });
|
||||||
|
assertEquals(1, rowsAffected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
public void testPutAndGetGlobalString() {
|
||||||
|
final String key = "key";
|
||||||
|
|
||||||
|
// put
|
||||||
|
final String expectedValue = "globalTestValue1";
|
||||||
|
boolean isPutSuccessful = CMSettings.Global.putString(mContentResolver, key, expectedValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
String actualValue = CMSettings.Global.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedValue, actualValue);
|
||||||
|
|
||||||
|
// replace
|
||||||
|
final String expectedReplaceValue = "globalTestValue2";
|
||||||
|
isPutSuccessful = CMSettings.Global.putString(mContentResolver, key, expectedReplaceValue);
|
||||||
|
assertTrue(isPutSuccessful);
|
||||||
|
|
||||||
|
// get
|
||||||
|
actualValue = CMSettings.Global.getString(mContentResolver, key);
|
||||||
|
assertEquals(expectedReplaceValue, actualValue);
|
||||||
|
|
||||||
|
// delete to clean up
|
||||||
|
int rowsAffected = mContentResolver.delete(CMSettings.Global.CONTENT_URI, Settings.NameValueTable.NAME + " = ?",
|
||||||
|
new String[]{ key });
|
||||||
|
assertEquals(1, rowsAffected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add tests for other users
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user