Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfeb0d83 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Expand "extras" support in content tool." into rvc-dev

parents 06ccd26d 547bf548
Loading
Loading
Loading
Loading
+114 −79
Original line number Original line Diff line number Diff line
@@ -32,8 +32,11 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Pair;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.List;


/**
/**
 * This class is a command line utility for manipulating content. A client
 * 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"
            "usage: adb shell content [subcommand] [options]\n"
                    + "\n"
                    + "\n"
                    + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
                    + "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"
                    + "  <URI> a content provider URI.\n"
                    + "  <BINDING> binds a typed value to a column and is formatted:\n"
                    + "  <BINDING> binds a typed value to a column and is formatted:\n"
                    + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\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"
                    + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
                    + " --bind value:s:new_value\n"
                    + " --bind value:s:new_value\n"
                    + "\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"
                    + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
                    + " - see example below).\n"
                    + " - see example below).\n"
                    + "  Example:\n"
                    + "  Example:\n"
@@ -93,14 +97,15 @@ public class Content {
                    + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
                    + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
                    + "\n"
                    + "\n"
                    + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
                    + "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"
                    + "  Example:\n"
                    + "  # Remove \"new_setting\" secure setting.\n"
                    + "  # Remove \"new_setting\" secure setting.\n"
                    + "  adb shell content delete --uri content://settings/secure "
                    + "  adb shell content delete --uri content://settings/secure "
                    + "--where \"name=\'new_setting\'\"\n"
                    + "--where \"name=\'new_setting\'\"\n"
                    + "\n"
                    + "\n"
                    + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
                    + "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"
                    + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
                    + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
                    + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
                    + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\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;
            Uri uri = null;
            int userId = UserHandle.USER_SYSTEM;
            int userId = UserHandle.USER_SYSTEM;
            ContentValues values = new ContentValues();
            ContentValues values = new ContentValues();
            Bundle extras = new Bundle();
            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
                if (ARGUMENT_URI.equals(argument)) {
                if (ARGUMENT_URI.equals(argument)) {
                    uri = Uri.parse(argumentValueRequired(argument));
                    uri = Uri.parse(argumentValueRequired(argument));
@@ -203,6 +209,8 @@ public class Content {
                    userId = Integer.parseInt(argumentValueRequired(argument));
                    userId = Integer.parseInt(argumentValueRequired(argument));
                } else if (ARGUMENT_BIND.equals(argument)) {
                } else if (ARGUMENT_BIND.equals(argument)) {
                    parseBindValue(values);
                    parseBindValue(values);
                } else if (ARGUMENT_EXTRA.equals(argument)) {
                    parseBindValue(extras);
                } else {
                } else {
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                }
                }
@@ -215,20 +223,23 @@ public class Content {
                throw new IllegalArgumentException("Bindings not specified."
                throw new IllegalArgumentException("Bindings not specified."
                        + " Did you specify --bind argument(s)?");
                        + " Did you specify --bind argument(s)?");
            }
            }
            return new InsertCommand(uri, userId, values);
            return new InsertCommand(uri, userId, values, extras);
        }
        }


        private DeleteCommand parseDeleteCommand() {
        private DeleteCommand parseDeleteCommand() {
            Uri uri = null;
            Uri uri = null;
            int userId = UserHandle.USER_SYSTEM;
            int userId = UserHandle.USER_SYSTEM;
            String where = null;
            Bundle extras = new Bundle();
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                if (ARGUMENT_URI.equals(argument)) {
                if (ARGUMENT_URI.equals(argument)) {
                    uri = Uri.parse(argumentValueRequired(argument));
                    uri = Uri.parse(argumentValueRequired(argument));
                } else if (ARGUMENT_USER.equals(argument)) {
                } else if (ARGUMENT_USER.equals(argument)) {
                    userId = Integer.parseInt(argumentValueRequired(argument));
                    userId = Integer.parseInt(argumentValueRequired(argument));
                } else if (ARGUMENT_WHERE.equals(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 {
                } else {
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                }
                }
@@ -237,23 +248,26 @@ public class Content {
                throw new IllegalArgumentException("Content provider URI not specified."
                throw new IllegalArgumentException("Content provider URI not specified."
                        + " Did you specify --uri argument?");
                        + " Did you specify --uri argument?");
            }
            }
            return new DeleteCommand(uri, userId, where);
            return new DeleteCommand(uri, userId, extras);
        }
        }


        private UpdateCommand parseUpdateCommand() {
        private UpdateCommand parseUpdateCommand() {
            Uri uri = null;
            Uri uri = null;
            int userId = UserHandle.USER_SYSTEM;
            int userId = UserHandle.USER_SYSTEM;
            String where = null;
            ContentValues values = new ContentValues();
            ContentValues values = new ContentValues();
            Bundle extras = new Bundle();
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                if (ARGUMENT_URI.equals(argument)) {
                if (ARGUMENT_URI.equals(argument)) {
                    uri = Uri.parse(argumentValueRequired(argument));
                    uri = Uri.parse(argumentValueRequired(argument));
                } else if (ARGUMENT_USER.equals(argument)) {
                } else if (ARGUMENT_USER.equals(argument)) {
                    userId = Integer.parseInt(argumentValueRequired(argument));
                    userId = Integer.parseInt(argumentValueRequired(argument));
                } else if (ARGUMENT_WHERE.equals(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)) {
                } else if (ARGUMENT_BIND.equals(argument)) {
                    parseBindValue(values);
                    parseBindValue(values);
                } else if (ARGUMENT_EXTRA.equals(argument)) {
                    parseBindValue(extras);
                } else {
                } else {
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                }
                }
@@ -266,7 +280,7 @@ public class Content {
                throw new IllegalArgumentException("Bindings not specified."
                throw new IllegalArgumentException("Bindings not specified."
                        + " Did you specify --bind argument(s)?");
                        + " Did you specify --bind argument(s)?");
            }
            }
            return new UpdateCommand(uri, userId, values, where);
            return new UpdateCommand(uri, userId, values, extras);
        }
        }


        public CallCommand parseCallCommand() {
        public CallCommand parseCallCommand() {
@@ -274,7 +288,7 @@ public class Content {
            int userId = UserHandle.USER_SYSTEM;
            int userId = UserHandle.USER_SYSTEM;
            String arg = null;
            String arg = null;
            Uri uri = null;
            Uri uri = null;
            ContentValues values = new ContentValues();
            Bundle extras = new Bundle();
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                if (ARGUMENT_URI.equals(argument)) {
                if (ARGUMENT_URI.equals(argument)) {
                    uri = Uri.parse(argumentValueRequired(argument));
                    uri = Uri.parse(argumentValueRequired(argument));
@@ -285,11 +299,10 @@ public class Content {
                } else if (ARGUMENT_ARG.equals(argument)) {
                } else if (ARGUMENT_ARG.equals(argument)) {
                    arg = argumentValueRequired(argument);
                    arg = argumentValueRequired(argument);
                } else if (ARGUMENT_EXTRA.equals(argument)) {
                } else if (ARGUMENT_EXTRA.equals(argument)) {
                    parseBindValue(values);
                    parseBindValue(extras);
                } else {
                } else {
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                }
                }

            }
            }
            if (uri == null) {
            if (uri == null) {
                throw new IllegalArgumentException("Content provider URI not specified."
                throw new IllegalArgumentException("Content provider URI not specified."
@@ -298,7 +311,7 @@ public class Content {
            if (method == null) {
            if (method == null) {
                throw new IllegalArgumentException("Content provider method not specified.");
                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() {
        private GetTypeCommand parseGetTypeCommand() {
@@ -363,19 +376,22 @@ public class Content {
            Uri uri = null;
            Uri uri = null;
            int userId = UserHandle.USER_SYSTEM;
            int userId = UserHandle.USER_SYSTEM;
            String[] projection = null;
            String[] projection = null;
            String sort = null;
            Bundle extras = new Bundle();
            String where = null;
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                if (ARGUMENT_URI.equals(argument)) {
                if (ARGUMENT_URI.equals(argument)) {
                    uri = Uri.parse(argumentValueRequired(argument));
                    uri = Uri.parse(argumentValueRequired(argument));
                } else if (ARGUMENT_USER.equals(argument)) {
                } else if (ARGUMENT_USER.equals(argument)) {
                    userId = Integer.parseInt(argumentValueRequired(argument));
                    userId = Integer.parseInt(argumentValueRequired(argument));
                } else if (ARGUMENT_WHERE.equals(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)) {
                } 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)) {
                } else if (ARGUMENT_PROJECTION.equals(argument)) {
                    projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
                    projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
                } else if (ARGUMENT_EXTRA.equals(argument)) {
                    parseBindValue(extras);
                } else {
                } else {
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                    throw new IllegalArgumentException("Unsupported argument: " + argument);
                }
                }
@@ -384,40 +400,76 @@ public class Content {
                throw new IllegalArgumentException("Content provider URI not specified."
                throw new IllegalArgumentException("Content provider URI not specified."
                        + " Did you specify --uri argument?");
                        + " 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();
            String argument = mTokenizer.nextArg();
            if (TextUtils.isEmpty(argument)) {
            if (TextUtils.isEmpty(argument)) {
                throw new IllegalArgumentException("Binding not well formed: " + argument);
                throw new IllegalArgumentException("Binding not well formed: " + argument);
            }
            }
            final int firstColonIndex = argument.indexOf(COLON);
            final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
            if (firstColonIndex < 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);
                throw new IllegalArgumentException("Binding not well formed: " + argument);
            }
            }
            String column = argument.substring(0, firstColonIndex);
            String column = split.get(0);
            String type = argument.substring(firstColonIndex + 1, secondColonIndex);
            String type = split.get(1);
            String value = argument.substring(secondColonIndex + 1);
            String value = split.get(2);
            if (TYPE_STRING.equals(type)) {
            if (TYPE_STRING.equals(type)) {
                values.put(column, value);
                return Pair.create(column, value);
            } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
            } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
                values.put(column, Boolean.parseBoolean(value));
                return Pair.create(column, Boolean.parseBoolean(value));
            } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
            } else if (TYPE_INTEGER.equalsIgnoreCase(type)) {
                values.put(column, Long.parseLong(value));
                return Pair.create(column, Integer.parseInt(value));
            } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
            } else if (TYPE_LONG.equalsIgnoreCase(type)) {
                values.put(column, Double.parseDouble(value));
                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)) {
            } else if (TYPE_NULL.equalsIgnoreCase(type)) {
                values.putNull(column);
                return Pair.create(column, null);
            } else {
            } else {
                throw new IllegalArgumentException("Unsupported type: " + type);
                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) {
        private String argumentValueRequired(String argument) {
            String value = mTokenizer.nextArg();
            String value = mTokenizer.nextArg();
            if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
            if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
@@ -500,60 +552,43 @@ public class Content {


    private static class InsertCommand extends Command {
    private static class InsertCommand extends Command {
        final ContentValues mContentValues;
        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);
            super(uri, userId);
            mContentValues = contentValues;
            mContentValues = contentValues;
            mExtras = extras;
        }
        }


        @Override
        @Override
        public void onExecute(IContentProvider provider) throws Exception {
        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 {
    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);
            super(uri, userId);
            mWhere = where;
            mExtras = extras;
        }
        }


        @Override
        @Override
        public void onExecute(IContentProvider provider) throws Exception {
        public void onExecute(IContentProvider provider) throws Exception {
            provider.delete(resolveCallingPackage(), null, mUri,
            provider.delete(resolveCallingPackage(), null, mUri, mExtras);
                    ContentResolver.createSqlQueryBundle(mWhere, null));
        }
        }
    }
    }


    private static class CallCommand extends Command {
    private static class CallCommand extends Command {
        final String mMethod, mArg;
        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);
            super(uri, userId);
            mMethod = method;
            mMethod = method;
            mArg = arg;
            mArg = arg;
            if (values != null) {
            mExtras = extras;
                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);
                    }
                }
            }
        }
        }


        @Override
        @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[] mProjection;
        final String mSortOrder;
        final Bundle mExtras;


        public QueryCommand(
        public QueryCommand(Uri uri, int userId, String[] projection, Bundle extras) {
                Uri uri, int userId, String[] projection, String where, String sortOrder) {
            super(uri, userId);
            super(uri, userId, where);
            mProjection = projection;
            mProjection = projection;
            mSortOrder = sortOrder;
            mExtras = extras;
        }
        }


        @Override
        @Override
        public void onExecute(IContentProvider provider) throws Exception {
        public void onExecute(IContentProvider provider) throws Exception {
            Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
            Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
                    ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
                    mExtras, null);
            if (cursor == null) {
            if (cursor == null) {
                System.out.println("No result found.");
                System.out.println("No result found.");
                return;
                return;
@@ -670,18 +704,19 @@ public class Content {
        }
        }
    }
    }


    private static class UpdateCommand extends InsertCommand {
    private static class UpdateCommand extends Command {
        final String mWhere;
        final ContentValues mValues;
        final Bundle mExtras;


        public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
        public UpdateCommand(Uri uri, int userId, ContentValues values, Bundle extras) {
            super(uri, userId, contentValues);
            super(uri, userId);
            mWhere = where;
            mValues = values;
            mExtras = extras;
        }
        }


        @Override
        @Override
        public void onExecute(IContentProvider provider) throws Exception {
        public void onExecute(IContentProvider provider) throws Exception {
            provider.update(resolveCallingPackage(), null, mUri, mContentValues,
            provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
                    ContentResolver.createSqlQueryBundle(mWhere, null));
        }
        }
    }
    }