Merge remote branch 'goog/honeycomb' into honeycomb-mr1
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d91f312..d8dda46 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -60,6 +60,10 @@
                     android:resource="@xml/accessory_filter" />
         </activity>
 
+        <activity android:name=".ReportViewerActivity"
+                android:configChanges="keyboardHidden|orientation"
+                android:label="@string/report_viewer" />
+
         <provider android:name=".TestResultsProvider" 
                 android:authorities="com.android.cts.verifier.testresultsprovider" />
                 
@@ -165,28 +169,6 @@
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
         </activity>
 
-        <activity android:name=".bluetooth.ConnectionAccessServerActivity"
-                android:label="@string/bt_connection_access_server"
-                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" />
-        </activity>
-        
-        <activity android:name=".bluetooth.ConnectionAccessClientActivity"
-                android:label="@string/bt_connection_access_client"
-                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" />
-        </activity>
-
         <activity android:name=".bluetooth.DevicePickerActivity"
                 android:label="@string/bt_device_picker"
                 android:configChanges="keyboardHidden|orientation" />
diff --git a/apps/CtsVerifier/res/layout/report_viewer.xml b/apps/CtsVerifier/res/layout/report_viewer.xml
new file mode 100644
index 0000000..c397582
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/report_viewer.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/report_text"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
diff --git a/apps/CtsVerifier/res/menu/test_list_menu.xml b/apps/CtsVerifier/res/menu/test_list_menu.xml
index 16323e9..e777791 100644
--- a/apps/CtsVerifier/res/menu/test_list_menu.xml
+++ b/apps/CtsVerifier/res/menu/test_list_menu.xml
@@ -3,9 +3,9 @@
     <item android:id="@+id/clear"
           android:icon="@android:drawable/ic_menu_delete" 
           android:title="@string/clear" />
-    <item android:id="@+id/copy"
-          android:icon="@android:drawable/ic_menu_upload"
-          android:title="@string/copy" />
+    <item android:id="@+id/view"
+          android:icon="@android:drawable/ic_menu_view"
+          android:title="@string/view" />
     <item android:id="@+id/export"
           android:icon="@android:drawable/ic_menu_save"
           android:title="@string/export" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 3af663d..63f9236 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -23,9 +23,6 @@
     <string name="info_button_text">Info</string>
     <string name="fail_button_text">Fail</string>
 
-    <!-- Strings for TestResultsReport -->
-    <string name="subject_header">CTS Verifier %1$s - %2$s</string>
-
     <!-- Strings for TestListActivity -->
     <string name="test_list_title">Manual Test List</string>
     <string name="test_category_audio">Audio</string>
@@ -39,13 +36,15 @@
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
     <string name="test_results_cleared">Test results cleared.</string>
-    <string name="copy">Copy</string>
-    <string name="test_results_copied">Test results copied to clipboard.</string>
+    <string name="view">View</string>
     <string name="test_results_error">Couldn\'t create test results report.</string>
     <string name="export">Export</string>
     <string name="no_storage">Cannot save report to external storage, see log for details.</string>
     <string name="report_saved">Report saved to: %s</string>
 
+    <!-- Strings for ReportViewerActivity -->
+    <string name="report_viewer">Report Viewer</string>
+
     <!-- Strings for BackupTestActivity -->
     <string name="backup_test">Data Backup Test</string>
     <string name="backup_info">This test checks that data backup and automatic restore works
@@ -93,7 +92,6 @@
     <string name="da_password_quality_alphanumeric">Alphanumeric</string>
     <string name="da_password_quality_numeric">Numeric</string>
     <string name="da_password_quality_something">Something</string>
-    <string name="da_password_quality_unspecified">Unspecified</string>
     <string name="da_password_minimum_length">Minimum Password Length</string>
     <string name="da_maximum_failed_passwords_for_wipe">Maximum Failed Passwords for Wipe</string>
     <string name="da_maximum_time_to_lock">Maximum Time to Lock</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index b31d6c6..9991b9d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -83,6 +83,9 @@
          * Returns a unique identifier for the test.  Usually, this is just the class name.
          */
         String getTestId();
+
+        /** @return null or details about the test run. */
+        String getTestDetails();
     }
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
@@ -111,6 +114,11 @@
         public String getTestId() {
             return getClass().getName();
         }
+
+        @Override
+        public String getTestDetails() {
+            return null;
+        }
     }
 
     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
@@ -139,6 +147,11 @@
         public String getTestId() {
             return getClass().getName();
         }
+
+        @Override
+        public String getTestDetails() {
+            return null;
+        }
     }
 
     public static class TestListActivity extends AbstractTestListActivity
@@ -168,6 +181,11 @@
         public String getTestId() {
             return getClass().getName();
         }
+
+        @Override
+        public String getTestDetails() {
+            return null;
+        }
     }
 
     private static <T extends android.app.Activity & PassFailActivity>
@@ -175,7 +193,8 @@
         View.OnClickListener clickListener = new View.OnClickListener() {
             @Override
             public void onClick(View target) {
-                setTestResultAndFinish(activity, activity.getTestId(), target);
+                setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
+                        target);
             }
         };
 
@@ -278,7 +297,7 @@
 
     /** Set the test result corresponding to the button clicked and finish the activity. */
     private static void setTestResultAndFinish(android.app.Activity activity, String testId,
-            View target) {
+            String testDetails, View target) {
         boolean passed;
         switch (target.getId()) {
             case R.id.pass_button:
@@ -290,16 +309,16 @@
             default:
                 throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
-        setTestResultAndFinish(activity, testId, passed);
+        setTestResultAndFinish(activity, testId, testDetails, passed);
     }
 
     /** Set the test result and finish the activity. */
     public static void setTestResultAndFinish(android.app.Activity activity, String testId,
-            boolean passed) {
+            String testDetails, boolean passed) {
         if (passed) {
-            TestResult.setPassedResult(activity, testId);
+            TestResult.setPassedResult(activity, testId, testDetails);
         } else {
-            TestResult.setFailedResult(activity, testId);
+            TestResult.setFailedResult(activity, testId, testDetails);
         }
 
         activity.finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportViewerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportViewerActivity.java
new file mode 100644
index 0000000..36ec213
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportViewerActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ReportViewerActivity extends Activity {
+
+    public static final String EXTRA_REPORT_CONTENTS = "reportContents";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.report_viewer);
+
+        Intent intent = getIntent();
+        if (intent != null) {
+            String reportContents = intent.getStringExtra(EXTRA_REPORT_CONTENTS);
+            if (reportContents != null) {
+                TextView reportText = (TextView) findViewById(R.id.report_text);
+                reportText.setText(reportContents);
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index f233312..c510653 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -17,8 +17,8 @@
 package com.android.cts.verifier;
 
 import android.app.ListActivity;
+import android.content.Intent;
 import android.os.Bundle;
-import android.text.ClipboardManager;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -52,8 +52,8 @@
                 handleClearItemSelected();
                 return true;
 
-            case R.id.copy:
-                handleCopyItemSelected();
+            case R.id.view:
+                handleViewItemSelected();
                 return true;
 
             case R.id.export:
@@ -70,13 +70,12 @@
         Toast.makeText(this, R.string.test_results_cleared, Toast.LENGTH_SHORT).show();
     }
 
-    private void handleCopyItemSelected() {
+    private void handleViewItemSelected() {
         try {
             TestResultsReport report = new TestResultsReport(this, mAdapter);
-            ClipboardManager clipboardManager = (ClipboardManager)
-                    getSystemService(CLIPBOARD_SERVICE);
-            clipboardManager.setText(report.getContents());
-            Toast.makeText(this, R.string.test_results_copied, Toast.LENGTH_SHORT).show();
+            Intent intent = new Intent(this, ReportViewerActivity.class);
+            intent.putExtra(ReportViewerActivity.EXTRA_REPORT_CONTENTS, report.getContents());
+            startActivity(intent);
         } catch (IOException e) {
             Toast.makeText(this, R.string.test_results_error, Toast.LENGTH_SHORT).show();
             Log.e(TAG, "Couldn't copy test results report", e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index 3f84f51..52d9b32 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -63,6 +63,9 @@
     /** Mutable test results that will change as each test activity finishes. */
     private final Map<String, Integer> mTestResults = new HashMap<String, Integer>();
 
+    /** Map from test name to test details. */
+    private final Map<String, String> mTestDetails = new HashMap<String, String>();
+
     private final LayoutInflater mLayoutInflater;
 
     /** {@link ListView} row that is either a test category header or a test. */
@@ -121,15 +124,15 @@
     }
 
     public void setTestResult(TestResult testResult) {
-        new SetTestResultTask(testResult.getName(), testResult.getResult()).execute();
+        new SetTestResultTask(testResult.getName(), testResult.getResult(),
+                testResult.getDetails()).execute();
     }
 
     class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
         @Override
         protected RefreshResult doInBackground(Void... params) {
             List<TestListItem> rows = getRows();
-            Map<String, Integer> results = getTestResults();
-            return new RefreshResult(rows, results);
+            return getRefreshResults(rows);
         }
 
         @Override
@@ -139,6 +142,8 @@
             mRows.addAll(result.mItems);
             mTestResults.clear();
             mTestResults.putAll(result.mResults);
+            mTestDetails.clear();
+            mTestDetails.putAll(result.mDetails);
             notifyDataSetChanged();
         }
     }
@@ -146,27 +151,40 @@
     static class RefreshResult {
         List<TestListItem> mItems;
         Map<String, Integer> mResults;
+        Map<String, String> mDetails;
 
-        RefreshResult(List<TestListItem> items, Map<String, Integer> results) {
+        RefreshResult(List<TestListItem> items, Map<String, Integer> results,
+                Map<String, String> details) {
             mItems = items;
             mResults = results;
+            mDetails = details;
         }
     }
 
     protected abstract List<TestListItem> getRows();
 
-    Map<String, Integer> getTestResults() {
+    static final String[] REFRESH_PROJECTION = {
+        TestResultsProvider._ID,
+        TestResultsProvider.COLUMN_TEST_NAME,
+        TestResultsProvider.COLUMN_TEST_RESULT,
+        TestResultsProvider.COLUMN_TEST_DETAILS,
+    };
+
+    RefreshResult getRefreshResults(List<TestListItem> items) {
         Map<String, Integer> results = new HashMap<String, Integer>();
+        Map<String, String> details = new HashMap<String, String>();
         ContentResolver resolver = mContext.getContentResolver();
         Cursor cursor = null;
         try {
-            cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI,
-                    TestResultsProvider.ALL_COLUMNS, null, null, null);
+            cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI, REFRESH_PROJECTION,
+                    null, null, null);
             if (cursor.moveToFirst()) {
                 do {
                     String testName = cursor.getString(1);
                     int testResult = cursor.getInt(2);
+                    String testDetails = cursor.getString(3);
                     results.put(testName, testResult);
+                    details.put(testName, testDetails);
                 } while (cursor.moveToNext());
             }
         } finally {
@@ -174,7 +192,7 @@
                 cursor.close();
             }
         }
-        return results;
+        return new RefreshResult(items, results, details);
     }
 
     class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
@@ -193,14 +211,17 @@
 
         private final int mResult;
 
-        SetTestResultTask(String testName, int result) {
+        private final String mDetails;
+
+        SetTestResultTask(String testName, int result, String details) {
             mTestName = testName;
             mResult = result;
+            mDetails = details;
         }
 
         @Override
         protected Void doInBackground(Void... params) {
-            TestResultsProvider.setTestResult(mContext, mTestName, mResult);
+            TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails);
             return null;
         }
     }
@@ -261,6 +282,13 @@
                 : TestResult.TEST_RESULT_NOT_EXECUTED;
     }
 
+    public String getTestDetails(int position) {
+        TestListItem item = getItem(position);
+        return mTestDetails.containsKey(item.testName)
+                ? mTestDetails.get(item.testName)
+                : null;
+    }
+
     public boolean allTestsPassed() {
         for (TestListItem item : mRows) {
             if (item.isTest() && (!mTestResults.containsKey(item.testName)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
index 3b42c3b..68513ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
@@ -21,8 +21,9 @@
 
 /**
  * Object representing the result of a test activity like whether it succeeded or failed.
- * Use {@link #setPassedResult(Activity, String)} or {@link #setFailedResult(Activity, String)} from
- * a test activity like you would {@link Activity#setResult(int)} so that {@link TestListActivity}
+ * Use {@link #setPassedResult(Activity, String, String)} or
+ * {@link #setFailedResult(Activity, String, String)} from a test activity like you would
+ * {@link Activity#setResult(int)} so that {@link TestListActivity}
  * will persist the test result and update its adapter and thus the list view.
  */
 public class TestResult {
@@ -33,25 +34,30 @@
 
     private static final String TEST_NAME = "name";
     private static final String TEST_RESULT = "result";
+    private static final String TEST_DETAILS = "details";
 
     private final String mName;
-
     private final int mResult;
+    private final String mDetails;
 
     /** Sets the test activity's result to pass. */
-    public static void setPassedResult(Activity activity, String testId) {
-        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId));
+    public static void setPassedResult(Activity activity, String testId, String testDetails) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
+                testDetails));
     }
 
     /** Sets the test activity's result to failed. */
-    public static void setFailedResult(Activity activity, String testId) {
-        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId));
+    public static void setFailedResult(Activity activity, String testId, String testDetails) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
+                testDetails));
     }
 
-    private static Intent createResult(Activity activity, int testResult, String testName) {
+    private static Intent createResult(Activity activity, int testResult, String testName,
+            String testDetails) {
         Intent data = new Intent(activity, activity.getClass());
         data.putExtra(TEST_NAME, testName);
         data.putExtra(TEST_RESULT, testResult);
+        data.putExtra(TEST_DETAILS, testDetails);
         return data;
     }
 
@@ -59,15 +65,17 @@
      * Convert the test activity's result into a {@link TestResult}. Only meant to be used by
      * {@link TestListActivity}.
      */
-    public static TestResult fromActivityResult(int resultCode, Intent data) {
+    static TestResult fromActivityResult(int resultCode, Intent data) {
         String name = data.getStringExtra(TEST_NAME);
         int result = data.getIntExtra(TEST_RESULT, TEST_RESULT_NOT_EXECUTED);
-        return new TestResult(name, result);
+        String details = data.getStringExtra(TEST_DETAILS);
+        return new TestResult(name, result, details);
     }
 
-    private TestResult(String name, int result) {
+    private TestResult(String name, int result, String details) {
         this.mName = name;
         this.mResult = result;
+        this.mDetails = details;
     }
 
     /** Return the name of the test like "com.android.cts.verifier.foo.FooTest" */
@@ -79,4 +87,9 @@
     public int getResult() {
         return mResult;
     }
+
+    /** Return null or string containing test output. */
+    public String getDetails() {
+        return mDetails;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
index 0966de4..e4cd24a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
@@ -58,6 +58,7 @@
             int nameIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_NAME);
             int resultIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_RESULT);
             int infoSeenIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_INFO_SEEN);
+            int detailsIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_DETAILS);
 
             ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
             DataOutputStream dataOutput = new DataOutputStream(byteOutput);
@@ -67,10 +68,12 @@
                 String name = cursor.getString(nameIndex);
                 int result = cursor.getInt(resultIndex);
                 int infoSeen = cursor.getInt(infoSeenIndex);
+                String details = cursor.getString(detailsIndex);
 
                 dataOutput.writeUTF(name);
                 dataOutput.writeInt(result);
                 dataOutput.writeInt(infoSeen);
+                dataOutput.writeUTF(details != null ? details : "");
             }
 
             byte[] rawBytes = byteOutput.toByteArray();
@@ -102,17 +105,19 @@
                     String name = dataInput.readUTF();
                     int result = dataInput.readInt();
                     int infoSeen = dataInput.readInt();
+                    String details = dataInput.readUTF();
 
                     values[i] = new ContentValues();
                     values[i].put(TestResultsProvider.COLUMN_TEST_NAME, name);
                     values[i].put(TestResultsProvider.COLUMN_TEST_RESULT, result);
                     values[i].put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, infoSeen);
+                    values[i].put(TestResultsProvider.COLUMN_TEST_DETAILS, details);
                 }
 
                 ContentResolver resolver = mContext.getContentResolver();
                 resolver.bulkInsert(TestResultsProvider.RESULTS_CONTENT_URI, values);
             } else {
-                failBackupTest();
+                Log.e(TAG, "Skipping key: " + data.getKey());
             }
         } catch (IOException e) {
             Log.e(TAG, "Couldn't restore test results...", e);
@@ -122,7 +127,7 @@
 
     private void failBackupTest() {
         TestResultsProvider.setTestResult(mContext, BackupTestActivity.class.getName(),
-                TestResult.TEST_RESULT_FAILED);
+                TestResult.TEST_RESULT_FAILED, null);
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index cc9dc73..df05519 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
@@ -53,12 +53,8 @@
     /** Boolean indicating whether the test info has been seen. */
     static final String COLUMN_TEST_INFO_SEEN = "testinfoseen";
 
-    static final String[] ALL_COLUMNS = {
-        _ID,
-        COLUMN_TEST_NAME,
-        COLUMN_TEST_RESULT,
-        COLUMN_TEST_INFO_SEEN,
-    };
+    /** String containing the test's details. */
+    static final String COLUMN_TEST_DETAILS = "testdetails";
 
     private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
     private static final int RESULTS_ALL = 1;
@@ -87,7 +83,7 @@
 
         private static final String DATABASE_NAME = "results.db";
 
-        private static final int DATABASE_VERSION = 5;
+        private static final int DATABASE_VERSION = 6;
 
         TestResultsOpenHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -99,7 +95,8 @@
                     + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
                     + COLUMN_TEST_NAME + " TEXT, "
                     + COLUMN_TEST_RESULT + " INTEGER,"
-                    + COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0);");
+                    + COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0,"
+                    + COLUMN_TEST_DETAILS + " TEXT);");
         }
 
         @Override
@@ -204,10 +201,12 @@
         return null;
     }
 
-    static void setTestResult(Context context, String testName, int testResult) {
+    static void setTestResult(Context context, String testName, int testResult,
+            String testDetails) {
         ContentValues values = new ContentValues(2);
         values.put(TestResultsProvider.COLUMN_TEST_RESULT, testResult);
         values.put(TestResultsProvider.COLUMN_TEST_NAME, testName);
+        values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
 
         ContentResolver resolver = context.getContentResolver();
         int numUpdated = resolver.update(TestResultsProvider.RESULTS_CONTENT_URI, values,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index efc9c85..e40b428 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -22,6 +22,7 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.text.TextUtils;
 import android.util.Xml;
 
 import java.io.ByteArrayOutputStream;
@@ -55,7 +56,7 @@
 class TestResultsReport {
 
     /** Version of the test report. Increment whenever adding new tags and attributes. */
-    private static final int REPORT_VERSION = 1;
+    private static final int REPORT_VERSION = 2;
 
     /** Format of the report's creation time. Maintain the same format at CTS. */
     private static DateFormat DATE_FORMAT =
@@ -67,6 +68,7 @@
     private static final String BUILD_INFO_TAG = "build-info";
     private static final String TEST_RESULTS_TAG = "test-results";
     private static final String TEST_TAG = "test";
+    private static final String TEST_DETAILS_TAG = "details";
 
     private final Context mContext;
 
@@ -105,7 +107,7 @@
         xml.attribute(null, "model", Build.MODEL);
         xml.attribute(null, "product", Build.PRODUCT);
         xml.attribute(null, "release", Build.VERSION.RELEASE);
-        xml.attribute(null, "sdk", Build.VERSION.SDK);
+        xml.attribute(null, "sdk", Integer.toString(Build.VERSION.SDK_INT));
         xml.endTag(null, BUILD_INFO_TAG);
         xml.endTag(null, DEVICE_INFO_TAG);
 
@@ -118,6 +120,14 @@
                 xml.attribute(null, "title", item.title);
                 xml.attribute(null, "class-name", item.testName);
                 xml.attribute(null, "result", getTestResultString(mAdapter.getTestResult(i)));
+
+                String details = mAdapter.getTestDetails(i);
+                if (!TextUtils.isEmpty(details)) {
+                    xml.startTag(null, TEST_DETAILS_TAG);
+                    xml.text(details);
+                    xml.endTag(null, TEST_DETAILS_TAG);
+                }
+
                 xml.endTag(null, TEST_TAG);
             }
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
index 7d7c16d..755b62d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/AudioQualityVerifierActivity.java
@@ -280,6 +280,11 @@
     }
 
     @Override
+    public String getTestDetails() {
+        return genReport();
+    }
+
+    @Override
     protected void onDestroy() {
         super.onDestroy();
         unregisterReceiver(mReceiver);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/MessageTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/MessageTestActivity.java
index c730aed..2c6324b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/MessageTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/MessageTestActivity.java
@@ -342,7 +342,7 @@
                     new DialogInterface.OnClickListener() {
                 @Override
                 public void onClick(DialogInterface dialog, int which) {
-                    TestResult.setFailedResult(MessageTestActivity.this, getTestId());
+                    TestResult.setFailedResult(MessageTestActivity.this, getTestId(), null);
                     finish();
                 }
             })
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
index efd076d..2b65421 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
@@ -121,7 +121,7 @@
                             @Override
                             public void onClick(DialogInterface dialog, int which) {
                                 PassFailButtons.setTestResultAndFinish(PlayVideoActivity.this,
-                                        getTestId(), false);
+                                        getTestId(), null, false);
                             }
                         })
                         .show();
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index 1c3b28a..08ce270 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -21,12 +21,18 @@
 import android.media.MediaPlayer;
 import android.test.ActivityInstrumentationTestCase2;
 
+import java.io.IOException;
+import java.util.logging.Logger;
+
 /**
  * Base class for tests which use MediaPlayer to play audio or video.
  */
 public class MediaPlayerTestBase extends ActivityInstrumentationTestCase2<MediaStubActivity> {
+    private static final Logger LOG = Logger.getLogger(MediaPlayerTestBase.class.getName());
+
     protected static final int SLEEP_TIME = 1000;
     protected static final int LONG_SLEEP_TIME = 6000;
+    protected static final int STREAM_RETRIES = 5;
 
     public static class Monitor {
         private boolean signalled;
@@ -100,9 +106,24 @@
         }
     }
 
+    /**
+     * Play a video at a path (expected to be a streaming URL).  Will retry playback 5 times before
+     * failing.
+     */
     protected void playVideoTest(String path, int width, int height) throws Exception {
-        mMediaPlayer.setDataSource(path);
-        playLoadedVideo(width, height);
+        boolean playedSuccessfully = false;
+        for (int i = 0; i < STREAM_RETRIES; i++) {
+          try {
+            mMediaPlayer.setDataSource(path);
+            playLoadedVideo(width, height);
+            playedSuccessfully = true;
+            break;
+          } catch (PrepareFailedException e) {
+            // prepare() can fail because of network issues, so try again
+            LOG.warning("prepare() failed on try " + i + ", trying playback again");
+          }
+        }
+        assertTrue("Stream did not play successfully after all attempts", playedSuccessfully);
     }
 
     protected void playVideoTest(int resid, int width, int height) throws Exception {
@@ -131,7 +152,12 @@
                 return true;
             }
         });
-        mMediaPlayer.prepare();
+        try {
+          mMediaPlayer.prepare();
+        } catch (IOException e) {
+          mMediaPlayer.reset();
+          throw new PrepareFailedException();
+        }
         mOnVideoSizeChangedCalled.waitForSignal();
 
         mMediaPlayer.start();
@@ -142,4 +168,6 @@
             Thread.sleep(SLEEP_TIME);
         }
     }
+
+    private static class PrepareFailedException extends Exception {}
 }
diff --git a/tests/tests/net/src/android/net/cts/ListeningPortsTest.java b/tests/tests/net/src/android/net/cts/ListeningPortsTest.java
index b6e6efb..5c1ba7c 100644
--- a/tests/tests/net/src/android/net/cts/ListeningPortsTest.java
+++ b/tests/tests/net/src/android/net/cts/ListeningPortsTest.java
@@ -118,13 +118,18 @@
 
                 String localAddress = fields[1];
                 String state = fields[3];
+                String uid = fields[7];
 
                 assertTrue(procFilePath + " should have an IP address in the second column",
                         isAddress(localAddress));
 
+                String localIp = localAddress.split(":")[0];
+                int localPort = Integer.parseInt(localAddress.split(":")[1], 16);
+
                 if (!isException(localAddress) && isPortListening(state, isTcp)) {
                     throw new ListeningPortsAssertionError(
-                            "Found port listening on " + localAddress + " in " + procFilePath);
+                            "Found port listening on addr=" + localIp + ", port="
+                                + localPort + ", UID=" + uid + " in " + procFilePath);
                 }
             }
         } catch (FileNotFoundException notFound) {
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 3cbb362..a0757fd 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -157,7 +157,9 @@
 
     /**
      * Verify that any publicly readable directories reachable from
-     * the root directory are not writable.
+     * the root directory are not writable.  World writable directories
+     * are a security hole and an application should only be able to
+     * write to it's own home directory.
      *
      * Note: Because not all directories are readable, this is a best-effort
      * test only.  Writable directories within unreadable subdirectories
@@ -170,25 +172,51 @@
 
     private static final Set<String> OTHER_RANDOM_DIRECTORIES = new HashSet<String>(
             Arrays.asList(
-                    "/data/backup",
-                    "/data/secure",
-                    "/data/system",
-                    "/data/dalvik-cache",
-                    "/data/property",
+                    "/data/anr",
                     "/data/app",
                     "/data/app-private",
-                    "/data/local",
-                    "/data/misc",
+                    "/data/backup",
+                    "/data/btips",
+                    "/data/btips/TI",
+                    "/data/btips/TI/opp",
+                    "/data/dalvik-cache",
+                    "/data/data/.drm",
+                    "/data/data/.drm/.wmdrm",
                     "/data/dontpanic",
-                    "/data/lost+found",
                     "/data/drm",
                     "/data/drm/rights",
-                    "/data/data/.drm",
-                    "/data/data/.drm/.wmdrm"
+                    "/data/dump",
+                    "/data/local",
+                    "/data/local/tmp/com.nuance.android.vsuite.vsuiteapp",
+                    "/data/log",
+                    "/data/lost+found",
+                    "/data/misc",
+                    "/data/misc/bluetooth",
+                    "/data/misc/dhcp",
+                    "/data/misc/wifi",
+                    "/data/misc/wifi/sockets",
+                    "/data/property",
+                    "/data/secure",
+                    "/data/shared",
+                    "/data/system",
+                    "/data/wifi",
+                    "/data/wiper",
+                    "/data/wpstiles",
+                    "/dbdata/databases",
+                    "/mnt_ext",
+                    "/mnt_ext/badablk2",
+                    "/mnt_ext/badablk3",
+                    "/mnt_ext/cache",
+                    "/mnt_ext/data"
             )
     );
 
     /**
+     * Verify that directories not discoverable by
+     * testAllOtherDirectoriesNotWritable are not writable.  World
+     * writable directories are a security hole and an application
+     * should only be able to write to it's own home directory.
+     *
      * Because /data and /data/data are not readable, we blindly try to
      * poke around in there looking for bad directories.  There has to be
      * a better way...