Merge "Expand "extras" support in content tool." into rvc-dev am: cfeb0d8323 am: 8afffa8dcc
Change-Id: Ia33e90c5718c7d5dad006e6feca8bc47ec580cc6
This commit is contained in:
@@ -32,8 +32,11 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is a command line utility for manipulating content. A client
|
||||
@@ -72,7 +75,7 @@ public class Content {
|
||||
"usage: adb shell content [subcommand] [options]\n"
|
||||
+ "\n"
|
||||
+ "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
|
||||
+ " --bind <BINDING> [--bind <BINDING>...]\n"
|
||||
+ " --bind <BINDING> [--bind <BINDING>...] [--extra <BINDING>...]\n"
|
||||
+ " <URI> a content provider URI.\n"
|
||||
+ " <BINDING> binds a typed value to a column and is formatted:\n"
|
||||
+ " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
|
||||
@@ -84,7 +87,8 @@ public class Content {
|
||||
+ " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
|
||||
+ " --bind value:s:new_value\n"
|
||||
+ "\n"
|
||||
+ "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
|
||||
+ "usage: adb shell content update --uri <URI> [--user <USER_ID>]"
|
||||
+ " [--where <WHERE>] [--extra <BINDING>...]\n"
|
||||
+ " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
|
||||
+ " - see example below).\n"
|
||||
+ " Example:\n"
|
||||
@@ -93,14 +97,15 @@ public class Content {
|
||||
+ " value:s:newer_value --where \"name=\'new_setting\'\"\n"
|
||||
+ "\n"
|
||||
+ "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
|
||||
+ " [--bind <BINDING>...] [--where <WHERE>]\n"
|
||||
+ " [--bind <BINDING>...] [--where <WHERE>] [--extra <BINDING>...]\n"
|
||||
+ " Example:\n"
|
||||
+ " # Remove \"new_setting\" secure setting.\n"
|
||||
+ " adb shell content delete --uri content://settings/secure "
|
||||
+ "--where \"name=\'new_setting\'\"\n"
|
||||
+ "\n"
|
||||
+ "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
|
||||
+ " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
|
||||
+ " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]"
|
||||
+ " [--extra <BINDING>...]\n"
|
||||
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
|
||||
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
|
||||
+ " <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
|
||||
@@ -196,6 +201,7 @@ public class Content {
|
||||
Uri uri = null;
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
ContentValues values = new ContentValues();
|
||||
Bundle extras = new Bundle();
|
||||
for (String argument; (argument = mTokenizer.nextArg()) != null;) {
|
||||
if (ARGUMENT_URI.equals(argument)) {
|
||||
uri = Uri.parse(argumentValueRequired(argument));
|
||||
@@ -203,6 +209,8 @@ public class Content {
|
||||
userId = Integer.parseInt(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_BIND.equals(argument)) {
|
||||
parseBindValue(values);
|
||||
} else if (ARGUMENT_EXTRA.equals(argument)) {
|
||||
parseBindValue(extras);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported argument: " + argument);
|
||||
}
|
||||
@@ -215,20 +223,23 @@ public class Content {
|
||||
throw new IllegalArgumentException("Bindings not specified."
|
||||
+ " Did you specify --bind argument(s)?");
|
||||
}
|
||||
return new InsertCommand(uri, userId, values);
|
||||
return new InsertCommand(uri, userId, values, extras);
|
||||
}
|
||||
|
||||
private DeleteCommand parseDeleteCommand() {
|
||||
Uri uri = null;
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
String where = null;
|
||||
Bundle extras = new Bundle();
|
||||
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
|
||||
if (ARGUMENT_URI.equals(argument)) {
|
||||
uri = Uri.parse(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_USER.equals(argument)) {
|
||||
userId = Integer.parseInt(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_WHERE.equals(argument)) {
|
||||
where = argumentValueRequired(argument);
|
||||
extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
|
||||
argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_EXTRA.equals(argument)) {
|
||||
parseBindValue(extras);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported argument: " + argument);
|
||||
}
|
||||
@@ -237,23 +248,26 @@ public class Content {
|
||||
throw new IllegalArgumentException("Content provider URI not specified."
|
||||
+ " Did you specify --uri argument?");
|
||||
}
|
||||
return new DeleteCommand(uri, userId, where);
|
||||
return new DeleteCommand(uri, userId, extras);
|
||||
}
|
||||
|
||||
private UpdateCommand parseUpdateCommand() {
|
||||
Uri uri = null;
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
String where = null;
|
||||
ContentValues values = new ContentValues();
|
||||
Bundle extras = new Bundle();
|
||||
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
|
||||
if (ARGUMENT_URI.equals(argument)) {
|
||||
uri = Uri.parse(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_USER.equals(argument)) {
|
||||
userId = Integer.parseInt(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_WHERE.equals(argument)) {
|
||||
where = argumentValueRequired(argument);
|
||||
extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
|
||||
argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_BIND.equals(argument)) {
|
||||
parseBindValue(values);
|
||||
} else if (ARGUMENT_EXTRA.equals(argument)) {
|
||||
parseBindValue(extras);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported argument: " + argument);
|
||||
}
|
||||
@@ -266,7 +280,7 @@ public class Content {
|
||||
throw new IllegalArgumentException("Bindings not specified."
|
||||
+ " Did you specify --bind argument(s)?");
|
||||
}
|
||||
return new UpdateCommand(uri, userId, values, where);
|
||||
return new UpdateCommand(uri, userId, values, extras);
|
||||
}
|
||||
|
||||
public CallCommand parseCallCommand() {
|
||||
@@ -274,7 +288,7 @@ public class Content {
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
String arg = null;
|
||||
Uri uri = null;
|
||||
ContentValues values = new ContentValues();
|
||||
Bundle extras = new Bundle();
|
||||
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
|
||||
if (ARGUMENT_URI.equals(argument)) {
|
||||
uri = Uri.parse(argumentValueRequired(argument));
|
||||
@@ -285,11 +299,10 @@ public class Content {
|
||||
} else if (ARGUMENT_ARG.equals(argument)) {
|
||||
arg = argumentValueRequired(argument);
|
||||
} else if (ARGUMENT_EXTRA.equals(argument)) {
|
||||
parseBindValue(values);
|
||||
parseBindValue(extras);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported argument: " + argument);
|
||||
}
|
||||
|
||||
}
|
||||
if (uri == null) {
|
||||
throw new IllegalArgumentException("Content provider URI not specified."
|
||||
@@ -298,7 +311,7 @@ public class Content {
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("Content provider method not specified.");
|
||||
}
|
||||
return new CallCommand(uri, userId, method, arg, values);
|
||||
return new CallCommand(uri, userId, method, arg, extras);
|
||||
}
|
||||
|
||||
private GetTypeCommand parseGetTypeCommand() {
|
||||
@@ -363,19 +376,22 @@ public class Content {
|
||||
Uri uri = null;
|
||||
int userId = UserHandle.USER_SYSTEM;
|
||||
String[] projection = null;
|
||||
String sort = null;
|
||||
String where = null;
|
||||
Bundle extras = new Bundle();
|
||||
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
|
||||
if (ARGUMENT_URI.equals(argument)) {
|
||||
uri = Uri.parse(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_USER.equals(argument)) {
|
||||
userId = Integer.parseInt(argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_WHERE.equals(argument)) {
|
||||
where = argumentValueRequired(argument);
|
||||
extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
|
||||
argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_SORT.equals(argument)) {
|
||||
sort = argumentValueRequired(argument);
|
||||
extras.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
|
||||
argumentValueRequired(argument));
|
||||
} else if (ARGUMENT_PROJECTION.equals(argument)) {
|
||||
projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
|
||||
} else if (ARGUMENT_EXTRA.equals(argument)) {
|
||||
parseBindValue(extras);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported argument: " + argument);
|
||||
}
|
||||
@@ -384,40 +400,76 @@ public class Content {
|
||||
throw new IllegalArgumentException("Content provider URI not specified."
|
||||
+ " Did you specify --uri argument?");
|
||||
}
|
||||
return new QueryCommand(uri, userId, projection, where, sort);
|
||||
return new QueryCommand(uri, userId, projection, extras);
|
||||
}
|
||||
|
||||
private void parseBindValue(ContentValues values) {
|
||||
private List<String> splitWithEscaping(String argument, char splitChar) {
|
||||
final List<String> res = new ArrayList<>();
|
||||
final StringBuilder cur = new StringBuilder();
|
||||
for (int i = 0; i < argument.length(); i++) {
|
||||
char c = argument.charAt(i);
|
||||
if (c == '\\') {
|
||||
if (++i == argument.length()) {
|
||||
throw new IllegalArgumentException("Invalid escaping");
|
||||
} else {
|
||||
// Skip escaping char and insert next
|
||||
c = argument.charAt(i);
|
||||
cur.append(c);
|
||||
}
|
||||
} else if (c == splitChar) {
|
||||
// Splitting char means next string
|
||||
res.add(cur.toString());
|
||||
cur.setLength(0);
|
||||
} else {
|
||||
// Copy non-escaping and non-splitting char
|
||||
cur.append(c);
|
||||
}
|
||||
}
|
||||
res.add(cur.toString());
|
||||
return res;
|
||||
}
|
||||
|
||||
private Pair<String, Object> parseBindValue() {
|
||||
String argument = mTokenizer.nextArg();
|
||||
if (TextUtils.isEmpty(argument)) {
|
||||
throw new IllegalArgumentException("Binding not well formed: " + argument);
|
||||
}
|
||||
final int firstColonIndex = argument.indexOf(COLON);
|
||||
if (firstColonIndex < 0) {
|
||||
final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
|
||||
if (split.size() != 3) {
|
||||
throw new IllegalArgumentException("Binding not well formed: " + argument);
|
||||
}
|
||||
final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
|
||||
if (secondColonIndex < 0) {
|
||||
throw new IllegalArgumentException("Binding not well formed: " + argument);
|
||||
}
|
||||
String column = argument.substring(0, firstColonIndex);
|
||||
String type = argument.substring(firstColonIndex + 1, secondColonIndex);
|
||||
String value = argument.substring(secondColonIndex + 1);
|
||||
String column = split.get(0);
|
||||
String type = split.get(1);
|
||||
String value = split.get(2);
|
||||
if (TYPE_STRING.equals(type)) {
|
||||
values.put(column, value);
|
||||
return Pair.create(column, value);
|
||||
} else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
|
||||
values.put(column, Boolean.parseBoolean(value));
|
||||
} else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
|
||||
values.put(column, Long.parseLong(value));
|
||||
} else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
|
||||
values.put(column, Double.parseDouble(value));
|
||||
return Pair.create(column, Boolean.parseBoolean(value));
|
||||
} else if (TYPE_INTEGER.equalsIgnoreCase(type)) {
|
||||
return Pair.create(column, Integer.parseInt(value));
|
||||
} else if (TYPE_LONG.equalsIgnoreCase(type)) {
|
||||
return Pair.create(column, Long.parseLong(value));
|
||||
} else if (TYPE_FLOAT.equalsIgnoreCase(type)) {
|
||||
return Pair.create(column, Float.parseFloat(value));
|
||||
} else if (TYPE_DOUBLE.equalsIgnoreCase(type)) {
|
||||
return Pair.create(column, Double.parseDouble(value));
|
||||
} else if (TYPE_NULL.equalsIgnoreCase(type)) {
|
||||
values.putNull(column);
|
||||
return Pair.create(column, null);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseBindValue(ContentValues values) {
|
||||
final Pair<String, Object> columnValue = parseBindValue();
|
||||
values.putObject(columnValue.first, columnValue.second);
|
||||
}
|
||||
|
||||
private void parseBindValue(Bundle extras) {
|
||||
final Pair<String, Object> columnValue = parseBindValue();
|
||||
extras.putObject(columnValue.first, columnValue.second);
|
||||
}
|
||||
|
||||
private String argumentValueRequired(String argument) {
|
||||
String value = mTokenizer.nextArg();
|
||||
if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
|
||||
@@ -500,60 +552,43 @@ public class Content {
|
||||
|
||||
private static class InsertCommand extends Command {
|
||||
final ContentValues mContentValues;
|
||||
final Bundle mExtras;
|
||||
|
||||
public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
|
||||
public InsertCommand(Uri uri, int userId, ContentValues contentValues, Bundle extras) {
|
||||
super(uri, userId);
|
||||
mContentValues = contentValues;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(IContentProvider provider) throws Exception {
|
||||
provider.insert(resolveCallingPackage(), null, mUri, mContentValues, null);
|
||||
provider.insert(resolveCallingPackage(), null, mUri, mContentValues, mExtras);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteCommand extends Command {
|
||||
final String mWhere;
|
||||
final Bundle mExtras;
|
||||
|
||||
public DeleteCommand(Uri uri, int userId, String where) {
|
||||
public DeleteCommand(Uri uri, int userId, Bundle extras) {
|
||||
super(uri, userId);
|
||||
mWhere = where;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(IContentProvider provider) throws Exception {
|
||||
provider.delete(resolveCallingPackage(), null, mUri,
|
||||
ContentResolver.createSqlQueryBundle(mWhere, null));
|
||||
provider.delete(resolveCallingPackage(), null, mUri, mExtras);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CallCommand extends Command {
|
||||
final String mMethod, mArg;
|
||||
Bundle mExtras = null;
|
||||
final Bundle mExtras;
|
||||
|
||||
public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) {
|
||||
public CallCommand(Uri uri, int userId, String method, String arg, Bundle extras) {
|
||||
super(uri, userId);
|
||||
mMethod = method;
|
||||
mArg = arg;
|
||||
if (values != null) {
|
||||
mExtras = new Bundle();
|
||||
for (String key : values.keySet()) {
|
||||
final Object val = values.get(key);
|
||||
if (val instanceof String) {
|
||||
mExtras.putString(key, (String) val);
|
||||
} else if (val instanceof Float) {
|
||||
mExtras.putFloat(key, (Float) val);
|
||||
} else if (val instanceof Double) {
|
||||
mExtras.putDouble(key, (Double) val);
|
||||
} else if (val instanceof Boolean) {
|
||||
mExtras.putBoolean(key, (Boolean) val);
|
||||
} else if (val instanceof Integer) {
|
||||
mExtras.putInt(key, (Integer) val);
|
||||
} else if (val instanceof Long) {
|
||||
mExtras.putLong(key, (Long) val);
|
||||
}
|
||||
}
|
||||
}
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -604,21 +639,20 @@ public class Content {
|
||||
}
|
||||
}
|
||||
|
||||
private static class QueryCommand extends DeleteCommand {
|
||||
private static class QueryCommand extends Command {
|
||||
final String[] mProjection;
|
||||
final String mSortOrder;
|
||||
final Bundle mExtras;
|
||||
|
||||
public QueryCommand(
|
||||
Uri uri, int userId, String[] projection, String where, String sortOrder) {
|
||||
super(uri, userId, where);
|
||||
public QueryCommand(Uri uri, int userId, String[] projection, Bundle extras) {
|
||||
super(uri, userId);
|
||||
mProjection = projection;
|
||||
mSortOrder = sortOrder;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(IContentProvider provider) throws Exception {
|
||||
Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
|
||||
ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
|
||||
mExtras, null);
|
||||
if (cursor == null) {
|
||||
System.out.println("No result found.");
|
||||
return;
|
||||
@@ -670,18 +704,19 @@ public class Content {
|
||||
}
|
||||
}
|
||||
|
||||
private static class UpdateCommand extends InsertCommand {
|
||||
final String mWhere;
|
||||
private static class UpdateCommand extends Command {
|
||||
final ContentValues mValues;
|
||||
final Bundle mExtras;
|
||||
|
||||
public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
|
||||
super(uri, userId, contentValues);
|
||||
mWhere = where;
|
||||
public UpdateCommand(Uri uri, int userId, ContentValues values, Bundle extras) {
|
||||
super(uri, userId);
|
||||
mValues = values;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(IContentProvider provider) throws Exception {
|
||||
provider.update(resolveCallingPackage(), null, mUri, mContentValues,
|
||||
ContentResolver.createSqlQueryBundle(mWhere, null));
|
||||
provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user