Merge "Tests to verify PICK and VIEW are handled." into klp-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d3068bd..f34b096 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -41,6 +41,8 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+
     <uses-feature android:name="android.hardware.usb.accessory" />
 
     <!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
@@ -52,7 +54,6 @@
             android:debuggable="true"
             android:largeHeap="true">
 
-        <uses-library android:name="com.android.future.usb.accessory" />
         <meta-data android:name="com.google.android.backup.api_key"
                 android:value="AEdPqrEAAAAIbK6ldcOzoeRtQ1u1dFVJ1A7KetRhit-a1Xa82Q" />
 
@@ -354,7 +355,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_camera" />
             <meta-data android:name="test_required_features" android:value="android.hardware.sensor.gyroscope" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.camera.any"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.camera"/>
         </activity>
         <activity
             android:name=".camera.fov.DetermineFovActivity"
@@ -462,6 +463,18 @@
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
         </activity>
 
+        <activity android:name=".deskclock.DeskClockTestsActivity"
+                  android:label="@string/deskclock_tests">
+            <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_deskclock" />
+        </activity>
+
+        <activity android:name=".deskclock.ShowAlarmsTestActivity"
+                  android:label="@string/dc_show_alarms_test"/>
+
         <receiver android:name=".widget.WidgetCtsProvider">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/apps/CtsVerifier/res/layout/dc_show_alarms.xml b/apps/CtsVerifier/res/layout/dc_show_alarms.xml
new file mode 100644
index 0000000..06a2bb1
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/dc_show_alarms.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+    >
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_alignParentTop="true"
+                  android:padding="5dp"
+        >
+
+        <TextView android:layout_width="wrap_content"
+                  android:textSize="18sp"
+                  android:layout_height="wrap_content"
+                  android:text="@string/dc_show_alarms_test_info"
+            />
+
+        <Button android:id="@+id/dc_show_alarms"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/dc_show_alarms_button"
+            />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        >
+        <include layout="@layout/pass_fail_buttons" />
+    </LinearLayout>
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index ed2ecd4..ef14be3 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -32,6 +32,7 @@
     <string name="test_category_security">Security</string>
     <string name="test_category_streaming">Streaming</string>
     <string name="test_category_features">Features</string>
+    <string name="test_category_deskclock">Desk Clock</string>
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
     <string name="test_results_cleared">Test results cleared.</string>
@@ -614,4 +615,22 @@
     <string name="widget_name">Widget Framework Test</string>
     <string name="widget_pass">Pass</string>
     <string name="widget_fail">Fail</string>
+
+    <!-- Strings for DeskClock -->
+    <string name="deskclock_tests">Desk Clock Tests</string>
+    <string name="deskclock_tests_info">
+        The Desk Clock tests verify that the Desk Clock app implements the Clock API\'s properly.
+    </string>
+    <string name="deskclock_group_alarms">Alarms</string>
+    <string name="deskclock_group_timers">Timers</string>
+
+    <string name="dc_show_alarms_test">Show Alarms Test</string>
+    <string name="dc_show_alarms_test_info">
+        This test verifies that the SHOW_ALARMS API works.\n
+        1. Press the "Show Alarms" button.\n
+        2. Verify that the Desk Clock app is launched and displays the Alarms section\n
+    </string>
+    <string name="dc_show_alarms_button">Show Alarms</string>
+
+
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
new file mode 100644
index 0000000..91b9b98
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
@@ -0,0 +1,52 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+package com.android.cts.verifier.deskclock;
+
+import android.content.Intent;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
+
+/**
+ * Activity that lists all the DeskClock tests.
+ */
+public class DeskClockTestsActivity extends PassFailButtons.TestListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.pass_fail_list);
+        setInfoResources(R.string.deskclock_tests, R.string.deskclock_tests_info, 0);
+        setPassFailButtonClickListeners();
+
+        getPassButton().setEnabled(false);
+
+        final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+
+        adapter.add(TestListItem.newCategory(this, R.string.deskclock_group_alarms));
+        adapter.add(TestListItem.newTest(this,
+                R.string.dc_show_alarms_test,
+                ShowAlarmsTestActivity.class.getName(),
+                new Intent(this, ShowAlarmsTestActivity.class), null));
+
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+
+        setTestListAdapter(adapter);
+    }
+
+    /**
+     * Enable Pass Button when the all tests passed.
+     */
+    private void updatePassButton() {
+        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java
new file mode 100644
index 0000000..0ce8f51
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/ShowAlarmsTestActivity.java
@@ -0,0 +1,37 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+package com.android.cts.verifier.deskclock;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.AlarmClock;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+public class ShowAlarmsTestActivity extends PassFailButtons.Activity implements OnClickListener {
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dc_show_alarms);
+        setPassFailButtonClickListeners();
+
+        final View button = findViewById(R.id.dc_show_alarms);
+        button.setOnClickListener(this);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        setResult(RESULT_CANCELED);
+    }
+
+    @Override
+    public void onClick(View v) {
+        startActivity(new Intent(AlarmClock.ACTION_SHOW_ALARMS));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 46963a0..1a68b48 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -154,7 +154,7 @@
 
     public static final Feature[] ALL_HONEYCOMB_MR1_FEATURES = {
             new Feature("android.hardware.usb.host", false),
-            new Feature("android.hardware.usb.accessory", true),
+            new Feature("android.hardware.usb.accessory", false),
     };
 
     public static final Feature[] ALL_HONEYCOMB_MR2_FEATURES = {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
index 2968a47..7091cac 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -75,19 +75,33 @@
         String[] ids = mCameraManager.getCameraIdList();
         if (VERBOSE) Log.v(TAG, "CameraManager ids: " + Arrays.toString(ids));
 
-        // Test: that if the device has a camera, there must be at least one reported id.
-        assertTrue("At least one camera must be detected",
-               ! mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
-            || ids.length >= 1);
+        /**
+         * Test: that if there is at least one reported id, then the system must have
+         * the FEATURE_CAMERA_ANY feature.
+         */
+        assertTrue("System camera feature and camera id list don't match",
+                ids.length == 0 ||
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
 
         /**
-         * Test: that if the device has both front and rear facing cameras, then there
-         * must be at lest two reported ids.
+         * Test: that if the device has front or rear facing cameras, then there
+         * must be matched system features.
          */
-        assertTrue("At least two cameras must be detected",
-               ! mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
-            || ! mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
-            || ids.length >= 2);
+        for (int i = 0; i < ids.length; i++) {
+            CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
+            assertNotNull("Can't get camera characteristics for camera " + ids[i], props);
+            Integer lensFacing = props.get(CameraCharacteristics.LENS_FACING);
+            assertNotNull("Can't get lens facing info", lensFacing);
+            if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) {
+                assertTrue("System doesn't have front camera feature",
+                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
+            } else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
+                assertTrue("System doesn't have back camera feature",
+                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA));
+            } else {
+                fail("Unknown camera lens facing " + lensFacing.toString());
+            }
+        }
 
         /**
          * Test: that if there is one camera device, then the system must have some
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
index c2f0c32..326c959 100644
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
@@ -21,6 +21,7 @@
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaFormat;
+import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -71,6 +72,18 @@
         decode(BASIC_IVF);
     }
 
+    /**
+     * Check if MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME is honored.
+     *
+     * At frame 15, request a sync frame. If one does not occur by EOF the
+     * encoder fails. The test does not verify the output stream.
+     */
+    public void testSyncFrame() throws Exception {
+        encodeSyncFrame(R.raw.video_176x144_yv12,
+                        176, // width
+                        144, // height
+                        30); // framerate
+    }
 
     /**
      * A basic check if an encoded stream is decodable.
@@ -221,7 +234,8 @@
             ivf = new IvfWriter(outputFilename, frameWidth, frameHeight);
             // encode loop
             long presentationTimeUs = 0;
-            int frameIndex = 0;
+            int inputFrameIndex = 0;
+            int outputFrameIndex = 0;
             boolean sawInputEOS = false;
             boolean sawOutputEOS = false;
 
@@ -241,8 +255,8 @@
                         mInputBuffers[inputBufIndex].put(frame);
                         mInputBuffers[inputBufIndex].rewind();
 
-                        presentationTimeUs = (frameIndex * 1000000) / frameRate;
-                        Log.d(TAG, "Encoding frame at index " + frameIndex);
+                        presentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
+                        Log.d(TAG, "Encoding frame at index " + inputFrameIndex);
                         encoder.queueInputBuffer(
                                 inputBufIndex,
                                 0,  // offset
@@ -250,7 +264,7 @@
                                 presentationTimeUs,
                                 sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
 
-                        frameIndex++;
+                        inputFrameIndex++;
                     }
                 }
 
@@ -261,6 +275,12 @@
                     mOutputBuffers[outputBufIndex].rewind();
                     mOutputBuffers[outputBufIndex].get(buffer, 0, mBufferInfo.size);
 
+                    if ((outputFrameIndex == 0)
+                        && ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0)) {
+                      throw new RuntimeException("First frame is not a sync frame.");
+
+                    }
+
                     if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                         sawOutputEOS = true;
                     } else {
@@ -268,6 +288,8 @@
                     }
                     encoder.releaseOutputBuffer(outputBufIndex,
                                                 false);  // render
+
+                    outputFrameIndex++;
                 } else if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                     mOutputBuffers = encoder.getOutputBuffers();
                 }
@@ -285,4 +307,128 @@
             }
         }
     }
+
+
+    /**
+     * Request Sync Frames
+     *
+     * MediaCodec will raise an IllegalStateException
+     * whenever vp8 encoder fails to encode a frame.
+     *
+     * This presumes a file with 28 frames. Under normal circumstances there
+     * would only be one sync frame: the first one. This test will request an
+     * additional sync frame at 15 and ensure that it occurs by EOF.
+     *
+     * Color format of input file should be YUV420, and frameWidth,
+     * frameHeight should be supplied correctly as raw input file doesn't
+     * include any header data.
+     *
+     * @param rawInputFd      File descriptor for the raw input file (YUV420)
+     * @param frameWidth      Frame width of input file
+     * @param frameHeight     Frame height of input file
+     * @param frameRate       Frame rate of input file in frames per second
+     */
+    private void encodeSyncFrame(int rawInputFd, int frameWidth,
+                                 int frameHeight, int frameRate) throws Exception {
+        int frameSize = frameWidth * frameHeight * 3 / 2;
+
+
+        // Create a media format signifying desired output
+        MediaFormat format = MediaFormat.createVideoFormat(VP8_MIME, frameWidth, frameHeight);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, 100000);
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+                          CodecCapabilities.COLOR_FormatYUV420Planar);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+
+        Log.d(TAG, "Creating encoder");
+        MediaCodec encoder;
+        encoder = MediaCodec.createByCodecName(VPX_ENCODER_NAME);
+        encoder.configure(format,
+                          null,  // surface
+                          null,  // crypto
+                          MediaCodec.CONFIGURE_FLAG_ENCODE);
+        encoder.start();
+
+        mInputBuffers = encoder.getInputBuffers();
+        mOutputBuffers = encoder.getOutputBuffers();
+
+        InputStream rawStream = null;
+
+        try {
+            rawStream = mResources.openRawResource(rawInputFd);
+            // encode loop
+            long presentationTimeUs = 0;
+            int inputFrameIndex = 0;
+            boolean sawInputEOS = false;
+            boolean sawOutputEOS = false;
+            boolean syncFrameRequested = false;
+            boolean matchedSyncFrame = false;
+
+            while (!sawOutputEOS) {
+                if (!sawInputEOS) {
+                    int inputBufIndex = encoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);
+                    if (inputBufIndex >= 0) {
+                        byte[] frame = new byte[frameSize];
+                        int bytesRead = rawStream.read(frame);
+
+                        if (bytesRead == -1) {
+                            sawInputEOS = true;
+                            bytesRead = 0;
+                        }
+
+                        mInputBuffers[inputBufIndex].clear();
+                        mInputBuffers[inputBufIndex].put(frame);
+                        mInputBuffers[inputBufIndex].rewind();
+
+                        if (inputFrameIndex == 15) {
+                            Log.d(TAG, "Requesting sync frame at index " + inputFrameIndex);
+                            Bundle syncFrame = new Bundle();
+                            syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
+                            encoder.setParameters(syncFrame);
+                            syncFrameRequested = true;
+                        }
+
+                        presentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
+                        encoder.queueInputBuffer(
+                                inputBufIndex,
+                                0,  // offset
+                                bytesRead,  // size
+                                presentationTimeUs,
+                                sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+                        inputFrameIndex++;
+                    }
+                }
+
+                int result = encoder.dequeueOutputBuffer(mBufferInfo, DEFAULT_TIMEOUT_US);
+                if (result >= 0) {
+                    if (syncFrameRequested && ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0)) {
+                        Log.d(TAG, "Found sync frame");
+                        matchedSyncFrame = true;
+                    }
+
+                    if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                        sawOutputEOS = true;
+                    }
+
+                    encoder.releaseOutputBuffer(result,
+                                                false);  // render
+
+                } else if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                    mOutputBuffers = encoder.getOutputBuffers();
+                }
+            }
+
+            if (!matchedSyncFrame) {
+                throw new RuntimeException("Requested sync frame did not occur");
+            }
+
+            encoder.stop();
+            encoder.release();
+        } finally {
+            if (rawStream != null) {
+                rawStream.close();
+            }
+        }
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index e68286f..3f28a34 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -78,6 +78,13 @@
 
         mHelper = new FileCopyHelper(mContext);
         mRowsAdded = new ArrayList<Uri>();
+
+        String campath = Environment.getExternalStorageDirectory() + File.separator +
+                Environment.DIRECTORY_DCIM + File.separator + "Camera";
+        File camfile = new File(campath);
+        if (!camfile.exists()) {
+            assertTrue("failed to create " + campath, camfile.mkdir());
+        }
     }
 
     public void testInsertImageWithImagePath() throws Exception {
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
index e8a13a9..03adad7 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
@@ -68,6 +68,13 @@
 
         mHelper = new FileCopyHelper(mContext);
         mRowsAdded = new ArrayList<Uri>();
+
+        String campath = Environment.getExternalStorageDirectory() + File.separator +
+                Environment.DIRECTORY_DCIM + File.separator + "Camera";
+        File camfile = new File(campath);
+        if (!camfile.exists()) {
+            assertTrue("failed to create " + campath, camfile.mkdir());
+        }
     }
 
     public void testQueryInternalThumbnails() throws Exception {
diff --git a/tests/tests/text/src/android/text/cts/EmojiTest.java b/tests/tests/text/src/android/text/cts/EmojiTest.java
index a8d8d2d..f5f191f 100644
--- a/tests/tests/text/src/android/text/cts/EmojiTest.java
+++ b/tests/tests/text/src/android/text/cts/EmojiTest.java
@@ -222,6 +222,14 @@
 
             webViewOnUiThread.loadDataAndWaitForCompletion("<html><body>" + String.valueOf(c) + "</body></html>",
                     "text/html; charset=utf-8", "utf-8");
+            // The Chromium-powered WebView renders asynchronously and there's nothing reliable
+            // we can easily wait for to be sure that capturePicture will return a fresh frame.
+            // So, just sleep for a sufficient time.
+            try {
+                Thread.sleep(250);
+            } catch (InterruptedException e) {
+                return null;
+            }
 
             Picture picture = webViewOnUiThread.capturePicture();
             if (picture == null || picture.getHeight() <= 0 || picture.getWidth() <= 0) {