Add support for queryIntentService() from Manfest. (#3153)

diff --git a/robolectric-resources/src/main/java/org/robolectric/manifest/AndroidManifest.java b/robolectric-resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
index 32b2fd3..6e90753 100644
--- a/robolectric-resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
+++ b/robolectric-resources/src/main/java/org/robolectric/manifest/AndroidManifest.java
@@ -280,7 +280,8 @@
       String serviceName = resolveClassRef(namedItem.getTextContent());
       MetaData metaData = new MetaData(getChildrenTags(serviceNode, "meta-data"));
 
-      ServiceData service = new ServiceData(serviceName, metaData);
+      final List<IntentFilterData> intentFilterData = parseIntentFilters(serviceNode);
+      ServiceData service = new ServiceData(serviceName, metaData, intentFilterData);
       List<Node> intentFilters = getChildrenTags(serviceNode, "intent-filter");
       for (Node intentFilterNode : intentFilters) {
         for (Node actionNode : getChildrenTags(intentFilterNode, "action")) {
@@ -290,7 +291,7 @@
           }
         }
       }
-      
+
       Node permissionItem = serviceNode.getAttributes().getNamedItem("android:permission");
       if (permissionItem != null) {
         service.setPermission(permissionItem.getTextContent());
diff --git a/robolectric-resources/src/main/java/org/robolectric/manifest/ServiceData.java b/robolectric-resources/src/main/java/org/robolectric/manifest/ServiceData.java
index 36f93bf..cde5bcc 100644
--- a/robolectric-resources/src/main/java/org/robolectric/manifest/ServiceData.java
+++ b/robolectric-resources/src/main/java/org/robolectric/manifest/ServiceData.java
@@ -1,6 +1,7 @@
 package org.robolectric.manifest;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
 public class ServiceData {
@@ -8,11 +9,13 @@
   private final MetaData metaData;
   private final List<String> actions;
   private String permission;
+  private List<IntentFilterData> intentFilters;
 
-  public ServiceData(String className, MetaData metaData) {
+  public ServiceData(String className, MetaData metaData, List<IntentFilterData> intentFilterData) {
     this.actions = new ArrayList<>();
     this.className = className;
     this.metaData = metaData;
+    intentFilters = new LinkedList<>(intentFilterData);
   }
 
   public String getClassName() {
@@ -38,4 +41,12 @@
   public String getPermission() {
     return permission;
   }
+
+  /**
+   * Get the intent filters defined for activity.
+   * @return A list of intent filters. Not null.
+   */
+  public List<IntentFilterData> getIntentFilters() {
+    return intentFilters;
+  }
 }
diff --git a/robolectric/src/main/java/org/robolectric/res/builder/DefaultPackageManager.java b/robolectric/src/main/java/org/robolectric/res/builder/DefaultPackageManager.java
index b8584be..c8e8d51 100644
--- a/robolectric/src/main/java/org/robolectric/res/builder/DefaultPackageManager.java
+++ b/robolectric/src/main/java/org/robolectric/res/builder/DefaultPackageManager.java
@@ -378,7 +378,42 @@
 
   @Override
   public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
-    return queryIntent(intent, flags);
+    // Check the manually added resolve infos first.
+    List<ResolveInfo> resolveInfos = queryIntent(intent, flags);
+    if (!resolveInfos.isEmpty()) {
+      return resolveInfos;
+    }
+
+    // Check matches from the manifest.
+    resolveInfos = new ArrayList<>();
+    if (resolveInfos.isEmpty()) {
+      for (ServiceData service : applicationManifest.getServices()) {
+        IntentFilter intentFilter = matchIntentFilter(intent, service.getIntentFilters());
+        if (intentFilter != null) {
+          resolveInfos.add(getResolveInfo(service, intentFilter, applicationManifest.getPackageName()));
+        }
+      }
+    }
+
+    return resolveInfos;
+  }
+
+  private static ResolveInfo getResolveInfo(ServiceData service, IntentFilter intentFilter, String packageName) {
+    try {
+      ResolveInfo info = new ResolveInfo();
+      info.isDefault = intentFilter.hasCategory("Intent.CATEGORY_DEFAULT");
+      info.serviceInfo = new ServiceInfo();
+      info.serviceInfo.name = service.getClassName();
+      info.serviceInfo.packageName = packageName;
+      info.serviceInfo.applicationInfo = new ApplicationInfo();
+      info.filter = new IntentFilter();
+      for (Iterator<String> it = intentFilter.typesIterator(); it.hasNext(); ) {
+        info.filter.addDataType(it.next());
+      }
+      return info;
+    } catch (IntentFilter.MalformedMimeTypeException e) {
+      throw new RuntimeException(e);
+    }
   }
 
   @Override
@@ -861,7 +896,8 @@
           activityName = activityData.getTargetActivityName();
         }
 
-        if (matchIntentFilter(activityData, intent)) {
+        IntentFilter intentFilter = matchIntentFilter(intent, activityData.getIntentFilters());
+        if (intentFilter != null) {
           ResolveInfo resolveInfo = new ResolveInfo();
           resolveInfo.resolvePackageName = packageName;
           resolveInfo.activityInfo = new ActivityInfo();
@@ -875,8 +911,8 @@
     return resolveInfoList;
   }
 
-  private boolean matchIntentFilter(ActivityData activityData, Intent intent) {
-    for (IntentFilterData intentFilterData : activityData.getIntentFilters()) {
+  private IntentFilter matchIntentFilter(Intent intent, List<IntentFilterData> intentFilters) {
+    for (IntentFilterData intentFilterData : intentFilters) {
       List<String> actionList = intentFilterData.getActions();
       List<String> categoryList = intentFilterData.getCategories();
       IntentFilter intentFilter = new IntentFilter();
@@ -928,10 +964,10 @@
           intent.getData());
       if (matchActionResult && (matchCategoriesResult == null) &&
           (matchResult != IntentFilter.NO_MATCH_DATA && matchResult != IntentFilter.NO_MATCH_TYPE)){
-        return true;
+        return intentFilter;
       }
     }
-    return false;
+    return null;
   }
 
   @Override
diff --git a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
index 8819ae7..ddc3e47 100644
--- a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
+++ b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java
@@ -92,10 +92,13 @@
 
     assertThat(config.getServices().get(0).getClassName()).isEqualTo("com.foo.Service");
     assertThat(config.getServices().get(0).getActions()).contains("org.robolectric.ACTION_DIFFERENT_PACKAGE");
+    assertThat(config.getServices().get(0).getIntentFilters()).isNotEmpty();
+    assertThat(config.getServices().get(0).getIntentFilters().get(0).getMimeTypes()).containsExactly("image/jpeg");
 
     assertThat(config.getServices().get(1).getClassName()).isEqualTo("com.bar.ServiceWithoutIntentFilter");
     assertThat(config.getServices().get(1).getActions()).isEmpty();
-    
+    assertThat(config.getServices().get(1).getIntentFilters()).isEmpty();
+
     assertThat(config.getServiceData("com.foo.Service").getClassName()).isEqualTo("com.foo.Service");
     assertThat(config.getServiceData("com.bar.ServiceWithoutIntentFilter").getClassName()).isEqualTo("com.bar.ServiceWithoutIntentFilter");
     assertEquals(config.getServiceData("com.foo.Service").getPermission(), "com.foo.Permission");
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java
index c6f4ea8..dd0d7fc 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java
@@ -422,9 +422,19 @@
 
     shadowPackageManager.addResolveInfoForIntent(i, info);
 
-    List<ResolveInfo> activities = shadowPackageManager.queryIntentServices(i, 0);
-    assertThat(activities).hasSize(1);
-    assertThat(activities.get(0).nonLocalizedLabel.toString()).isEqualTo(TEST_PACKAGE_LABEL);
+    List<ResolveInfo> services = shadowPackageManager.queryIntentServices(i, 0);
+    assertThat(services).hasSize(1);
+    assertThat(services.get(0).nonLocalizedLabel.toString()).isEqualTo(TEST_PACKAGE_LABEL);
+  }
+
+  @Test
+  @Config(manifest = "TestAndroidManifestWithServices.xml")
+  public void queryIntentServices_fromManifest() {
+    Intent i = new Intent("org.robolectric.ACTION_DIFFERENT_PACKAGE");
+    i.addCategory(Intent.CATEGORY_LAUNCHER);
+    i.setType("image/jpeg");
+    List<ResolveInfo> services = shadowPackageManager.queryIntentServices(i, 0);
+    assertThat(services).isNotEmpty();
   }
 
   @Test
diff --git a/robolectric/src/test/resources/TestAndroidManifestForActivitiesWithIntentFilter.xml b/robolectric/src/test/resources/TestAndroidManifestForActivitiesWithIntentFilter.xml
index 2fec297..a44e70a 100644
--- a/robolectric/src/test/resources/TestAndroidManifestForActivitiesWithIntentFilter.xml
+++ b/robolectric/src/test/resources/TestAndroidManifestForActivitiesWithIntentFilter.xml
@@ -10,5 +10,11 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <service android:name="org.robolectric.shadows.TestService">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </service>
     </application>
 </manifest>
diff --git a/robolectric/src/test/resources/TestAndroidManifestWithServices.xml b/robolectric/src/test/resources/TestAndroidManifestWithServices.xml
index 7b50afc..bd1c131 100644
--- a/robolectric/src/test/resources/TestAndroidManifestWithServices.xml
+++ b/robolectric/src/test/resources/TestAndroidManifestWithServices.xml
@@ -5,6 +5,8 @@
     <service android:name="com.foo.Service" android:permission="com.foo.Permission">
       <intent-filter>
         <action android:name="org.robolectric.ACTION_DIFFERENT_PACKAGE"/>
+        <data android:mimeType="image/jpeg"/>
+        <category android:name="android.intent.category.LAUNCHER"/>
       </intent-filter>
     </service>