Merge "Some debugging improvements."
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 7f33cb5..62e0919a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -55,6 +55,7 @@
 import android.os.RemoteException;
 import android.os.SELinux;
 import android.os.ServiceManager;
+import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -72,6 +73,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -117,7 +119,8 @@
 
     @Override
     public void onShowUsage(PrintStream out) {
-        out.println(
+        PrintWriter pw = new PrintWriter(out);
+        pw.println(
                 "usage: am [subcommand] [options]\n" +
                 "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
                 "               [--sampling INTERVAL] [-R COUNT] [-S]\n" +
@@ -337,52 +340,10 @@
                 "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" +
                 "\n" +
                 "am get-current-user: returns id of the current foreground user.\n" +
-                "\n" +
-                "<INTENT> specifications include these flags and arguments:\n" +
-                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
-                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
-                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
-                "    [--esn <EXTRA_KEY> ...]\n" +
-                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
-                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
-                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
-                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
-                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
-                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
-                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
-                "        (mutiple extras passed as Integer[])\n" +
-                "    [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
-                "        (mutiple extras passed as List<Integer>)\n" +
-                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
-                "        (mutiple extras passed as Long[])\n" +
-                "    [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
-                "        (mutiple extras passed as List<Long>)\n" +
-                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
-                "        (mutiple extras passed as Float[])\n" +
-                "    [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
-                "        (mutiple extras passed as List<Float>)\n" +
-                "    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
-                "        (mutiple extras passed as String[]; to embed a comma into a string,\n" +
-                "         escape it using \"\\,\")\n" +
-                "    [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
-                "        (mutiple extras passed as List<String>; to embed a comma into a string,\n" +
-                "         escape it using \"\\,\")\n" +
-                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
-                "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
-                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
-                "    [--include-stopped-packages]\n" +
-                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
-                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
-                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
-                "    [--activity-no-animation] [--activity-no-history]\n" +
-                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
-                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
-                "    [--activity-single-top] [--activity-clear-task]\n" +
-                "    [--activity-task-on-home]\n" +
-                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
-                "    [--selector]\n" +
-                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
-                );
+                "\n"
+        );
+        Intent.printIntentArgsHelp(pw, "");
+        pw.flush();
     }
 
     @Override
@@ -486,10 +447,6 @@
     }
 
     private Intent makeIntent(int defUser) throws URISyntaxException {
-        Intent intent = new Intent();
-        Intent baseIntent = intent;
-        boolean hasIntentInfo = false;
-
         mStartFlags = 0;
         mWaitOption = false;
         mStopOption = false;
@@ -498,316 +455,38 @@
         mSamplingInterval = 0;
         mAutoStop = false;
         mUserId = defUser;
-        Uri data = null;
-        String type = null;
 
-        String opt;
-        while ((opt=nextOption()) != null) {
-            if (opt.equals("-a")) {
-                intent.setAction(nextArgRequired());
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-d")) {
-                data = Uri.parse(nextArgRequired());
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-t")) {
-                type = nextArgRequired();
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-c")) {
-                intent.addCategory(nextArgRequired());
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-e") || opt.equals("--es")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                intent.putExtra(key, value);
-            } else if (opt.equals("--esn")) {
-                String key = nextArgRequired();
-                intent.putExtra(key, (String) null);
-            } else if (opt.equals("--ei")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                intent.putExtra(key, Integer.decode(value));
-            } else if (opt.equals("--eu")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                intent.putExtra(key, Uri.parse(value));
-            } else if (opt.equals("--ecn")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                ComponentName cn = ComponentName.unflattenFromString(value);
-                if (cn == null) throw new IllegalArgumentException("Bad component name: " + value);
-                intent.putExtra(key, cn);
-            } else if (opt.equals("--eia")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                int[] list = new int[strings.length];
-                for (int i = 0; i < strings.length; i++) {
-                    list[i] = Integer.decode(strings[i]);
-                }
-                intent.putExtra(key, list);
-            } else if (opt.equals("--eial")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                ArrayList<Integer> list = new ArrayList<>(strings.length);
-                for (int i = 0; i < strings.length; i++) {
-                    list.add(Integer.decode(strings[i]));
-                }
-                intent.putExtra(key, list);
-            } else if (opt.equals("--el")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                intent.putExtra(key, Long.valueOf(value));
-            } else if (opt.equals("--ela")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                long[] list = new long[strings.length];
-                for (int i = 0; i < strings.length; i++) {
-                    list[i] = Long.valueOf(strings[i]);
-                }
-                intent.putExtra(key, list);
-                hasIntentInfo = true;
-            } else if (opt.equals("--elal")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                ArrayList<Long> list = new ArrayList<>(strings.length);
-                for (int i = 0; i < strings.length; i++) {
-                    list.add(Long.valueOf(strings[i]));
-                }
-                intent.putExtra(key, list);
-                hasIntentInfo = true;
-            } else if (opt.equals("--ef")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                intent.putExtra(key, Float.valueOf(value));
-                hasIntentInfo = true;
-            } else if (opt.equals("--efa")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                float[] list = new float[strings.length];
-                for (int i = 0; i < strings.length; i++) {
-                    list[i] = Float.valueOf(strings[i]);
-                }
-                intent.putExtra(key, list);
-                hasIntentInfo = true;
-            } else if (opt.equals("--efal")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                String[] strings = value.split(",");
-                ArrayList<Float> list = new ArrayList<>(strings.length);
-                for (int i = 0; i < strings.length; i++) {
-                    list.add(Float.valueOf(strings[i]));
-                }
-                intent.putExtra(key, list);
-                hasIntentInfo = true;
-            } else if (opt.equals("--esa")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                // Split on commas unless they are preceeded by an escape.
-                // The escape character must be escaped for the string and
-                // again for the regex, thus four escape characters become one.
-                String[] strings = value.split("(?<!\\\\),");
-                intent.putExtra(key, strings);
-                hasIntentInfo = true;
-            } else if (opt.equals("--esal")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired();
-                // Split on commas unless they are preceeded by an escape.
-                // The escape character must be escaped for the string and
-                // again for the regex, thus four escape characters become one.
-                String[] strings = value.split("(?<!\\\\),");
-                ArrayList<String> list = new ArrayList<>(strings.length);
-                for (int i = 0; i < strings.length; i++) {
-                    list.add(strings[i]);
-                }
-                intent.putExtra(key, list);
-                hasIntentInfo = true;
-            } else if (opt.equals("--ez")) {
-                String key = nextArgRequired();
-                String value = nextArgRequired().toLowerCase();
-                // Boolean.valueOf() results in false for anything that is not "true", which is
-                // error-prone in shell commands
-                boolean arg;
-                if ("true".equals(value) || "t".equals(value)) {
-                    arg = true;
-                } else if ("false".equals(value) || "f".equals(value)) {
-                    arg = false;
+        return Intent.parseCommandArgs(mArgs, new Intent.CommandOptionHandler() {
+            @Override
+            public boolean handleOption(String opt, ShellCommand cmd) {
+                if (opt.equals("-D")) {
+                    mStartFlags |= ActivityManager.START_FLAG_DEBUG;
+                } else if (opt.equals("-W")) {
+                    mWaitOption = true;
+                } else if (opt.equals("-P")) {
+                    mProfileFile = nextArgRequired();
+                    mAutoStop = true;
+                } else if (opt.equals("--start-profiler")) {
+                    mProfileFile = nextArgRequired();
+                    mAutoStop = false;
+                } else if (opt.equals("--sampling")) {
+                    mSamplingInterval = Integer.parseInt(nextArgRequired());
+                } else if (opt.equals("-R")) {
+                    mRepeat = Integer.parseInt(nextArgRequired());
+                } else if (opt.equals("-S")) {
+                    mStopOption = true;
+                } else if (opt.equals("--track-allocation")) {
+                    mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION;
+                } else if (opt.equals("--user")) {
+                    mUserId = parseUserArg(nextArgRequired());
+                } else if (opt.equals("--receiver-permission")) {
+                    mReceiverPermission = nextArgRequired();
                 } else {
-                    try {
-                        arg = Integer.decode(value) != 0;
-                    } catch (NumberFormatException ex) {
-                        throw new IllegalArgumentException("Invalid boolean value: " + value);
-                    }
+                    return false;
                 }
-
-                intent.putExtra(key, arg);
-            } else if (opt.equals("-n")) {
-                String str = nextArgRequired();
-                ComponentName cn = ComponentName.unflattenFromString(str);
-                if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
-                intent.setComponent(cn);
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-p")) {
-                String str = nextArgRequired();
-                intent.setPackage(str);
-                if (intent == baseIntent) {
-                    hasIntentInfo = true;
-                }
-            } else if (opt.equals("-f")) {
-                String str = nextArgRequired();
-                intent.setFlags(Integer.decode(str).intValue());
-            } else if (opt.equals("--grant-read-uri-permission")) {
-                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            } else if (opt.equals("--grant-write-uri-permission")) {
-                intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            } else if (opt.equals("--grant-persistable-uri-permission")) {
-                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
-            } else if (opt.equals("--grant-prefix-uri-permission")) {
-                intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
-            } else if (opt.equals("--exclude-stopped-packages")) {
-                intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
-            } else if (opt.equals("--include-stopped-packages")) {
-                intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
-            } else if (opt.equals("--debug-log-resolution")) {
-                intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
-            } else if (opt.equals("--activity-brought-to-front")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-            } else if (opt.equals("--activity-clear-top")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            } else if (opt.equals("--activity-clear-when-task-reset")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-            } else if (opt.equals("--activity-exclude-from-recents")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            } else if (opt.equals("--activity-launched-from-history")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
-            } else if (opt.equals("--activity-multiple-task")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-            } else if (opt.equals("--activity-no-animation")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-            } else if (opt.equals("--activity-no-history")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-            } else if (opt.equals("--activity-no-user-action")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
-            } else if (opt.equals("--activity-previous-is-top")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-            } else if (opt.equals("--activity-reorder-to-front")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
-            } else if (opt.equals("--activity-reset-task-if-needed")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-            } else if (opt.equals("--activity-single-top")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-            } else if (opt.equals("--activity-clear-task")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            } else if (opt.equals("--activity-task-on-home")) {
-                intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-            } else if (opt.equals("--receiver-registered-only")) {
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            } else if (opt.equals("--receiver-replace-pending")) {
-                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-            } else if (opt.equals("--selector")) {
-                intent.setDataAndType(data, type);
-                intent = new Intent();
-            } else if (opt.equals("-D")) {
-                mStartFlags |= ActivityManager.START_FLAG_DEBUG;
-            } else if (opt.equals("-W")) {
-                mWaitOption = true;
-            } else if (opt.equals("-P")) {
-                mProfileFile = nextArgRequired();
-                mAutoStop = true;
-            } else if (opt.equals("--start-profiler")) {
-                mProfileFile = nextArgRequired();
-                mAutoStop = false;
-            } else if (opt.equals("--sampling")) {
-                mSamplingInterval = Integer.parseInt(nextArgRequired());
-            } else if (opt.equals("-R")) {
-                mRepeat = Integer.parseInt(nextArgRequired());
-            } else if (opt.equals("-S")) {
-                mStopOption = true;
-            } else if (opt.equals("--track-allocation")) {
-                mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION;
-            } else if (opt.equals("--user")) {
-                mUserId = parseUserArg(nextArgRequired());
-            } else if (opt.equals("--receiver-permission")) {
-                mReceiverPermission = nextArgRequired();
-            } else {
-                throw new IllegalArgumentException("Unknown option: " + opt);
+                return true;
             }
-        }
-        intent.setDataAndType(data, type);
-
-        final boolean hasSelector = intent != baseIntent;
-        if (hasSelector) {
-            // A selector was specified; fix up.
-            baseIntent.setSelector(intent);
-            intent = baseIntent;
-        }
-
-        String arg = nextArg();
-        baseIntent = null;
-        if (arg == null) {
-            if (hasSelector) {
-                // If a selector has been specified, and no arguments
-                // have been supplied for the main Intent, then we can
-                // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't
-                // need to have a component name specified yet, the
-                // selector will take care of that.
-                baseIntent = new Intent(Intent.ACTION_MAIN);
-                baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            }
-        } else if (arg.indexOf(':') >= 0) {
-            // The argument is a URI.  Fully parse it, and use that result
-            // to fill in any data not specified so far.
-            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME
-                    | Intent.URI_ANDROID_APP_SCHEME | Intent.URI_ALLOW_UNSAFE);
-        } else if (arg.indexOf('/') >= 0) {
-            // The argument is a component name.  Build an Intent to launch
-            // it.
-            baseIntent = new Intent(Intent.ACTION_MAIN);
-            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            baseIntent.setComponent(ComponentName.unflattenFromString(arg));
-        } else {
-            // Assume the argument is a package name.
-            baseIntent = new Intent(Intent.ACTION_MAIN);
-            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            baseIntent.setPackage(arg);
-        }
-        if (baseIntent != null) {
-            Bundle extras = intent.getExtras();
-            intent.replaceExtras((Bundle)null);
-            Bundle uriExtras = baseIntent.getExtras();
-            baseIntent.replaceExtras((Bundle)null);
-            if (intent.getAction() != null && baseIntent.getCategories() != null) {
-                HashSet<String> cats = new HashSet<String>(baseIntent.getCategories());
-                for (String c : cats) {
-                    baseIntent.removeCategory(c);
-                }
-            }
-            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR);
-            if (extras == null) {
-                extras = uriExtras;
-            } else if (uriExtras != null) {
-                uriExtras.putAll(extras);
-                extras = uriExtras;
-            }
-            intent.replaceExtras(extras);
-            hasIntentInfo = true;
-        }
-
-        if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
-        return intent;
+        });
     }
 
     private void runStartService() throws Exception {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 68b77fe..30fe531 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -18,6 +18,7 @@
 
 import android.content.pm.ApplicationInfo;
 import android.os.ResultReceiver;
+import android.os.ShellCommand;
 import android.provider.MediaStore;
 import android.util.ArraySet;
 
@@ -57,11 +58,13 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.io.Serializable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -3054,21 +3057,21 @@
 
     /**
      * Thermal state when the device is normal. This state is sent in the
-     * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * {@link #ACTION_THERMAL_EVENT} broadcast as {@link #EXTRA_THERMAL_STATE}.
      * {@hide}
      */
     public static final int EXTRA_THERMAL_STATE_NORMAL = 0;
 
     /**
      * Thermal state where the device is approaching its maximum threshold. This state is sent in
-     * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * the {@link #ACTION_THERMAL_EVENT} broadcast as {@link #EXTRA_THERMAL_STATE}.
      * {@hide}
      */
     public static final int EXTRA_THERMAL_STATE_WARNING = 1;
 
     /**
      * Thermal state where the device has reached its maximum threshold. This state is sent in the
-     * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * {@link #ACTION_THERMAL_EVENT} broadcast as {@link #EXTRA_THERMAL_STATE}.
      * {@hide}
      */
     public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2;
@@ -5083,6 +5086,437 @@
         return intent;
     }
 
+    /** @hide */
+    public interface CommandOptionHandler {
+        boolean handleOption(String opt, ShellCommand cmd);
+    }
+
+    /** @hide */
+    public static Intent parseCommandArgs(ShellCommand cmd, CommandOptionHandler optionHandler)
+            throws URISyntaxException {
+        Intent intent = new Intent();
+        Intent baseIntent = intent;
+        boolean hasIntentInfo = false;
+
+        Uri data = null;
+        String type = null;
+
+        String opt;
+        while ((opt=cmd.getNextOption()) != null) {
+            switch (opt) {
+                case "-a":
+                    intent.setAction(cmd.getNextArgRequired());
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                    break;
+                case "-d":
+                    data = Uri.parse(cmd.getNextArgRequired());
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                    break;
+                case "-t":
+                    type = cmd.getNextArgRequired();
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                    break;
+                case "-c":
+                    intent.addCategory(cmd.getNextArgRequired());
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                    break;
+                case "-e":
+                case "--es": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    intent.putExtra(key, value);
+                }
+                break;
+                case "--esn": {
+                    String key = cmd.getNextArgRequired();
+                    intent.putExtra(key, (String) null);
+                }
+                break;
+                case "--ei": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    intent.putExtra(key, Integer.decode(value));
+                }
+                break;
+                case "--eu": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    intent.putExtra(key, Uri.parse(value));
+                }
+                break;
+                case "--ecn": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    ComponentName cn = ComponentName.unflattenFromString(value);
+                    if (cn == null)
+                        throw new IllegalArgumentException("Bad component name: " + value);
+                    intent.putExtra(key, cn);
+                }
+                break;
+                case "--eia": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    int[] list = new int[strings.length];
+                    for (int i = 0; i < strings.length; i++) {
+                        list[i] = Integer.decode(strings[i]);
+                    }
+                    intent.putExtra(key, list);
+                }
+                break;
+                case "--eial": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    ArrayList<Integer> list = new ArrayList<>(strings.length);
+                    for (int i = 0; i < strings.length; i++) {
+                        list.add(Integer.decode(strings[i]));
+                    }
+                    intent.putExtra(key, list);
+                }
+                break;
+                case "--el": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    intent.putExtra(key, Long.valueOf(value));
+                }
+                break;
+                case "--ela": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    long[] list = new long[strings.length];
+                    for (int i = 0; i < strings.length; i++) {
+                        list[i] = Long.valueOf(strings[i]);
+                    }
+                    intent.putExtra(key, list);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--elal": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    ArrayList<Long> list = new ArrayList<>(strings.length);
+                    for (int i = 0; i < strings.length; i++) {
+                        list.add(Long.valueOf(strings[i]));
+                    }
+                    intent.putExtra(key, list);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--ef": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    intent.putExtra(key, Float.valueOf(value));
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--efa": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    float[] list = new float[strings.length];
+                    for (int i = 0; i < strings.length; i++) {
+                        list[i] = Float.valueOf(strings[i]);
+                    }
+                    intent.putExtra(key, list);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--efal": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    String[] strings = value.split(",");
+                    ArrayList<Float> list = new ArrayList<>(strings.length);
+                    for (int i = 0; i < strings.length; i++) {
+                        list.add(Float.valueOf(strings[i]));
+                    }
+                    intent.putExtra(key, list);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--esa": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    // Split on commas unless they are preceeded by an escape.
+                    // The escape character must be escaped for the string and
+                    // again for the regex, thus four escape characters become one.
+                    String[] strings = value.split("(?<!\\\\),");
+                    intent.putExtra(key, strings);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--esal": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired();
+                    // Split on commas unless they are preceeded by an escape.
+                    // The escape character must be escaped for the string and
+                    // again for the regex, thus four escape characters become one.
+                    String[] strings = value.split("(?<!\\\\),");
+                    ArrayList<String> list = new ArrayList<>(strings.length);
+                    for (int i = 0; i < strings.length; i++) {
+                        list.add(strings[i]);
+                    }
+                    intent.putExtra(key, list);
+                    hasIntentInfo = true;
+                }
+                break;
+                case "--ez": {
+                    String key = cmd.getNextArgRequired();
+                    String value = cmd.getNextArgRequired().toLowerCase();
+                    // Boolean.valueOf() results in false for anything that is not "true", which is
+                    // error-prone in shell commands
+                    boolean arg;
+                    if ("true".equals(value) || "t".equals(value)) {
+                        arg = true;
+                    } else if ("false".equals(value) || "f".equals(value)) {
+                        arg = false;
+                    } else {
+                        try {
+                            arg = Integer.decode(value) != 0;
+                        } catch (NumberFormatException ex) {
+                            throw new IllegalArgumentException("Invalid boolean value: " + value);
+                        }
+                    }
+
+                    intent.putExtra(key, arg);
+                }
+                break;
+                case "-n": {
+                    String str = cmd.getNextArgRequired();
+                    ComponentName cn = ComponentName.unflattenFromString(str);
+                    if (cn == null)
+                        throw new IllegalArgumentException("Bad component name: " + str);
+                    intent.setComponent(cn);
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                }
+                break;
+                case "-p": {
+                    String str = cmd.getNextArgRequired();
+                    intent.setPackage(str);
+                    if (intent == baseIntent) {
+                        hasIntentInfo = true;
+                    }
+                }
+                break;
+                case "-f":
+                    String str = cmd.getNextArgRequired();
+                    intent.setFlags(Integer.decode(str).intValue());
+                    break;
+                case "--grant-read-uri-permission":
+                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                    break;
+                case "--grant-write-uri-permission":
+                    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                    break;
+                case "--grant-persistable-uri-permission":
+                    intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+                    break;
+                case "--grant-prefix-uri-permission":
+                    intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
+                    break;
+                case "--exclude-stopped-packages":
+                    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
+                    break;
+                case "--include-stopped-packages":
+                    intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+                    break;
+                case "--debug-log-resolution":
+                    intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+                    break;
+                case "--activity-brought-to-front":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+                    break;
+                case "--activity-clear-top":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    break;
+                case "--activity-clear-when-task-reset":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                    break;
+                case "--activity-exclude-from-recents":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                    break;
+                case "--activity-launched-from-history":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+                    break;
+                case "--activity-multiple-task":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                    break;
+                case "--activity-no-animation":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+                    break;
+                case "--activity-no-history":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+                    break;
+                case "--activity-no-user-action":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
+                    break;
+                case "--activity-previous-is-top":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+                    break;
+                case "--activity-reorder-to-front":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+                    break;
+                case "--activity-reset-task-if-needed":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                    break;
+                case "--activity-single-top":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+                    break;
+                case "--activity-clear-task":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                    break;
+                case "--activity-task-on-home":
+                    intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+                    break;
+                case "--receiver-registered-only":
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    break;
+                case "--receiver-replace-pending":
+                    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+                    break;
+                case "--selector":
+                    intent.setDataAndType(data, type);
+                    intent = new Intent();
+                    break;
+                default:
+                    if (optionHandler != null && optionHandler.handleOption(opt, cmd)) {
+                        // Okay, caller handled this option.
+                    } else {
+                        throw new IllegalArgumentException("Unknown option: " + opt);
+                    }
+                    break;
+            }
+        }
+        intent.setDataAndType(data, type);
+
+        final boolean hasSelector = intent != baseIntent;
+        if (hasSelector) {
+            // A selector was specified; fix up.
+            baseIntent.setSelector(intent);
+            intent = baseIntent;
+        }
+
+        String arg = cmd.getNextArg();
+        baseIntent = null;
+        if (arg == null) {
+            if (hasSelector) {
+                // If a selector has been specified, and no arguments
+                // have been supplied for the main Intent, then we can
+                // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't
+                // need to have a component name specified yet, the
+                // selector will take care of that.
+                baseIntent = new Intent(Intent.ACTION_MAIN);
+                baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            }
+        } else if (arg.indexOf(':') >= 0) {
+            // The argument is a URI.  Fully parse it, and use that result
+            // to fill in any data not specified so far.
+            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME
+                    | Intent.URI_ANDROID_APP_SCHEME | Intent.URI_ALLOW_UNSAFE);
+        } else if (arg.indexOf('/') >= 0) {
+            // The argument is a component name.  Build an Intent to launch
+            // it.
+            baseIntent = new Intent(Intent.ACTION_MAIN);
+            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            baseIntent.setComponent(ComponentName.unflattenFromString(arg));
+        } else {
+            // Assume the argument is a package name.
+            baseIntent = new Intent(Intent.ACTION_MAIN);
+            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            baseIntent.setPackage(arg);
+        }
+        if (baseIntent != null) {
+            Bundle extras = intent.getExtras();
+            intent.replaceExtras((Bundle)null);
+            Bundle uriExtras = baseIntent.getExtras();
+            baseIntent.replaceExtras((Bundle)null);
+            if (intent.getAction() != null && baseIntent.getCategories() != null) {
+                HashSet<String> cats = new HashSet<String>(baseIntent.getCategories());
+                for (String c : cats) {
+                    baseIntent.removeCategory(c);
+                }
+            }
+            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_SELECTOR);
+            if (extras == null) {
+                extras = uriExtras;
+            } else if (uriExtras != null) {
+                uriExtras.putAll(extras);
+                extras = uriExtras;
+            }
+            intent.replaceExtras(extras);
+            hasIntentInfo = true;
+        }
+
+        if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
+        return intent;
+    }
+
+    /** @hide */
+    public static void printIntentArgsHelp(PrintWriter pw, String prefix) {
+        final String[] lines = new String[] {
+                "<INTENT> specifications include these flags and arguments:",
+                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]",
+                "    [-c <CATEGORY> [-c <CATEGORY>] ...]",
+                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]",
+                "    [--esn <EXTRA_KEY> ...]",
+                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]",
+                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]",
+                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]",
+                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]",
+                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]",
+                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]",
+                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]",
+                "        (mutiple extras passed as Integer[])",
+                "    [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]",
+                "        (mutiple extras passed as List<Integer>)",
+                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]",
+                "        (mutiple extras passed as Long[])",
+                "    [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]",
+                "        (mutiple extras passed as List<Long>)",
+                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]",
+                "        (mutiple extras passed as Float[])",
+                "    [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]",
+                "        (mutiple extras passed as List<Float>)",
+                "    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]",
+                "        (mutiple extras passed as String[]; to embed a comma into a string,",
+                "         escape it using \"\\,\")",
+                "    [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]",
+                "        (mutiple extras passed as List<String>; to embed a comma into a string,",
+                "         escape it using \"\\,\")",
+                "    [--grant-read-uri-permission] [--grant-write-uri-permission]",
+                "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]",
+                "    [--debug-log-resolution] [--exclude-stopped-packages]",
+                "    [--include-stopped-packages]",
+                "    [--activity-brought-to-front] [--activity-clear-top]",
+                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]",
+                "    [--activity-launched-from-history] [--activity-multiple-task]",
+                "    [--activity-no-animation] [--activity-no-history]",
+                "    [--activity-no-user-action] [--activity-previous-is-top]",
+                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]",
+                "    [--activity-single-top] [--activity-clear-task]",
+                "    [--activity-task-on-home]",
+                "    [--receiver-registered-only] [--receiver-replace-pending]",
+                "    [--selector]",
+                "    [<URI> | <PACKAGE> | <COMPONENT>]"
+        };
+        for (String line : lines) {
+            pw.print(prefix);
+            pw.println(line);
+        }
+    }
+
     /**
      * Retrieve the general action to be performed, such as
      * {@link #ACTION_VIEW}.  The action describes the general way the rest of
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index cad482b..6f12b62 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -48,19 +48,35 @@
     private FastPrintWriter mErrPrintWriter;
     private InputStream mInputStream;
 
-    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ResultReceiver resultReceiver) {
+    public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, int firstArgPos) {
         mTarget = target;
         mIn = in;
         mOut = out;
         mErr = err;
         mArgs = args;
-        mResultReceiver = resultReceiver;
-        mCmd = args != null && args.length > 0 ? args[0] : null;
-        mArgPos = 1;
+        mResultReceiver = null;
+        mCmd = null;
+        mArgPos = firstArgPos;
         mCurArgData = null;
         mOutPrintWriter = null;
         mErrPrintWriter = null;
+    }
+
+    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ResultReceiver resultReceiver) {
+        String cmd;
+        int start;
+        if (args != null && args.length > 0) {
+            cmd = args[0];
+            start = 1;
+        } else {
+            cmd = null;
+            start = 0;
+        }
+        init(target, in, out, err, args, start);
+        mCmd = cmd;
+        mResultReceiver = resultReceiver;
 
         if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget);
         int res = -1;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 95da438..f946ca7 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -256,6 +256,23 @@
         }
     }
 
+    /** @hide */
+    public static int parseUserArg(String arg) {
+        int userId;
+        if ("all".equals(arg)) {
+            userId = UserHandle.USER_ALL;
+        } else if ("current".equals(arg) || "cur".equals(arg)) {
+            userId = UserHandle.USER_CURRENT;
+        } else {
+            try {
+                userId = Integer.parseInt(arg);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Bad user number: " + arg);
+            }
+        }
+        return userId;
+    }
+
     /**
      * Returns the user id of the current process
      * @return user id of the current process
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index e26b27d..c067da7 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -17,13 +17,19 @@
 
 package com.android.internal.os;
 
+import android.os.ShellCommand;
+
 import java.io.PrintStream;
 
 public abstract class BaseCommand {
 
-    protected String[] mArgs;
-    private int mNextArg;
-    private String mCurArgData;
+    final protected ShellCommand mArgs = new ShellCommand() {
+        @Override public int onCommand(String cmd) {
+            return 0;
+        }
+        @Override public void onHelp() {
+        }
+    };
 
     // These are magic strings understood by the Eclipse plugin.
     public static final String FATAL_ERROR_CODE = "Error type 1";
@@ -39,9 +45,7 @@
             return;
         }
 
-        mArgs = args;
-        mNextArg = 0;
-        mCurArgData = null;
+        mArgs.init(null, null, null, null, args, 0);
 
         try {
             onRun();
@@ -87,32 +91,7 @@
      * starts with '-'.  If the next argument is not an option, null is returned.
      */
     public String nextOption() {
-        if (mCurArgData != null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
-        }
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        if (!arg.startsWith("-")) {
-            return null;
-        }
-        mNextArg++;
-        if (arg.equals("--")) {
-            return null;
-        }
-        if (arg.length() > 1 && arg.charAt(1) != '-') {
-            if (arg.length() > 2) {
-                mCurArgData = arg.substring(2);
-                return arg.substring(0, 2);
-            } else {
-                mCurArgData = null;
-                return arg;
-            }
-        }
-        mCurArgData = null;
-        return arg;
+        return mArgs.getNextOption();
     }
 
     /**
@@ -120,15 +99,7 @@
      * no arguments left, return null.
      */
     public String nextArg() {
-        if (mCurArgData != null) {
-            String arg = mCurArgData;
-            mCurArgData = null;
-            return arg;
-        } else if (mNextArg < mArgs.length) {
-            return mArgs[mNextArg++];
-        } else {
-            return null;
-        }
+        return mArgs.getNextArg();
     }
 
     /**
@@ -136,11 +107,6 @@
      * no arguments left, throws an IllegalArgumentException to report this to the user.
      */
     public String nextArgRequired() {
-        String arg = nextArg();
-        if (arg == null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
-        }
-        return arg;
+        return mArgs.getNextArgRequired();
     }
 }
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 3359060..43d10c7 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -226,7 +226,7 @@
             final int N = a.length;
             boolean printedHeader = false;
             F filter;
-            if (collapseDuplicates) {
+            if (collapseDuplicates && !printFilter) {
                 found.clear();
                 for (int i=0; i<N && (filter=a[i]) != null; i++) {
                     if (packageName != null && !isPackageForFilter(packageName, filter)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d1e7e85..13c1417 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -73,7 +73,7 @@
         String opt;
         while ((opt = getNextOption()) != null) {
             if (opt.equals("--user")) {
-                userId = parseUserArg(getNextArgRequired());
+                userId = UserHandle.parseUserArg(getNextArgRequired());
             } else {
                 pw.println("Error: Unknown option: " + opt);
                 return -1;
@@ -89,7 +89,7 @@
         String opt;
         while ((opt=getNextOption()) != null) {
             if (opt.equals("--user")) {
-                userId = parseUserArg(getNextArgRequired());
+                userId = UserHandle.parseUserArg(getNextArgRequired());
             } else {
                 pw.println("Error: Unknown option: " + opt);
                 return -1;
@@ -141,22 +141,6 @@
         return 0;
     }
 
-    int parseUserArg(String arg) {
-        int userId;
-        if ("all".equals(arg)) {
-            userId = UserHandle.USER_ALL;
-        } else if ("current".equals(arg) || "cur".equals(arg)) {
-            userId = UserHandle.USER_CURRENT;
-        } else {
-            try {
-                userId = Integer.parseInt(arg);
-            } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("Bad user number: " + arg);
-            }
-        }
-        return userId;
-    }
-
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index add7a98..1da3140 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14837,20 +14837,23 @@
     static class DumpState {
         public static final int DUMP_LIBS = 1 << 0;
         public static final int DUMP_FEATURES = 1 << 1;
-        public static final int DUMP_RESOLVERS = 1 << 2;
-        public static final int DUMP_PERMISSIONS = 1 << 3;
-        public static final int DUMP_PACKAGES = 1 << 4;
-        public static final int DUMP_SHARED_USERS = 1 << 5;
-        public static final int DUMP_MESSAGES = 1 << 6;
-        public static final int DUMP_PROVIDERS = 1 << 7;
-        public static final int DUMP_VERIFIERS = 1 << 8;
-        public static final int DUMP_PREFERRED = 1 << 9;
-        public static final int DUMP_PREFERRED_XML = 1 << 10;
-        public static final int DUMP_KEYSETS = 1 << 11;
-        public static final int DUMP_VERSION = 1 << 12;
-        public static final int DUMP_INSTALLS = 1 << 13;
-        public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 14;
-        public static final int DUMP_DOMAIN_PREFERRED = 1 << 15;
+        public static final int DUMP_ACTIVITY_RESOLVERS = 1 << 2;
+        public static final int DUMP_SERVICE_RESOLVERS = 1 << 3;
+        public static final int DUMP_RECEIVER_RESOLVERS = 1 << 4;
+        public static final int DUMP_CONTENT_RESOLVERS = 1 << 5;
+        public static final int DUMP_PERMISSIONS = 1 << 6;
+        public static final int DUMP_PACKAGES = 1 << 7;
+        public static final int DUMP_SHARED_USERS = 1 << 8;
+        public static final int DUMP_MESSAGES = 1 << 9;
+        public static final int DUMP_PROVIDERS = 1 << 10;
+        public static final int DUMP_VERIFIERS = 1 << 11;
+        public static final int DUMP_PREFERRED = 1 << 12;
+        public static final int DUMP_PREFERRED_XML = 1 << 13;
+        public static final int DUMP_KEYSETS = 1 << 14;
+        public static final int DUMP_VERSION = 1 << 15;
+        public static final int DUMP_INSTALLS = 1 << 16;
+        public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
+        public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
 
         public static final int OPTION_SHOW_FILTERS = 1 << 0;
 
@@ -14949,9 +14952,9 @@
                 pw.println("    -h: print this help");
                 pw.println("  cmd may be one of:");
                 pw.println("    l[ibraries]: list known shared libraries");
-                pw.println("    f[ibraries]: list device features");
+                pw.println("    f[eatures]: list device features");
                 pw.println("    k[eysets]: print known keysets");
-                pw.println("    r[esolvers]: dump intent resolvers");
+                pw.println("    r[esolvers] [activity|service|receiver|content]: dump intent resolvers");
                 pw.println("    perm[issions]: dump permissions");
                 pw.println("    permission [name ...]: dump declaration and use of given permission");
                 pw.println("    pref[erred]: print preferred package settings");
@@ -15018,7 +15021,29 @@
             } else if ("f".equals(cmd) || "features".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_FEATURES);
             } else if ("r".equals(cmd) || "resolvers".equals(cmd)) {
-                dumpState.setDump(DumpState.DUMP_RESOLVERS);
+                if (opti >= args.length) {
+                    dumpState.setDump(DumpState.DUMP_ACTIVITY_RESOLVERS
+                            | DumpState.DUMP_SERVICE_RESOLVERS
+                            | DumpState.DUMP_RECEIVER_RESOLVERS
+                            | DumpState.DUMP_CONTENT_RESOLVERS);
+                } else {
+                    while (opti < args.length) {
+                        String name = args[opti];
+                        if ("a".equals(name) || "activity".equals(name)) {
+                            dumpState.setDump(DumpState.DUMP_ACTIVITY_RESOLVERS);
+                        } else if ("s".equals(name) || "service".equals(name)) {
+                            dumpState.setDump(DumpState.DUMP_SERVICE_RESOLVERS);
+                        } else if ("r".equals(name) || "receiver".equals(name)) {
+                            dumpState.setDump(DumpState.DUMP_RECEIVER_RESOLVERS);
+                        } else if ("c".equals(name) || "content".equals(name)) {
+                            dumpState.setDump(DumpState.DUMP_CONTENT_RESOLVERS);
+                        } else {
+                            pw.println("Error: unknown resolver table type: " + name);
+                            return;
+                        }
+                        opti++;
+                    }
+                }
             } else if ("perm".equals(cmd) || "permissions".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_PERMISSIONS);
             } else if ("permission".equals(cmd)) {
@@ -15185,22 +15210,28 @@
                 }
             }
 
-            if (!checkin && dumpState.isDumping(DumpState.DUMP_RESOLVERS)) {
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
                 if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
                         : "Activity Resolver Table:", "  ", packageName,
                         dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
                     dumpState.setTitlePrinted(true);
                 }
+            }
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
                 if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
                         : "Receiver Resolver Table:", "  ", packageName,
                         dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
                     dumpState.setTitlePrinted(true);
                 }
+            }
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
                 if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
                         : "Service Resolver Table:", "  ", packageName,
                         dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
                     dumpState.setTitlePrinted(true);
                 }
+            }
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
                 if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:"
                         : "Provider Resolver Table:", "  ", packageName,
                         dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS), true)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d7176fd..2cedc9c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -35,6 +35,7 @@
 import android.content.pm.PermissionInfo;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.ResolveInfo;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
@@ -46,6 +47,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 
+import android.util.PrintWriterPrinter;
 import com.android.internal.util.SizedInputStream;
 
 import libcore.io.IoUtils;
@@ -56,6 +58,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -68,6 +71,7 @@
     final IPackageManager mInterface;
     final private WeakHashMap<String, Resources> mResourceCache =
             new WeakHashMap<String, Resources>();
+    int mTargetUser;
 
     PackageManagerShellCommand(PackageManagerService service) {
         mInterface = service;
@@ -97,6 +101,12 @@
                     return runList();
                 case "uninstall":
                     return runUninstall();
+                case "query-intent-activities":
+                    return runQueryIntentActivities();
+                case "query-intent-services":
+                    return runQueryIntentServices();
+                case "query-intent-receivers":
+                    return runQueryIntentReceivers();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -340,7 +350,7 @@
                         listThirdParty = true;
                         break;
                     case "--user":
-                        userId = Integer.parseInt(getNextArg());
+                        userId = UserHandle.parseUserArg(getNextArgRequired());
                         break;
                     default:
                         pw.println("Error: Unknown option: " + opt);
@@ -487,7 +497,7 @@
                     flags |= PackageManager.DELETE_KEEP_DATA;
                     break;
                 case "--user":
-                    userId = Integer.parseInt(getNextArg());
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
                 default:
                     pw.println("Error: Unknown option: " + opt);
@@ -538,6 +548,104 @@
         }
     }
 
+    private Intent parseIntentAndUser() throws URISyntaxException {
+        mTargetUser = UserHandle.USER_CURRENT;
+        Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
+            @Override
+            public boolean handleOption(String opt, ShellCommand cmd) {
+                if ("--user".equals(opt)) {
+                    mTargetUser = UserHandle.parseUserArg(cmd.getNextArgRequired());
+                    return true;
+                }
+                return false;
+            }
+        });
+        mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), mTargetUser, false, false, null, null);
+        return intent;
+    }
+
+    private int runQueryIntentActivities() {
+        Intent intent;
+        try {
+            intent = parseIntentAndUser();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        try {
+            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0,
+                    mTargetUser);
+            PrintWriter pw = getOutPrintWriter();
+            if (result == null || result.size() <= 0) {
+                pw.println("No activities found");
+            } else {
+                pw.print(result.size()); pw.println(" activities found:");
+                PrintWriterPrinter pr = new PrintWriterPrinter(pw);
+                for (int i=0; i<result.size(); i++) {
+                    pw.print("  Activity #"); pw.print(i); pw.println(":");
+                    result.get(i).dump(pr, "    ");
+                }
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed calling service", e);
+        }
+        return 0;
+    }
+
+    private int runQueryIntentServices() {
+        Intent intent;
+        try {
+            intent = parseIntentAndUser();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        try {
+            List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0,
+                    mTargetUser);
+            PrintWriter pw = getOutPrintWriter();
+            if (result == null || result.size() <= 0) {
+                pw.println("No services found");
+            } else {
+                pw.print(result.size()); pw.println(" services found:");
+                PrintWriterPrinter pr = new PrintWriterPrinter(pw);
+                for (int i=0; i<result.size(); i++) {
+                    pw.print("  Service #"); pw.print(i); pw.println(":");
+                    result.get(i).dump(pr, "    ");
+                }
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed calling service", e);
+        }
+        return 0;
+    }
+
+    private int runQueryIntentReceivers() {
+        Intent intent;
+        try {
+            intent = parseIntentAndUser();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        try {
+            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0,
+                    mTargetUser);
+            PrintWriter pw = getOutPrintWriter();
+            if (result == null || result.size() <= 0) {
+                pw.println("No receivers found");
+            } else {
+                pw.print(result.size()); pw.println(" receivers found:");
+                PrintWriterPrinter pr = new PrintWriterPrinter(pw);
+                for (int i=0; i<result.size(); i++) {
+                    pw.print("  Receiver #"); pw.print(i); pw.println(":");
+                    result.get(i).dump(pr, "    ");
+                }
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed calling service", e);
+        }
+        return 0;
+    }
+
     private static class InstallParams {
         SessionParams sessionParams;
         String installerPackageName;
@@ -598,7 +706,7 @@
                     sessionParams.abiOverride = checkAbiArgument(getNextArg());
                     break;
                 case "--user":
-                    params.userId = Integer.parseInt(getNextArg());
+                    params.userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
                 case "--install-location":
                     sessionParams.installLocation = Integer.parseInt(getNextArg());
@@ -908,7 +1016,14 @@
         pw.println("      -s: short summary");
         pw.println("      -d: only list dangerous permissions");
         pw.println("      -u: list only the permissions users will see");
-        pw.println("");
+        pw.println("  query-intent-activities [--user USER_ID] INTENT");
+        pw.println("    Prints all activities that can handle the given Intent.");
+        pw.println("  query-intent-services [--user USER_ID] INTENT");
+        pw.println("    Prints all services that can handle the given Intent.");
+        pw.println("  query-intent-receivers [--user USER_ID] INTENT");
+        pw.println("    Prints all broadcast receivers that can handle the given Intent.");
+        pw.println();
+        Intent.printIntentArgsHelp(pw , "");
     }
 
     private static class LocalIntentReceiver {