Fixing apicheck to cope with interfaces inherited from other interfaces.

For example, in Java 5, FutureTask was declared like this:
    public class FutureTask<V> implements Runnable, Future<V> {}

In Java 6, it's declared like this:
    public class FutureTask<V> implements RunnableFuture<V> {}
    public interface RunnableFuture extends Runnable, Future<V> {}

Change-Id: I0cd66a655fbe7fd5c7c48099d656b7a39368dac4
diff --git a/tools/apicheck/src/com/android/apicheck/ApiCheck.java b/tools/apicheck/src/com/android/apicheck/ApiCheck.java
index c8272dd..b2f2265 100644
--- a/tools/apicheck/src/com/android/apicheck/ApiCheck.java
+++ b/tools/apicheck/src/com/android/apicheck/ApiCheck.java
@@ -107,6 +107,7 @@
             xmlreader.parse(new InputSource(fileReader));
             ApiInfo apiInfo = handler.getApi();
             apiInfo.resolveSuperclasses();
+            apiInfo.resolveInterfaces();
             return apiInfo;
         } catch (SAXParseException e) {
             Errors.error(Errors.PARSE_ERROR,
diff --git a/tools/apicheck/src/com/android/apicheck/ApiInfo.java b/tools/apicheck/src/com/android/apicheck/ApiInfo.java
index c237814..47b9a15 100644
--- a/tools/apicheck/src/com/android/apicheck/ApiInfo.java
+++ b/tools/apicheck/src/com/android/apicheck/ApiInfo.java
@@ -31,14 +31,13 @@
         return mAllClasses.get(name);
     }
 
-    private void resolveInterfaces() {
+    public void resolveInterfaces() {
         for (ClassInfo c : mAllClasses.values()) {
             c.resolveInterfaces(this);
         }
     }
     
     public boolean isConsistent(ApiInfo otherApi) {
-        resolveInterfaces();
         boolean consistent = true;
         for (PackageInfo pInfo : mPackages.values()) {
             if (otherApi.getPackages().containsKey(pInfo.name())) {
diff --git a/tools/apicheck/src/com/android/apicheck/ClassInfo.java b/tools/apicheck/src/com/android/apicheck/ClassInfo.java
index e62a3d0..2555ea4 100644
--- a/tools/apicheck/src/com/android/apicheck/ClassInfo.java
+++ b/tools/apicheck/src/com/android/apicheck/ClassInfo.java
@@ -135,11 +135,7 @@
             consistent = false;
         }
         for (String iface : mInterfaceNames) {
-            boolean found = false;
-            for (ClassInfo c = cl; c != null && !found; c = c.mSuperClass) {
-                found = c.mInterfaceNames.contains(iface);
-            }
-            if (!found) {
+            if (!implementsInterface(cl, iface)) {
                 Errors.error(Errors.REMOVED_INTERFACE, cl.position(),
                         "Class " + qualifiedName() + " no longer implements " + iface);
             }
@@ -274,6 +270,26 @@
         return consistent;
     }
 
+    /**
+     * Returns true if {@code cl} implements the interface {@code iface} either
+     * by either being that interface, implementing that interface or extending
+     * a type that implements the interface.
+     */
+    private boolean implementsInterface(ClassInfo cl, String iface) {
+        if (cl.qualifiedName().equals(iface)) {
+            return true;
+        }
+        for (ClassInfo clImplements : cl.mInterfaces) {
+            if (implementsInterface(clImplements, iface)) {
+                return true;
+            }
+        }
+        if (cl.mSuperClass != null && implementsInterface(cl.mSuperClass, iface)) {
+            return true;
+        }
+        return false;
+    }
+
     public void resolveInterfaces(ApiInfo apiInfo) {
         for (String interfaceName : mInterfaceNames) {
             mInterfaces.add(apiInfo.findClass(interfaceName));