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 Diff line number Diff line
@@ -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) {
                throw new IllegalArgumentException("Binding not well formed: " + argument);
            }
            final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
            if (secondColonIndex < 0) {
            final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
            if (split.size() != 3) {
                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);
        }
    }