Add <intent-filter> support to <provider>.

For the new documents work, we're only interested in the subset of
ContentProviders that actually implement DocumentsContract.  Instead
of returning all providers, add <intent-filter> support to make it
easier to limit the set of returned ProviderInfo.

Define a well-known action for DocumentsProviders, and start using it
when querying for roots.  Continue supporting the old <meta-data>
approach until all apps have been updated.

Bug: 8599233
Change-Id: I05f049bba21311f5421738002f99ee214447c909
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index e360e40..1ff41c0 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -23,6 +23,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Printer;
+import android.util.Slog;
 
 import java.text.Collator;
 import java.util.Comparator;
@@ -34,20 +35,30 @@
  * &lt;intent&gt; tags.
  */
 public class ResolveInfo implements Parcelable {
+    private static final String TAG = "ResolveInfo";
+
     /**
-     * The activity or broadcast receiver that corresponds to this resolution match,
-     * if this resolution is for an activity or broadcast receiver. One and only one of this and
-     * serviceInfo must be non-null.
+     * The activity or broadcast receiver that corresponds to this resolution
+     * match, if this resolution is for an activity or broadcast receiver.
+     * Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or
+     * {@link #providerInfo} will be non-null.
      */
     public ActivityInfo activityInfo;
     
     /**
-     * The service that corresponds to this resolution match, if this
-     * resolution is for a service. One and only one of this and
-     * activityInfo must be non-null.
+     * The service that corresponds to this resolution match, if this resolution
+     * is for a service. Exactly one of {@link #activityInfo},
+     * {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
      */
     public ServiceInfo serviceInfo;
-    
+
+    /**
+     * The provider that corresponds to this resolution match, if this
+     * resolution is for a provider. Exactly one of {@link #activityInfo},
+     * {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
+     */
+    public ProviderInfo providerInfo;
+
     /**
      * The IntentFilter that was matched for this ResolveInfo.
      */
@@ -120,6 +131,13 @@
      */
     public boolean system;
 
+    private ComponentInfo getComponentInfo() {
+        if (activityInfo != null) return activityInfo;
+        if (serviceInfo != null) return serviceInfo;
+        if (providerInfo != null) return providerInfo;
+        throw new IllegalStateException("Missing ComponentInfo!");
+    }
+
     /**
      * Retrieve the current textual label associated with this resolution.  This
      * will call back on the given PackageManager to load the label from
@@ -142,7 +160,7 @@
                 return label.toString().trim();
             }
         }
-        ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
+        ComponentInfo ci = getComponentInfo();
         ApplicationInfo ai = ci.applicationInfo;
         if (labelRes != 0) {
             label = pm.getText(ci.packageName, labelRes, ai);
@@ -176,7 +194,7 @@
                 return dr;
             }
         }
-        ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
+        ComponentInfo ci = getComponentInfo();
         ApplicationInfo ai = ci.applicationInfo;
         if (icon != 0) {
             dr = pm.getDrawable(ci.packageName, icon, ai);
@@ -196,8 +214,8 @@
      */
     public final int getIconResource() {
         if (icon != 0) return icon;
-        if (activityInfo != null) return activityInfo.getIconResource();
-        if (serviceInfo != null) return serviceInfo.getIconResource();
+        final ComponentInfo ci = getComponentInfo();
+        if (ci != null) return ci.getIconResource();
         return 0;
     }
 
@@ -225,6 +243,9 @@
         } else if (serviceInfo != null) {
             pw.println(prefix + "ServiceInfo:");
             serviceInfo.dump(pw, prefix + "  ");
+        } else if (providerInfo != null) {
+            pw.println(prefix + "ProviderInfo:");
+            providerInfo.dump(pw, prefix + "  ");
         }
     }
     
@@ -234,6 +255,7 @@
     public ResolveInfo(ResolveInfo orig) {
         activityInfo = orig.activityInfo;
         serviceInfo = orig.serviceInfo;
+        providerInfo = orig.providerInfo;
         filter = orig.filter;
         priority = orig.priority;
         preferredOrder = orig.preferredOrder;
@@ -247,7 +269,7 @@
     }
 
     public String toString() {
-        ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
+        final ComponentInfo ci = getComponentInfo();
         StringBuilder sb = new StringBuilder(128);
         sb.append("ResolveInfo{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
@@ -278,6 +300,9 @@
         } else if (serviceInfo != null) {
             dest.writeInt(2);
             serviceInfo.writeToParcel(dest, parcelableFlags);
+        } else if (providerInfo != null) {
+            dest.writeInt(3);
+            providerInfo.writeToParcel(dest, parcelableFlags);
         } else {
             dest.writeInt(0);
         }
@@ -309,18 +334,21 @@
     };
 
     private ResolveInfo(Parcel source) {
+        activityInfo = null;
+        serviceInfo = null;
+        providerInfo = null;
         switch (source.readInt()) {
             case 1:
                 activityInfo = ActivityInfo.CREATOR.createFromParcel(source);
-                serviceInfo = null;
                 break;
             case 2:
                 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source);
-                activityInfo = null;
+                break;
+            case 3:
+                providerInfo = ProviderInfo.CREATOR.createFromParcel(source);
                 break;
             default:
-                activityInfo = null;
-                serviceInfo = null;
+                Slog.w(TAG, "Missing ComponentInfo!");
                 break;
         }
         if (source.readInt() != 0) {