am d866ed04: Merge "Remove optional video encoder: MPEG-4 SP" into jb-dev

* commit 'd866ed04ecb7b051b89abe7b479ab73a5c15f094':
  Remove optional video encoder: MPEG-4 SP
diff --git a/CtsCoverage.mk b/CtsCoverage.mk
index 8e00913..61ad9c9 100644
--- a/CtsCoverage.mk
+++ b/CtsCoverage.mk
@@ -33,6 +33,7 @@
 
 cts-test-coverage-report := $(coverage_out)/test-coverage.html
 cts-verifier-coverage-report := $(coverage_out)/verifier-coverage.html
+cts-combined-coverage-report := $(coverage_out)/combined-coverage.html
 
 cts_api_coverage_dependencies := $(cts_api_coverage_exe) $(dexdeps_exe) $(api_xml_description) $(ACP)
 
@@ -44,16 +45,24 @@
 	$(call generate-coverage-report,"CTS Verifier API Coverage Report",\
 			CtsVerifier,cts-verifier-apks,html,verifier-coverage.html)
 
+$(cts-combined-coverage-report) : CtsVerifier $(cts_api_coverage_dependencies) $(CTS_COVERAGE_TEST_CASE_LIST) $(cts_api_coverage_dependencies)
+	$(call generate-coverage-report,"CTS Combined API Coverage Report",\
+			$(CTS_COVERAGE_TEST_CASE_LIST) CtsVerifier,cts-combined-apks,html,combined-coverage.html)
+
 .PHONY: cts-test-coverage
 cts-test-coverage : $(cts-test-coverage-report)
 
 .PHONY: cts-verifier-coverage
 cts-verifier-coverage : $(cts-verifier-coverage-report)
 
+.PHONY: cts-combined-coverage
+cts-combined-coverage : $(cts-combined-coverage-report)
+
 # Put the test coverage report in the dist dir if "cts" is among the build goals.
 ifneq ($(filter cts, $(MAKECMDGOALS)),)
   $(call dist-for-goals, cts, $(cts-test-coverage-report):cts-test-coverage-report.html)
   $(call dist-for-goals, cts, $(cts-verifier-coverage-report):cts-verifier-coverage-report.html)
+  $(call dist-for-goals, cts, $(cts-combined-coverage-report):cts-combined-coverage-report.html)
 endif
 
 # Arguments;
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 6373173..0898369 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
       android:versionCode="1"
-      android:versionName="4.1_r1">
+      android:versionName="4.1_r2">
 
     <!-- Using 10 for more complete NFC support... -->
     <uses-sdk android:minSdkVersion="10"></uses-sdk>
@@ -183,7 +183,6 @@
                 android:configChanges="keyboardHidden|orientation">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
@@ -194,7 +193,6 @@
                 android:configChanges="keyboardHidden|orientation">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
@@ -308,7 +306,6 @@
                  android:screenOrientation="landscape">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_camera" />
 
diff --git a/suite/audio_quality/Android.mk b/suite/audio_quality/Android.mk
index c12e390..2078606 100644
--- a/suite/audio_quality/Android.mk
+++ b/suite/audio_quality/Android.mk
@@ -19,16 +19,26 @@
 
 CTS_AUDIO_TOP:= $(call my-dir)
 
-CTS_AUDIO_INSTALL_DIR := $(HOST_OUT)/cts_audio_quality
+CTS_AUDIO_INSTALL_DIR := $(HOST_OUT)/cts-audio-quality/android-cts-audio-quality
+CTS_AUDIO_QUALITY_ZIP := $(HOST_OUT)/cts-audio-quality/android-cts-audio-quality.zip
 
-cts_audio: cts_audio_quality_test cts_audio_quality CtsAudioClient $(CTS_AUDIO_TOP)/test_description
+$(CTS_AUDIO_QUALITY_ZIP): cts_audio_quality_test cts_audio_quality \
+  CtsAudioClient $(CTS_AUDIO_TOP)/test_description
 	$(hide) mkdir -p $(CTS_AUDIO_INSTALL_DIR)
 	$(hide) mkdir -p $(CTS_AUDIO_INSTALL_DIR)/client
-	$(hide) $(ACP) -fp $(ANDROID_PRODUCT_OUT)/data/app/CtsAudioClient.apk \
+	$(hide) $(ACP) -fp $(PRODUCT_OUT)/data/app/CtsAudioClient.apk \
         $(CTS_AUDIO_INSTALL_DIR)/client
 	$(hide) $(ACP) -fp $(HOST_OUT)/bin/cts_audio_quality_test $(CTS_AUDIO_INSTALL_DIR)
 	$(hide) $(ACP) -fp $(HOST_OUT)/bin/cts_audio_quality $(CTS_AUDIO_INSTALL_DIR)
 	$(hide) $(ACP) -fr $(CTS_AUDIO_TOP)/test_description $(CTS_AUDIO_INSTALL_DIR)
+	$(hide) echo "Package cts_audio: $@"
+	$(hide) cd $(HOST_OUT)/cts-audio-quality && \
+        zip -rq android-cts-audio-quality.zip android-cts-audio-quality -x android-cts-audio-quality/reports/\*
+
+cts: $(CTS_AUDIO_QUALITY_ZIP)
+ifneq ($(filter cts, $(MAKECMDGOALS)),)
+$(call dist-for-goals, cts, $(CTS_AUDIO_QUALITY_ZIP))
+endif # cts
 
 include $(call all-subdir-makefiles)
 
diff --git a/suite/audio_quality/executable/src/main.cpp b/suite/audio_quality/executable/src/main.cpp
index 98dfabe..cf33a0f 100644
--- a/suite/audio_quality/executable/src/main.cpp
+++ b/suite/audio_quality/executable/src/main.cpp
@@ -61,7 +61,7 @@
         fprintf(stderr, "%s [-l log_level][-s serial] test_xml\n", argv[0]);
         return 1;
     }
-    int logLevel = 3;
+    int logLevel = Log::ELogE;
     char* serial = NULL;
     int opt;
     while ((opt = getopt(argc, argv, "l:s:")) != -1) {
diff --git a/suite/audio_quality/test_description/dut_speaker_calibration.xml b/suite/audio_quality/test_description/dut_speaker_calibration.xml
index f0ddf17..e0a613d 100644
--- a/suite/audio_quality/test_description/dut_speaker_calibration.xml
+++ b/suite/audio_quality/test_description/dut_speaker_calibration.xml
@@ -31,7 +31,7 @@
 			<sequential repeat="8" index="j">
 				<input device="host" id="host_in" gain="100" time="500" sync="complete" />
 				<!-- ------------moving average RMS        min for pass, max for pass                result calculated -->
-				<process method="builtin:rms_mva" input="id:host_in,consti:3000,consti:8000" output="val:rms_$i_$j" />
+				<process method="builtin:rms_mva" input="id:host_in,consti:1000,consti:8000" output="val:rms_$i_$j" />
 				<!-- <message input="val:passfail" output_low="Volume Low" output_ok="Volume OK" output_high="Volume High" /> -->
 			</sequential>
 		</sequential>
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
index f1a7114..a5d92ee 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityActivityTestCase.java
@@ -53,12 +53,27 @@
         public boolean accept(AccessibilityEvent event);
     }
 
+    private static final boolean DEBUG = false;
+
+    private static final String LOG_TAG = AccessibilityActivityTestCase.class.getSimpleName();
+
     /**
      * Timeout required for pending Binder calls or event processing to
      * complete.
      */
     public static final long TIMEOUT_ASYNC_PROCESSING = 5000;
 
+    /**
+     * The timeout after the last accessibility event to consider the device idle.
+     */
+    public static final long TIMEOUT_ACCESSIBILITY_STATE_IDLE = 100;
+
+    /**
+     * Instance for detecting the next accessibility event.
+     */
+    private static final NextAccessibilityEventWatcher sNextEventWatcher =
+            new NextAccessibilityEventWatcher();
+
     private static AccessibilityInteractionBridge sInteractionBridge;
 
     /**
@@ -71,6 +86,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        waitForAccessibilityStateIdle();
         startActivityAndWaitForFirstEvent();
     }
 
@@ -124,6 +140,39 @@
     }
 
     /**
+     * Waits for idle accessibility state.
+     */
+    private void waitForAccessibilityStateIdle() throws Exception {
+        AccessibilityEvent awaitedEvent = null;
+        try {
+            do {
+                awaitedEvent = getInteractionBridge().executeCommandAndWaitForAccessibilityEvent(
+                        sNextEventWatcher, sNextEventWatcher, TIMEOUT_ACCESSIBILITY_STATE_IDLE);
+            } while (awaitedEvent != null);
+        } catch (TimeoutException te) {
+            /* success - no event within the timeout - do nothing */
+        }
+    }
+
+    /**
+     * Dummy implementation that matches every event and does nothing.
+     */
+    private static class NextAccessibilityEventWatcher implements Runnable,
+            AccessibilityEventFilter {
+        @Override
+        public boolean accept(AccessibilityEvent event) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Watcher event: " + event);
+            }
+            return true;
+        }
+        @Override
+        public void run() {
+            /* do nothing */
+        }
+    }
+
+    /**
      * This class serves as a bridge for querying the screen content.
      * The bride is connected of a delegating accessibility service.
      */
@@ -180,7 +229,6 @@
 
         public void onAccessibilityEvent(AccessibilityEvent event) {
             synchronized (mLock) {
-                Log.e("OPALA", "Event: " + event);
                 mLock.notifyAll();
                 if (mWaitingForEventDelivery) {
                     mEventQueue.add(AccessibilityEvent.obtain(event));
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 04d5ca9..8b33359 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -29,7 +29,7 @@
 
     private static final String LOG_TAG = "BuildVersionTest";
     private static final Set<String> EXPECTED_RELEASES =
-            new HashSet<String>(Arrays.asList("4.1.1"));
+	    new HashSet<String>(Arrays.asList("4.1.1", "4.1.2"));
     private static final int EXPECTED_SDK = 16;
 
     @SuppressWarnings("deprecation")
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index f5ae100..4712257 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -165,6 +165,71 @@
         assertFalse(f.canRead());
         assertFalse(f.canWrite());
         assertFalse(f.canExecute());
+
+        assertFileOwnedBy(f, "nfc");
+        assertFileOwnedByGroup(f, "nfc");
+    }
+
+    @MediumTest
+    public void testBcm2079xSane() throws Exception {
+        File f = new File("/dev/bcm2079x");
+        assertFalse(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+
+        assertFileOwnedBy(f, "nfc");
+        assertFileOwnedByGroup(f, "nfc");
+    }
+
+    @MediumTest
+    public void testBcm2079xi2cSane() throws Exception {
+        File f = new File("/dev/bcm2079x-i2c");
+        assertFalse(f.canRead());
+        assertFalse(f.canWrite());
+        assertFalse(f.canExecute());
+
+        assertFileOwnedBy(f, "nfc");
+        assertFileOwnedByGroup(f, "nfc");
+    }
+
+    /**
+     * Assert that a file is owned by a specific owner. This is a noop if the
+     * file does not exist.
+     *
+     * @param file The file to check.
+     * @param expectedOwner The owner of the file.
+     */
+    private static void assertFileOwnedBy(File file, String expectedOwner) {
+        FileUtils.FileStatus status = new FileUtils.FileStatus();
+        String path = file.getAbsolutePath();
+        if (file.exists() && FileUtils.getFileStatus(path, status, true)) {
+            String actualOwner = FileUtils.getUserName(status.uid);
+            if (!expectedOwner.equals(actualOwner)) {
+                String msg = String.format("Wrong owner. Expected '%s', but found '%s' for %s.",
+                        expectedOwner, actualOwner, path);
+                fail(msg);
+            }
+        }
+    }
+
+    /**
+     * Assert that a file is owned by a specific group. This is a noop if the
+     * file does not exist.
+     *
+     * @param file The file to check.
+     * @param expectedGroup The owner group of the file.
+     */
+    private static void assertFileOwnedByGroup(File file, String expectedGroup) {
+        FileUtils.FileStatus status = new FileUtils.FileStatus();
+        String path = file.getAbsolutePath();
+        if (file.exists() && FileUtils.getFileStatus(path, status, true)) {
+            String actualGroup = FileUtils.getGroupName(status.gid);
+            if (!expectedGroup.equals(actualGroup)) {
+                String msg = String.format("Wrong group. Expected '%s', but found '%s' for %s.",
+                        expectedGroup, actualGroup, path);
+                fail(msg);
+            }
+        }
     }
 
     @MediumTest
@@ -218,6 +283,8 @@
                     "/app-cache/ciq/socket",
                     "/cache/fotapkg",
                     "/cache/fotapkg/tmp",
+                    "/data/_SamsungBnR_",
+                    "/data/_SamsungBnR_/BR",
                     "/data/2nd-init",
                     "/data/amit",
                     "/data/anr",
@@ -230,6 +297,7 @@
                     "/data/btips/TI",
                     "/data/btips/TI/opp",
                     "/data/calibration",
+                    "/data/clipboard",
                     "/data/clp",
                     "/data/dalvik-cache",
                     "/data/data",
@@ -267,6 +335,7 @@
                     "/data/drm/rights",
                     "/data/dump",
                     "/data/emt",
+                    "/data/factory",
                     "/data/fota",
                     "/data/gpscfg",
                     "/data/hwvefs",
@@ -298,6 +367,9 @@
                     "/data/misc/bluetooth",
                     "/data/misc/dhcp",
                     "/data/misc/lockscreen",
+                    "/data/misc/webwidgets",
+                    "/data/misc/webwidgets/chess",
+                    "/data/misc/widgets",
                     "/data/misc/wifi",
                     "/data/misc/wifi/sockets",
                     "/data/misc/wimax",
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 277f104..e02998e 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -164,6 +164,7 @@
     }
 
     public void testOnUnhandledKeyEvent() throws Throwable {
+        requireLoadedPage();
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
 
@@ -191,6 +192,10 @@
         assertTrue(webViewClient.hasOnScaleChangedCalled());
     }
 
+    private void requireLoadedPage() throws Throwable {
+        mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+    }
+
     private class MockWebViewClient extends WaitForLoadedClient {
         private boolean mOnPageStartedCalled;
         private boolean mOnPageFinishedCalled;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 0a8cc30..3f7ea78 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1167,6 +1167,20 @@
     }
 
     public void testRequestImageRef() throws Exception, Throwable {
+        final class ImageLoaded {
+            public boolean mImageLoaded;
+
+            public void loaded() {
+                mImageLoaded = true;
+            }
+        }
+        final ImageLoaded imageLoaded = new ImageLoaded();
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mOnUiThread.getSettings().setJavaScriptEnabled(true);
+            }
+        });
+        mOnUiThread.addJavascriptInterface(imageLoaded, "imageLoaded");
         AssetManager assets = getActivity().getAssets();
         Bitmap bitmap = BitmapFactory.decodeStream(assets.open(TestHtmlConstants.LARGE_IMG_URL));
         int imgWidth = bitmap.getWidth();
@@ -1175,9 +1189,24 @@
         startWebServer(false);
         final String imgUrl = mWebServer.getAssetUrl(TestHtmlConstants.LARGE_IMG_URL);
         mOnUiThread.loadDataAndWaitForCompletion(
-                "<html><title>Title</title><body><img src=\"" + imgUrl
+                "<html><head><title>Title</title><style type=\"text/css\">"
+                + "#imgElement { -webkit-transform: translate3d(0,0,1); }"
+                + "#imgElement.finish { -webkit-transform: translate3d(0,0,0);"
+                + " -webkit-transition-duration: 1ms; }</style>"
+                + "<script type=\"text/javascript\">function imgLoad() {"
+                + "imgElement = document.getElementById('imgElement');"
+                + "imgElement.addEventListener('webkitTransitionEnd',"
+                + "function(e) { imageLoaded.loaded(); });"
+                + "imgElement.className = 'finish';}</script>"
+                + "</head><body><img id=\"imgElement\" src=\"" + imgUrl
                 + "\" width=\"" + imgWidth + "\" height=\"" + imgHeight
-                + "\"/></body></html>", "text/html", null);
+                + "\" onLoad=\"imgLoad()\"/></body></html>", "text/html", null);
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return imageLoaded.mImageLoaded;
+            }
+        }.run();
         getInstrumentation().waitForIdleSync();
 
         final HrefCheckHandler handler = new HrefCheckHandler(mWebView.getHandler().getLooper());
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
index 101be7f..2a62aa0 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
@@ -28,13 +28,16 @@
 
     private final boolean mDeprecated;
 
+    private final boolean mAbstract;
+
     private final List<ApiConstructor> mApiConstructors = new ArrayList<ApiConstructor>();
 
     private final List<ApiMethod> mApiMethods = new ArrayList<ApiMethod>();
 
-    ApiClass(String name, boolean deprecated) {
+    ApiClass(String name, boolean deprecated, boolean classAbstract) {
         mName = name;
         mDeprecated = deprecated;
+        mAbstract = classAbstract;
     }
 
     @Override
@@ -51,6 +54,10 @@
         return mDeprecated;
     }
 
+    public boolean isAbstract() {
+        return mAbstract;
+    }
+
     public void addConstructor(ApiConstructor constructor) {
         mApiConstructors.add(constructor);
     }
@@ -108,6 +115,10 @@
 
     @Override
     public float getCoveragePercentage() {
-        return (float) getNumCoveredMethods() / getTotalMethods() * 100;
+        if (getTotalMethods() == 0) {
+            return 100;
+        } else {
+            return (float) getNumCoveredMethods() / getTotalMethods() * 100;
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
index dc40062..adf2ea9 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.apicoverage;
 
+import java.lang.String;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -37,4 +38,11 @@
     public Collection<ApiPackage> getPackages() {
         return Collections.unmodifiableCollection(mPackages.values());
     }
+
+    public void removeEmptyAbstractClasses() {
+        for (Map.Entry<String, ApiPackage> entry : mPackages.entrySet()) {
+            ApiPackage pkg = entry.getValue();
+            pkg.removeEmptyAbstractClasses();
+        }
+    }
 }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
index ddc6fb4..c83256c 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
@@ -19,7 +19,9 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 /** Representation of a package in the API containing classes. */
 class ApiPackage implements HasCoverage {
@@ -69,4 +71,16 @@
     public float getCoveragePercentage() {
         return (float) getNumCoveredMethods() / getTotalMethods() * 100;
     }
-}
\ No newline at end of file
+
+    public void removeEmptyAbstractClasses() {
+        Iterator<Entry<String, ApiClass>> it = mApiClassMap.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, ApiClass> entry = it.next();
+            ApiClass cls = entry.getValue();
+            if (cls.isAbstract() && (cls.getTotalMethods() == 0)) {
+                // this is essentially interface
+                it.remove();
+            }
+        }
+    }
+}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
index 2923ba2..d6abf9a 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
@@ -109,6 +109,7 @@
          */
 
         ApiCoverage apiCoverage = getEmptyApiCoverage(apiXmlPath);
+        apiCoverage.removeEmptyAbstractClasses();
         for (File testApk : testApks) {
             addApiCoverage(apiCoverage, testApk, dexDeps);
         }
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
index f3abd86..b9f9e9c 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
@@ -32,12 +32,17 @@
 
     private String mCurrentClassName;
 
+    private boolean mIgnoreCurrentClass;
+
     private String mCurrentMethodName;
 
     private String mCurrentMethodReturnType;
 
+    private boolean mCurrentMethodIsAbstract;
+
     private boolean mDeprecated;
 
+
     private List<String> mCurrentParameterTypes = new ArrayList<String>();
 
     private ApiCoverage mApiCoverage = new ApiCoverage();
@@ -56,15 +61,20 @@
             ApiPackage apiPackage = new ApiPackage(mCurrentPackageName);
             mApiCoverage.addPackage(apiPackage);
 
-        } else if ("class".equalsIgnoreCase(localName)
-                || "interface".equalsIgnoreCase(localName)) {
+        } else if ("class".equalsIgnoreCase(localName)) {
+            if (isEnum(attributes)) {
+                mIgnoreCurrentClass = true;
+                return;
+            }
+            mIgnoreCurrentClass = false;
             mCurrentClassName = getValue(attributes, "name");
             mDeprecated = isDeprecated(attributes);
-
-            ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated);
+            ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated, isAbstract(attributes));
             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
             apiPackage.addClass(apiClass);
-
+        } else if ("interface".equalsIgnoreCase(localName)) {
+            // don't add interface
+            mIgnoreCurrentClass = true;
         } else if ("constructor".equalsIgnoreCase(localName)) {
             mDeprecated = isDeprecated(attributes);
             mCurrentParameterTypes.clear();
@@ -72,6 +82,7 @@
             mDeprecated = isDeprecated(attributes);
             mCurrentMethodName = getValue(attributes, "name");
             mCurrentMethodReturnType = getValue(attributes, "return");
+            mCurrentMethodIsAbstract = isAbstract(attributes);
             mCurrentParameterTypes.clear();
         } else if ("parameter".equalsIgnoreCase(localName)) {
             mCurrentParameterTypes.add(getValue(attributes, "type"));
@@ -81,6 +92,10 @@
     @Override
     public void endElement(String uri, String localName, String name) throws SAXException {
         super.endElement(uri, localName, name);
+        if (mIgnoreCurrentClass) {
+            // do not add anything for interface
+            return;
+        }
         if ("constructor".equalsIgnoreCase(localName)) {
             if (mCurrentParameterTypes.isEmpty()) {
                 // Don't add empty default constructors...
@@ -92,6 +107,9 @@
             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
             apiClass.addConstructor(apiConstructor);
         }  else if ("method".equalsIgnoreCase(localName)) {
+            if (mCurrentMethodIsAbstract) { // do not add abstract method
+                return;
+            }
             ApiMethod apiMethod = new ApiMethod(mCurrentMethodName, mCurrentParameterTypes,
                     mCurrentMethodReturnType, mDeprecated);
             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
@@ -110,4 +128,12 @@
     private boolean isDeprecated(Attributes attributes) {
         return "deprecated".equals(attributes.getValue("deprecated"));
     }
+
+    private boolean isAbstract(Attributes attributes) {
+        return "true".equals(attributes.getValue("abstract"));
+    }
+
+    private boolean isEnum(Attributes attributes) {
+        return "java.lang.Enum".equals(attributes.getValue("extends"));
+    }
 }
\ No newline at end of file
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
index 94ccbb4..e76343e 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
@@ -54,12 +54,18 @@
         CoverageComparator comparator = new CoverageComparator();
         List<ApiPackage> packages = new ArrayList<ApiPackage>(apiCoverage.getPackages());
         Collections.sort(packages, comparator);
+        int totalMethods = 0;
+        int totalCoveredMethods = 0;
         for (ApiPackage pkg : packages) {
             if (pkg.getName().startsWith("android")
                     && pkg.getTotalMethods() > 0) {
+                int pkgTotal = pkg.getTotalMethods();
+                totalMethods += pkgTotal;
+                int pkgTotalCovered = pkg.getNumCoveredMethods();
+                totalCoveredMethods += pkgTotalCovered;
                 out.println("<package name=\"" + pkg.getName()
-                        + "\" numCovered=\"" + pkg.getNumCoveredMethods()
-                        + "\" numTotal=\"" + pkg.getTotalMethods()
+                        + "\" numCovered=\"" + pkgTotalCovered
+                        + "\" numTotal=\"" + pkgTotal
                         + "\" coveragePercentage=\""
                             + Math.round(pkg.getCoveragePercentage())
                         + "\">");
@@ -81,7 +87,12 @@
                             out.println("<constructor name=\"" + constructor.getName()
                                     + "\" deprecated=\"" + constructor.isDeprecated()
                                     + "\" covered=\"" + constructor.isCovered() + "\">");
-
+                            if (constructor.isDeprecated()) {
+                                if (constructor.isCovered()) {
+                                    totalCoveredMethods -= 1;
+                                }
+                                totalMethods -= 1;
+                            }
                             for (String parameterType : constructor.getParameterTypes()) {
                                 out.println("<parameter type=\"" + parameterType + "\" />");
                             }
@@ -94,7 +105,12 @@
                                     + "\" returnType=\"" + method.getReturnType()
                                     + "\" deprecated=\"" + method.isDeprecated()
                                     + "\" covered=\"" + method.isCovered() + "\">");
-
+                            if (method.isDeprecated()) {
+                                if (method.isCovered()) {
+                                    totalCoveredMethods -= 1;
+                                }
+                                totalMethods -= 1;
+                            }
                             for (String parameterType : method.getParameterTypes()) {
                                 out.println("<parameter type=\"" + parameterType + "\" />");
                             }
@@ -109,6 +125,10 @@
         }
 
         out.println("</api>");
+        out.println("<total numCovered=\"" + totalCoveredMethods + "\" "
+                + "numTotal=\"" + totalMethods + "\" "
+                + "coveragePercentage=\""
+                + Math.round((float)totalCoveredMethods / totalMethods * 100.0f) + "\" />");
         out.println("</api-coverage>");
     }
 }
diff --git a/tools/cts-api-coverage/src/res/api-coverage.xsl b/tools/cts-api-coverage/src/res/api-coverage.xsl
index 95994e2..9cd4aeb 100644
--- a/tools/cts-api-coverage/src/res/api-coverage.xsl
+++ b/tools/cts-api-coverage/src/res/api-coverage.xsl
@@ -82,6 +82,10 @@
                 <div class="info">
                     Generated: <xsl:value-of select="api-coverage/@generatedTime" />
                 </div>
+                <div class="total">
+                    Total:&nbsp;<xsl:value-of select="api-coverage/total/@coveragePercentage" />%
+                &nbsp;(<xsl:value-of select="api-coverage/total/@numCovered" />/<xsl:value-of select="api-coverage/total/@numTotal" />)
+                </div>
                 <div class="apks" onclick="toggleVisibility('sourceApks')">
                     Source APKs (<xsl:value-of select="count(api-coverage/debug/sources/apk)" />)
                 </div>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 78f7412..a79b84e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -51,6 +51,7 @@
 import java.lang.System;
 import java.lang.Thread;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -148,6 +149,9 @@
             "Interval between each reboot in min. Meaningful only with reboot-per-package option")
     private int mRebootIntervalMin = 30;
 
+
+    private long mPrevRebootTime; // last reboot time
+
     /** data structure for a {@link IRemoteTest} and its known tests */
     class TestPackage {
         private final IRemoteTest mTestForPackage;
@@ -350,8 +354,8 @@
                 Log.i(LOG_TAG, "Initial reboot for multiple packages");
                 rebootDevice();
             }
-            long prevTime = System.currentTimeMillis();
-            long intervalInMSec = mRebootIntervalMin * 60 * 1000;
+            mPrevRebootTime = System.currentTimeMillis();
+
             while (!mRemainingTestPkgs.isEmpty()) {
                 TestPackage knownTests = mRemainingTestPkgs.get(0);
 
@@ -367,15 +371,7 @@
                 test.run(filter);
                 mRemainingTestPkgs.remove(0);
                 if (mRemainingTestPkgs.size() > 0) {
-                    if (mRebootPerPackage) {
-                        long currentTime = System.currentTimeMillis();
-                        if ((currentTime - prevTime) > intervalInMSec) {
-                            Log.i(LOG_TAG, String.format("Rebooting after running package %s",
-                                    knownTests.getPackageDef().getName()));
-                            rebootDevice();
-                            prevTime = System.currentTimeMillis();
-                        }
-                    }
+                    rebootIfNecessary(knownTests, mRemainingTestPkgs.get(0));
                     // remove artifacts like status bar from the previous test.
                     // But this cannot dismiss dialog popped-up.
                     changeToHomeScreen();
@@ -398,6 +394,33 @@
         }
     }
 
+    private void rebootIfNecessary(TestPackage testFinished, TestPackage testToRun)
+            throws DeviceNotAvailableException {
+        // If there comes spurious failure like INJECT_EVENTS for a package,
+        // reboot it before running it.
+        // Also reboot after package which is know to leave pop-up behind
+        final List<String> rebootAfterList = Arrays.asList("CtsWebkitSecurityTestCases");
+        final List<String> rebootBeforeList = Arrays.asList("CtsAnimationTestCases",
+                "CtsGraphicsTestCases",
+                "CtsViewTestCases",
+                "CtsWebkitSecurityTestCases",
+                "CtsWidgetTestCases" );
+        long intervalInMSec = mRebootIntervalMin * 60 * 1000;
+        if (mRebootPerPackage) {
+            long currentTime = System.currentTimeMillis();
+            if (((currentTime - mPrevRebootTime) > intervalInMSec) ||
+                    rebootAfterList.contains(testFinished.getPackageDef().getName()) ||
+                    rebootBeforeList.contains(testToRun.getPackageDef().getName()) ) {
+                Log.i(LOG_TAG,
+                        String.format("Rebooting after running package %s, before package %s",
+                                testFinished.getPackageDef().getName(),
+                                testToRun.getPackageDef().getName()));
+                rebootDevice();
+                mPrevRebootTime = System.currentTimeMillis();
+            }
+        }
+    }
+
     private void rebootDevice() throws DeviceNotAvailableException {
         final int TIMEOUT_MS = 4 * 60 * 1000;
         TestDeviceOptions options = mDevice.getOptions();