diff options
Diffstat (limited to 'cmds/content/src')
-rw-r--r-- | cmds/content/src/com/android/commands/content/Content.java | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java new file mode 100644 index 0000000..1dcba70 --- /dev/null +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -0,0 +1,442 @@ +/* +** Copyright 2012, The Android Open Source 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 com.android.commands.content; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IActivityManager.ContentProviderHolder; +import android.content.ContentValues; +import android.content.IContentProvider; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.text.TextUtils; + +/** + * This class is a command line utility for manipulating content. A client + * can insert, update, and remove records in a content provider. For example, + * some settings may be configured before running the CTS tests, etc. + * <p> + * Examples: + * <ul> + * <li> + * # Add "new_setting" secure setting with value "new_value".</br> + * adb shell content insert --uri content://settings/secure --bind name:s:new_setting + * --bind value:s:new_value + * </li> + * <li> + * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in + * the where clause).</br> + * adb shell content update --uri content://settings/secure --bind value:s:newer_value + * --where "name=\'new_setting\'" + * </li> + * <li> + * # Remove "new_setting" secure setting.</br> + * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'" + * </li> + * <li> + * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to" + * \"new_setting\" and sort the result by name in ascending order.\n" + * adb shell content query --uri content://settings/secure --projection name:value + * --where "name=\'new_setting\'" --sort \"name ASC\" + * </li> + * </ul> + * </p> + */ +public class Content { + + private static final String USAGE = + "usage: adb shell content [subcommand] [options]\n" + + "\n" + + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <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" + + " <TYPE> specifies data type such as:\n" + + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n" + + " Example:\n" + + " # Add \"new_setting\" secure setting with value \"new_value\".\n" + + " 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> [--where <WHERE>]\n" + + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" + + " - see example below).\n" + + " Example:\n" + + " # Change \"new_setting\" secure setting to \"newer_value\".\n" + + " adb shell content update --uri content://settings/secure --bind" + + " value:s:newer_value --where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content delete --uri <URI> --bind <BINDING>" + + " [--bind <BINDING>...] [--where <WHERE>]\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> [--projection <PROJECTION>]" + + " [--where <WHERE>] [--sort <SORT_ORDER>]\n" + + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" + + " <SORT_OREDER> is the order in which rows in the result should be sorted.\n" + + " Example:\n" + + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + + "equal to \"new_setting\" and sort the result by name in ascending order.\n" + + " adb shell content query --uri content://settings/secure --projection name:value" + + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" + + "\n"; + + private static class Parser { + private static final String ARGUMENT_INSERT = "insert"; + private static final String ARGUMENT_DELETE = "delete"; + private static final String ARGUMENT_UPDATE = "update"; + private static final String ARGUMENT_QUERY = "query"; + private static final String ARGUMENT_WHERE = "--where"; + private static final String ARGUMENT_BIND = "--bind"; + private static final String ARGUMENT_URI = "--uri"; + private static final String ARGUMENT_PROJECTION = "--projection"; + private static final String ARGUMENT_SORT = "--sort"; + private static final String TYPE_BOOLEAN = "b"; + private static final String TYPE_STRING = "s"; + private static final String TYPE_INTEGER = "i"; + private static final String TYPE_LONG = "l"; + private static final String TYPE_FLOAT = "f"; + private static final String TYPE_DOUBLE = "d"; + private static final String COLON = ":"; + private static final String ARGUMENT_PREFIX = "--"; + + private final Tokenizer mTokenizer; + + public Parser(String[] args) { + mTokenizer = new Tokenizer(args); + } + + public Command parseCommand() { + try { + String operation = mTokenizer.nextArg(); + if (ARGUMENT_INSERT.equals(operation)) { + return parseInsertCommand(); + } else if (ARGUMENT_DELETE.equals(operation)) { + return parseDeleteCommand(); + } else if (ARGUMENT_UPDATE.equals(operation)) { + return parseUpdateCommand(); + } else if (ARGUMENT_QUERY.equals(operation)) { + return parseQueryCommand(); + } else { + throw new IllegalArgumentException("Unsupported operation: " + operation); + } + } catch (IllegalArgumentException iae) { + System.out.println(USAGE); + System.out.println("[ERROR] " + iae.getMessage()); + return null; + } + } + + private InsertCommand parseInsertCommand() { + Uri uri = null; + ContentValues values = new ContentValues(); + for (String argument; (argument = mTokenizer.nextArg()) != null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_BIND.equals(argument)) { + parseBindValue(values); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + if (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new InsertCommand(uri, values); + } + + private DeleteCommand parseDeleteCommand() { + Uri uri = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new DeleteCommand(uri, where); + } + + private UpdateCommand parseUpdateCommand() { + Uri uri = null; + String where = null; + ContentValues values = new ContentValues(); + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_BIND.equals(argument)) { + parseBindValue(values); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + if (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new UpdateCommand(uri, values, where); + } + + public QueryCommand parseQueryCommand() { + Uri uri = null; + String[] projection = null; + String sort = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_SORT.equals(argument)) { + sort = argumentValueRequired(argument); + } else if (ARGUMENT_PROJECTION.equals(argument)) { + projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*"); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new QueryCommand(uri, projection, where, sort); + } + + private void parseBindValue(ContentValues values) { + String argument = mTokenizer.nextArg(); + if (TextUtils.isEmpty(argument)) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + String[] binding = argument.split(COLON); + if (binding.length != 3) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + String column = binding[0]; + String type = binding[1]; + String value = binding[2]; + if (TYPE_STRING.equals(type)) { + values.put(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)); + } else { + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private String argumentValueRequired(String argument) { + String value = mTokenizer.nextArg(); + if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { + throw new IllegalArgumentException("No value for argument: " + argument); + } + return value; + } + } + + private static class Tokenizer { + private final String[] mArgs; + private int mNextArg; + + public Tokenizer(String[] args) { + mArgs = args; + } + + private String nextArg() { + if (mNextArg < mArgs.length) { + return mArgs[mNextArg++]; + } else { + return null; + } + } + } + + private static abstract class Command { + final Uri mUri; + + public Command(Uri uri) { + mUri = uri; + } + + public final void execute() { + String providerName = mUri.getAuthority(); + try { + IActivityManager activityManager = ActivityManagerNative.getDefault(); + IContentProvider provider = null; + IBinder token = new Binder(); + try { + ContentProviderHolder holder = activityManager.getContentProviderExternal( + providerName, token); + if (holder == null) { + throw new IllegalStateException("Could not find provider: " + providerName); + } + provider = holder.provider; + onExecute(provider); + } finally { + if (provider != null) { + activityManager.removeContentProviderExternal(providerName, token); + } + } + } catch (Exception e) { + System.err.println("Error while accessing provider:" + providerName); + e.printStackTrace(); + } + } + + protected abstract void onExecute(IContentProvider provider) throws Exception; + } + + private static class InsertCommand extends Command { + final ContentValues mContentValues; + + public InsertCommand(Uri uri, ContentValues contentValues) { + super(uri); + mContentValues = contentValues; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.insert(mUri, mContentValues); + } + } + + private static class DeleteCommand extends Command { + final String mWhere; + + public DeleteCommand(Uri uri, String where) { + super(uri); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.delete(mUri, mWhere, null); + } + } + + private static class QueryCommand extends DeleteCommand { + final String[] mProjection; + final String mSortOrder; + + public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) { + super(uri, where); + mProjection = projection; + mSortOrder = sortOrder; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null); + if (cursor == null) { + System.out.println("No result found."); + return; + } + try { + if (cursor.moveToFirst()) { + int rowIndex = 0; + StringBuilder builder = new StringBuilder(); + do { + builder.setLength(0); + builder.append("Row: ").append(rowIndex).append(" "); + rowIndex++; + final int columnCount = cursor.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + if (i > 0) { + builder.append(", "); + } + String columnName = cursor.getColumnName(i); + String columnValue = null; + final int columnIndex = cursor.getColumnIndex(columnName); + final int type = cursor.getType(columnIndex); + switch (type) { + case Cursor.FIELD_TYPE_FLOAT: + columnValue = String.valueOf(cursor.getFloat(columnIndex)); + break; + case Cursor.FIELD_TYPE_INTEGER: + columnValue = String.valueOf(cursor.getInt(columnIndex)); + break; + case Cursor.FIELD_TYPE_STRING: + columnValue = cursor.getString(columnIndex); + break; + case Cursor.FIELD_TYPE_BLOB: + columnValue = "BLOB"; + break; + case Cursor.FIELD_TYPE_NULL: + columnValue = "NULL"; + break; + } + builder.append(columnName).append("=").append(columnValue); + } + System.out.println(builder); + } while (cursor.moveToNext()); + } else { + System.out.println("No reuslt found."); + } + } finally { + cursor.close(); + } + } + } + + private static class UpdateCommand extends InsertCommand { + final String mWhere; + + public UpdateCommand(Uri uri, ContentValues contentValues, String where) { + super(uri, contentValues); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.update(mUri, mContentValues, mWhere, null); + } + } + + public static void main(String[] args) { + Parser parser = new Parser(args); + Command command = parser.parseCommand(); + if (command != null) { + command.execute(); + } + } +} |