125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov/*
225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** Copyright 2012, The Android Open Source Project
325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov**
425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** Licensed under the Apache License, Version 2.0 (the "License");
525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** you may not use this file except in compliance with the License.
625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** You may obtain a copy of the License at
725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov**
825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov**     http://www.apache.org/licenses/LICENSE-2.0
925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov**
1025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** Unless required by applicable law or agreed to in writing, software
1125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** distributed under the License is distributed on an "AS IS" BASIS,
1225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** See the License for the specific language governing permissions and
1425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov** limitations under the License.
1525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov*/
1625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
1725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovpackage com.android.commands.content;
1825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
1925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.app.ActivityManagerNative;
2025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.app.IActivityManager;
2125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.app.IActivityManager.ContentProviderHolder;
2225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.content.ContentValues;
2325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.content.IContentProvider;
2425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.database.Cursor;
2525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.net.Uri;
2625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.os.Binder;
2725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.os.IBinder;
286d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkeyimport android.os.UserHandle;
2925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovimport android.text.TextUtils;
3025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
3125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov/**
3225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * This class is a command line utility for manipulating content. A client
3325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * can insert, update, and remove records in a content provider. For example,
3425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * some settings may be configured before running the CTS tests, etc.
3525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <p>
3625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * Examples:
3725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <ul>
3825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <li>
3925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * # Add "new_setting" secure setting with value "new_value".</br>
4025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * adb shell content insert --uri content://settings/secure --bind name:s:new_setting
4125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov *  --bind value:s:new_value
4225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </li>
4325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <li>
4425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in
4525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * the where clause).</br>
4625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * adb shell content update --uri content://settings/secure --bind value:s:newer_value
4725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov *  --where "name=\'new_setting\'"
4825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </li>
4925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <li>
5025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * # Remove "new_setting" secure setting.</br>
5125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'"
5225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </li>
5325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * <li>
5425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to"
5525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov *    \"new_setting\" and sort the result by name in ascending order.\n"
5625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * adb shell content query --uri content://settings/secure --projection name:value
5725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov *  --where "name=\'new_setting\'" --sort \"name ASC\"
5825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </li>
5925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </ul>
6025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov * </p>
6125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov */
6225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganovpublic class Content {
6325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
6425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static final String USAGE =
6525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        "usage: adb shell content [subcommand] [options]\n"
6625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "\n"
676d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
686d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                + " --bind <BINDING> [--bind <BINDING>...]\n"
6925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <URI> a content provider URI.\n"
7025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <BINDING> binds a typed value to a column and is formatted:\n"
7125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
7225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <TYPE> specifies data type such as:\n"
7325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
748486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov        + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
7525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  Example:\n"
7625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
7725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
7825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + " --bind value:s:new_value\n"
7925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "\n"
806d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
8125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
8225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + " - see example below).\n"
8325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  Example:\n"
8425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
8525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  adb shell content update --uri content://settings/secure --bind"
8625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
8725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "\n"
886d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
8925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + " [--bind <BINDING>...] [--where <WHERE>]\n"
9025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  Example:\n"
9125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  # Remove \"new_setting\" secure setting.\n"
9225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  adb shell content delete --uri content://settings/secure "
9325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + "--where \"name=\'new_setting\'\"\n"
9425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "\n"
956d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
966d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
9725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
9825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
9925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  <SORT_OREDER> is the order in which rows in the result should be sorted.\n"
10025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  Example:\n"
10125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
10225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
10325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "  adb shell content query --uri content://settings/secure --projection name:value"
10425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
10525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        + "\n";
10625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
10725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class Parser {
10825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_INSERT = "insert";
10925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_DELETE = "delete";
11025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_UPDATE = "update";
11125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_QUERY = "query";
11225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_WHERE = "--where";
11325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_BIND = "--bind";
11425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_URI = "--uri";
1156d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        private static final String ARGUMENT_USER = "--user";
11625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_PROJECTION = "--projection";
11725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_SORT = "--sort";
11825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_BOOLEAN = "b";
11925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_STRING = "s";
12025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_INTEGER = "i";
12125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_LONG = "l";
12225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_FLOAT = "f";
12325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String TYPE_DOUBLE = "d";
12425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String COLON = ":";
12525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private static final String ARGUMENT_PREFIX = "--";
12625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
12725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private final Tokenizer mTokenizer;
12825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
12925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public Parser(String[] args) {
13025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mTokenizer = new Tokenizer(args);
13125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
13225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
13325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public Command parseCommand() {
13425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            try {
13525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                String operation = mTokenizer.nextArg();
13625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (ARGUMENT_INSERT.equals(operation)) {
13725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    return parseInsertCommand();
13825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_DELETE.equals(operation)) {
13925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    return parseDeleteCommand();
14025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_UPDATE.equals(operation)) {
14125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    return parseUpdateCommand();
14225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_QUERY.equals(operation)) {
14325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    return parseQueryCommand();
14425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
14525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    throw new IllegalArgumentException("Unsupported operation: " + operation);
14625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
14725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } catch (IllegalArgumentException iae) {
14825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                System.out.println(USAGE);
14925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                System.out.println("[ERROR] " + iae.getMessage());
15025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                return null;
15125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
15225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
15325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
15425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private InsertCommand parseInsertCommand() {
15525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            Uri uri = null;
1566d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            int userId = UserHandle.USER_OWNER;
15725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            ContentValues values = new ContentValues();
15825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
15925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (ARGUMENT_URI.equals(argument)) {
16025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    uri = Uri.parse(argumentValueRequired(argument));
1616d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                } else if (ARGUMENT_USER.equals(argument)) {
1626d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                    userId = Integer.parseInt(argumentValueRequired(argument));
16325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_BIND.equals(argument)) {
16425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    parseBindValue(values);
16525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
16625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    throw new IllegalArgumentException("Unsupported argument: " + argument);
16725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
16825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
16925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (uri == null) {
17025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Content provider URI not specified."
17125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --uri argument?");
17225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
17325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (values.size() == 0) {
17425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Bindings not specified."
17525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --bind argument(s)?");
17625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
1776d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            return new InsertCommand(uri, userId, values);
17825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
17925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
18025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private DeleteCommand parseDeleteCommand() {
18125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            Uri uri = null;
1826d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            int userId = UserHandle.USER_OWNER;
18325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String where = null;
18425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
18525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (ARGUMENT_URI.equals(argument)) {
18625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    uri = Uri.parse(argumentValueRequired(argument));
1876d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                } else if (ARGUMENT_USER.equals(argument)) {
1886d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                    userId = Integer.parseInt(argumentValueRequired(argument));
18925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_WHERE.equals(argument)) {
19025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    where = argumentValueRequired(argument);
19125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
19225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    throw new IllegalArgumentException("Unsupported argument: " + argument);
19325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
19425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
19525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (uri == null) {
19625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Content provider URI not specified."
19725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --uri argument?");
19825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
1996d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            return new DeleteCommand(uri, userId, where);
20025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
20125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
20225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private UpdateCommand parseUpdateCommand() {
20325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            Uri uri = null;
2046d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            int userId = UserHandle.USER_OWNER;
20525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String where = null;
20625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            ContentValues values = new ContentValues();
20725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
20825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (ARGUMENT_URI.equals(argument)) {
20925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    uri = Uri.parse(argumentValueRequired(argument));
2106d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                } else if (ARGUMENT_USER.equals(argument)) {
2116d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                    userId = Integer.parseInt(argumentValueRequired(argument));
21225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_WHERE.equals(argument)) {
21325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    where = argumentValueRequired(argument);
21425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_BIND.equals(argument)) {
21525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    parseBindValue(values);
21625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
21725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    throw new IllegalArgumentException("Unsupported argument: " + argument);
21825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
21925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
22025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (uri == null) {
22125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Content provider URI not specified."
22225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --uri argument?");
22325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
22425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (values.size() == 0) {
22525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Bindings not specified."
22625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --bind argument(s)?");
22725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
2286d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            return new UpdateCommand(uri, userId, values, where);
22925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
23025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
23125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public QueryCommand parseQueryCommand() {
23225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            Uri uri = null;
2336d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            int userId = UserHandle.USER_OWNER;
23425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String[] projection = null;
23525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String sort = null;
23625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String where = null;
23725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
23825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (ARGUMENT_URI.equals(argument)) {
23925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    uri = Uri.parse(argumentValueRequired(argument));
2406d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                } else if (ARGUMENT_USER.equals(argument)) {
2416d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                    userId = Integer.parseInt(argumentValueRequired(argument));
24225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_WHERE.equals(argument)) {
24325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    where = argumentValueRequired(argument);
24425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_SORT.equals(argument)) {
24525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    sort = argumentValueRequired(argument);
24625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else if (ARGUMENT_PROJECTION.equals(argument)) {
24725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
24825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
24925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    throw new IllegalArgumentException("Unsupported argument: " + argument);
25025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
25125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
25225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (uri == null) {
25325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Content provider URI not specified."
25425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        + " Did you specify --uri argument?");
25525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
2566d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            return new QueryCommand(uri, userId, projection, where, sort);
25725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
25825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
25925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private void parseBindValue(ContentValues values) {
26025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String argument = mTokenizer.nextArg();
26125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (TextUtils.isEmpty(argument)) {
26225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Binding not well formed: " + argument);
26325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
2648486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            final int firstColonIndex = argument.indexOf(COLON);
2658486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            if (firstColonIndex < 0) {
26625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Binding not well formed: " + argument);
26725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
2688486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
2698486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            if (secondColonIndex < 0) {
2708486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov                throw new IllegalArgumentException("Binding not well formed: " + argument);
2718486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            }
2728486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            String column = argument.substring(0, firstColonIndex);
2738486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            String type = argument.substring(firstColonIndex + 1, secondColonIndex);
2748486bc11baa717390796f2ebd55c7b2ae9294bb7Svetoslav Ganov            String value = argument.substring(secondColonIndex + 1);
27525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (TYPE_STRING.equals(type)) {
27625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                values.put(column, value);
27725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
27825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                values.put(column, Boolean.parseBoolean(value));
27925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
28025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                values.put(column, Long.parseLong(value));
28125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
28225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                values.put(column, Double.parseDouble(value));
28325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } else {
28425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("Unsupported type: " + type);
28525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
28625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
28725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
28825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private String argumentValueRequired(String argument) {
28925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String value = mTokenizer.nextArg();
29025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
29125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                throw new IllegalArgumentException("No value for argument: " + argument);
29225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
29325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            return value;
29425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
29525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
29625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
29725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class Tokenizer {
29825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private final String[] mArgs;
29925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private int mNextArg;
30025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
30125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public Tokenizer(String[] args) {
30225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mArgs = args;
30325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
30425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
30525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        private String nextArg() {
30625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (mNextArg < mArgs.length) {
30725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                return mArgs[mNextArg++];
30825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } else {
30925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                return null;
31025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
31125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
31225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
31325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
31425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static abstract class Command {
31525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final Uri mUri;
3166d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        final int mUserId;
31725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
3186d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        public Command(Uri uri, int userId) {
31925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mUri = uri;
3206d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            mUserId = userId;
32125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
32225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
32325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public final void execute() {
32425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            String providerName = mUri.getAuthority();
32525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            try {
32625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                IActivityManager activityManager = ActivityManagerNative.getDefault();
32725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                IContentProvider provider = null;
32825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                IBinder token = new Binder();
32925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                try {
33025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    ContentProviderHolder holder = activityManager.getContentProviderExternal(
3316d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                            providerName, mUserId, token);
33225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    if (holder == null) {
33325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        throw new IllegalStateException("Could not find provider: " + providerName);
33425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    }
33525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    provider = holder.provider;
33625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    onExecute(provider);
33725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } finally {
33825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    if (provider != null) {
33925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        activityManager.removeContentProviderExternal(providerName, token);
34025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    }
34125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
34225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } catch (Exception e) {
34325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                System.err.println("Error while accessing provider:" + providerName);
34425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                e.printStackTrace();
34525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
34625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
34725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
34825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        protected abstract void onExecute(IContentProvider provider) throws Exception;
34925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
35025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
35125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class InsertCommand extends Command {
35225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final ContentValues mContentValues;
35325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
3546d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
3556d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            super(uri, userId);
35625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mContentValues = contentValues;
35725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
35825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
35925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        @Override
36025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public void onExecute(IContentProvider provider) throws Exception {
36125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            provider.insert(mUri, mContentValues);
36225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
36325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
36425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
36525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class DeleteCommand extends Command {
36625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final String mWhere;
36725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
3686d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        public DeleteCommand(Uri uri, int userId, String where) {
3696d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            super(uri, userId);
37025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mWhere = where;
37125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
37225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
37325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        @Override
37425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public void onExecute(IContentProvider provider) throws Exception {
37525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            provider.delete(mUri, mWhere, null);
37625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
37725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
37825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
37925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class QueryCommand extends DeleteCommand {
38025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final String[] mProjection;
38125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final String mSortOrder;
38225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
3836d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        public QueryCommand(
3846d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey                Uri uri, int userId, String[] projection, String where, String sortOrder) {
3856d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            super(uri, userId, where);
38625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mProjection = projection;
38725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mSortOrder = sortOrder;
38825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
38925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
39025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        @Override
39125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public void onExecute(IContentProvider provider) throws Exception {
39225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null);
39325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            if (cursor == null) {
39425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                System.out.println("No result found.");
39525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                return;
39625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
39725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            try {
39825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                if (cursor.moveToFirst()) {
39925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    int rowIndex = 0;
40025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    StringBuilder builder = new StringBuilder();
40125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    do {
40225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        builder.setLength(0);
40325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        builder.append("Row: ").append(rowIndex).append(" ");
40425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        rowIndex++;
40525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        final int columnCount = cursor.getColumnCount();
40625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        for (int i = 0; i < columnCount; i++) {
40725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            if (i > 0) {
40825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                builder.append(", ");
40925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            }
41025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            String columnName = cursor.getColumnName(i);
41125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            String columnValue = null;
41225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            final int columnIndex = cursor.getColumnIndex(columnName);
41325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            final int type = cursor.getType(columnIndex);
41425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            switch (type) {
41525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                case Cursor.FIELD_TYPE_FLOAT:
41625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    columnValue = String.valueOf(cursor.getFloat(columnIndex));
41725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    break;
41825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                case Cursor.FIELD_TYPE_INTEGER:
41925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    columnValue = String.valueOf(cursor.getInt(columnIndex));
42025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    break;
42125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                case Cursor.FIELD_TYPE_STRING:
42225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    columnValue = cursor.getString(columnIndex);
42325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    break;
42425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                case Cursor.FIELD_TYPE_BLOB:
42525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    columnValue = "BLOB";
42625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    break;
42725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                case Cursor.FIELD_TYPE_NULL:
42825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    columnValue = "NULL";
42925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                                    break;
43025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            }
43125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                            builder.append(columnName).append("=").append(columnValue);
43225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        }
43325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                        System.out.println(builder);
43425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    } while (cursor.moveToNext());
43525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                } else {
43625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                    System.out.println("No reuslt found.");
43725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                }
43825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            } finally {
43925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov                cursor.close();
44025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            }
44125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
44225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
44325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
44425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    private static class UpdateCommand extends InsertCommand {
44525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        final String mWhere;
44625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
4476d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey        public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
4486d51571835737c7502a2e111ee9dc2527ebad984Jeff Sharkey            super(uri, userId, contentValues);
44925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            mWhere = where;
45025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
45125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
45225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        @Override
45325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        public void onExecute(IContentProvider provider) throws Exception {
45425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            provider.update(mUri, mContentValues, mWhere, null);
45525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
45625872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
45725872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov
45825872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    public static void main(String[] args) {
45925872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        Parser parser = new Parser(args);
46025872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        Command command = parser.parseCommand();
46125872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        if (command != null) {
46225872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov            command.execute();
46325872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov        }
46425872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov    }
46525872aa3ef189ae5506a923398af11ce5eb1a9b9Svetoslav Ganov}
466