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

Commit 8afffa8d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

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

Change-Id: Ifb8b61249816e5e538377c3dda678b6833c32efe
parents ce162f28 cfeb0d83
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));
        }
        }
    }
    }