Merge "Go faster by wasting CPU" into klp-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 755cb45..5d23eb5 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -19,6 +19,7 @@
CtsInstrumentationAppDiffCert \
CtsPermissionDeclareApp \
CtsPermissionDeclareAppCompat \
+ CtsReadExternalStorageApp \
CtsSharedUidInstall \
CtsSharedUidInstallDiffCert \
CtsSimpleAppInstall \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d3068bd..8695981 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -20,8 +20,8 @@
android:versionCode="1"
android:versionName="1337">
- <!-- Using 10 for more complete NFC support... -->
- <uses-sdk android:minSdkVersion="11"></uses-sdk>
+ <!-- Using 10+ for more complete NFC support... -->
+ <uses-sdk android:minSdkVersion="12"></uses-sdk>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -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/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
index 3779db9..88b05fb 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -17,7 +17,6 @@
package com.android.cts.appsecurity;
import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.InstrumentationResultParser;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -66,15 +65,16 @@
private static final String APP_ACCESS_DATA_PKG = "com.android.cts.appaccessdata";
// External storage constants
+ private static final String COMMON_EXTERNAL_STORAGE_APP_CLASS = "com.android.cts.externalstorageapp.CommonExternalStorageTest";
private static final String EXTERNAL_STORAGE_APP_APK = "CtsExternalStorageApp.apk";
private static final String EXTERNAL_STORAGE_APP_PKG = "com.android.cts.externalstorageapp";
- private static final String EXTERNAL_STORAGE_APP_CLASS = EXTERNAL_STORAGE_APP_PKG
- + ".ExternalStorageTest";
+ private static final String EXTERNAL_STORAGE_APP_CLASS = EXTERNAL_STORAGE_APP_PKG + ".ExternalStorageTest";
+ private static final String READ_EXTERNAL_STORAGE_APP_APK = "CtsReadExternalStorageApp.apk";
+ private static final String READ_EXTERNAL_STORAGE_APP_PKG = "com.android.cts.readexternalstorageapp";
+ private static final String READ_EXTERNAL_STORAGE_APP_CLASS = READ_EXTERNAL_STORAGE_APP_PKG + ".ReadExternalStorageTest";
private static final String WRITE_EXTERNAL_STORAGE_APP_APK = "CtsWriteExternalStorageApp.apk";
- private static final String
- WRITE_EXTERNAL_STORAGE_APP_PKG = "com.android.cts.writeexternalstorageapp";
- private static final String WRITE_EXTERNAL_STORAGE_APP_CLASS = WRITE_EXTERNAL_STORAGE_APP_PKG
- + ".WriteExternalStorageTest";
+ private static final String WRITE_EXTERNAL_STORAGE_APP_PKG = "com.android.cts.writeexternalstorageapp";
+ private static final String WRITE_EXTERNAL_STORAGE_APP_CLASS = WRITE_EXTERNAL_STORAGE_APP_PKG + ".WriteExternalStorageTest";
// testInstrumentationDiffCert constants
private static final String TARGET_INSTRUMENT_APK = "CtsTargetInstrumentationApp.apk";
@@ -207,20 +207,89 @@
}
/**
- * Verify that legacy filesystem paths continue working, and that they all
- * point to same location.
+ * Verify that app with no external storage permissions works correctly.
*/
- public void testExternalStorageLegacyPaths() throws Exception {
+ public void testExternalStorageNone() throws Exception {
try {
+ wipePrimaryExternalStorage(getDevice());
+
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false));
+ assertTrue("Failed external storage with no permissions",
+ runDeviceTests(EXTERNAL_STORAGE_APP_PKG));
+ } finally {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ }
+ }
+
+ /**
+ * Verify that app with
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} works
+ * correctly.
+ */
+ public void testExternalStorageRead() throws Exception {
+ try {
+ wipePrimaryExternalStorage(getDevice());
+
+ getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(READ_EXTERNAL_STORAGE_APP_APK), false));
+ assertTrue("Failed external storage with read permissions",
+ runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG));
+ } finally {
+ getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
+ }
+ }
+
+ /**
+ * Verify that app with
+ * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} works
+ * correctly.
+ */
+ public void testExternalStorageWrite() throws Exception {
+ try {
+ wipePrimaryExternalStorage(getDevice());
+
getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
assertNull(getDevice()
.installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false));
+ assertTrue("Failed external storage with write permissions",
+ runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG));
+ } finally {
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ }
+ }
- assertTrue("Failed to verify legacy filesystem paths", runDeviceTests(
- WRITE_EXTERNAL_STORAGE_APP_PKG, WRITE_EXTERNAL_STORAGE_APP_CLASS,
- "testLegacyPaths"));
+ /**
+ * Verify that app with WRITE_EXTERNAL can leave gifts in external storage
+ * directories belonging to other apps, and those apps can read.
+ */
+ public void testExternalStorageGifts() throws Exception {
+ try {
+ wipePrimaryExternalStorage(getDevice());
+
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false));
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(READ_EXTERNAL_STORAGE_APP_APK), false));
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false));
+
+ assertTrue("Failed to write gifts", runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG,
+ WRITE_EXTERNAL_STORAGE_APP_CLASS, "doWriteGifts"));
+
+ assertTrue("Read failed to verify gifts", runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG,
+ READ_EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
+ assertTrue("None failed to verify gifts", runDeviceTests(EXTERNAL_STORAGE_APP_PKG,
+ EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
} finally {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
}
}
@@ -500,4 +569,9 @@
getDevice().executeShellCommand(cmd, parser);
return listener.getCurrentRunResults();
}
+
+ private static void wipePrimaryExternalStorage(ITestDevice device)
+ throws DeviceNotAvailableException {
+ device.executeShellCommand("rm -rf /sdcard/*");
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
index 91d6ccf..bc99560 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 10
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsExternalStorageApp
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
new file mode 100644
index 0000000..340ebed
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2012 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.externalstorageapp;
+
+import android.content.Context;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests common functionality that should be supported regardless of external
+ * storage status.
+ */
+public class CommonExternalStorageTest extends AndroidTestCase {
+ private static final String TAG = "CommonExternalStorageTest";
+
+ public static final String PACKAGE_NONE = "com.android.cts.externalstorageapp";
+ public static final String PACKAGE_READ = "com.android.cts.readexternalstorageapp";
+ public static final String PACKAGE_WRITE = "com.android.cts.writeexternalstorageapp";
+
+ /**
+ * Primary storage must always be mounted.
+ */
+ public void testExternalStorageMounted() {
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ }
+
+ /**
+ * Verify that single path is always first item in multiple.
+ */
+ public void testMultipleCacheDirs() throws Exception {
+ final File single = getContext().getExternalCacheDir();
+ assertNotNull("Primary storage must always be available", single);
+ final File firstMultiple = getContext().getExternalCacheDirs()[0];
+ assertEquals(single, firstMultiple);
+ }
+
+ /**
+ * Verify that single path is always first item in multiple.
+ */
+ public void testMultipleFilesDirs() throws Exception {
+ final File single = getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
+ assertNotNull("Primary storage must always be available", single);
+ final File firstMultiple = getContext()
+ .getExternalFilesDirs(Environment.DIRECTORY_PICTURES)[0];
+ assertEquals(single, firstMultiple);
+ }
+
+ /**
+ * Verify that single path is always first item in multiple.
+ */
+ public void testMultipleObbDirs() throws Exception {
+ final File single = getContext().getObbDir();
+ assertNotNull("Primary storage must always be available", single);
+ final File firstMultiple = getContext().getObbDirs()[0];
+ assertEquals(single, firstMultiple);
+ }
+
+ /**
+ * Verify we can write to our own package dirs.
+ */
+ public void testPackageDirs() throws Exception {
+ final List<File> paths = getAllPackageSpecificPaths(getContext());
+ for (File path : paths) {
+ if (path == null) continue;
+
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getStorageState(path));
+ assertDirReadWriteAccess(path);
+
+ final File directChild = new File(path, "directChild");
+ final File subdir = new File(path, "subdir");
+ final File subdirChild = new File(path, "subdirChild");
+
+ writeInt(directChild, 32);
+ subdir.mkdirs();
+ assertDirReadWriteAccess(subdir);
+ writeInt(subdirChild, 64);
+
+ assertEquals(32, readInt(directChild));
+ assertEquals(64, readInt(subdirChild));
+ }
+
+ for (File path : paths) {
+ deleteContents(path);
+ }
+ }
+
+ /**
+ * Return a set of several package-specific external storage paths.
+ */
+ public static List<File> getAllPackageSpecificPaths(Context context) {
+ final List<File> paths = new ArrayList<File>();
+ Collections.addAll(paths, context.getExternalCacheDirs());
+ Collections.addAll(paths, context.getExternalFilesDirs(null));
+ Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES));
+ Collections.addAll(paths, context.getObbDirs());
+ return paths;
+ }
+
+ public static List<File> getPrimaryPackageSpecificPaths(Context context) {
+ final List<File> paths = new ArrayList<File>();
+ Collections.addAll(paths, context.getExternalCacheDir());
+ Collections.addAll(paths, context.getExternalFilesDir(null));
+ Collections.addAll(paths, context.getExternalFilesDir(Environment.DIRECTORY_PICTURES));
+ Collections.addAll(paths, context.getObbDir());
+ return paths;
+ }
+
+ public static List<File> getSecondaryPackageSpecificPaths(Context context) {
+ final List<File> paths = new ArrayList<File>();
+ Collections.addAll(paths, dropFirst(context.getExternalCacheDirs()));
+ Collections.addAll(paths, dropFirst(context.getExternalFilesDirs(null)));
+ Collections.addAll(
+ paths, dropFirst(context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES)));
+ Collections.addAll(paths, dropFirst(context.getObbDirs()));
+ return paths;
+ }
+
+ private static File[] dropFirst(File[] before) {
+ final File[] after = new File[before.length - 1];
+ System.arraycopy(before, 1, after, 0, after.length);
+ return after;
+ }
+
+ public static File buildGiftForPackage(Context context, String packageName) {
+ final File myCache = context.getExternalCacheDir();
+ return new File(myCache.getAbsolutePath().replace(context.getPackageName(), packageName),
+ packageName + ".gift");
+ }
+
+ public static void assertDirReadOnlyAccess(File path) {
+ Log.d(TAG, "Asserting read-only access to " + path);
+
+ assertTrue("exists", path.exists());
+ assertTrue("read", path.canRead());
+ assertTrue("execute", path.canExecute());
+ assertNotNull("list", path.list());
+
+ try {
+ final File probe = new File(path, ".probe");
+ assertTrue(!probe.exists());
+ probe.createNewFile();
+ probe.delete();
+ fail("able to create probe!");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ public static void assertDirReadWriteAccess(File path) {
+ Log.d(TAG, "Asserting read/write access to " + path);
+
+ assertTrue("exists", path.exists());
+ assertTrue("read", path.canRead());
+ assertTrue("execute", path.canExecute());
+ assertNotNull("list", path.list());
+
+ try {
+ final File probe = new File(path, ".probe");
+ assertTrue(!probe.exists());
+ probe.createNewFile();
+ probe.delete();
+ } catch (IOException e) {
+ fail("failed to create probe!");
+ }
+ }
+
+ public static void assertDirNoAccess(File path) {
+ Log.d(TAG, "Asserting no access to " + path);
+
+ assertFalse("read", path.canRead());
+ assertNull("list", path.list());
+
+ try {
+ final File probe = new File(path, ".probe");
+ assertTrue(!probe.exists());
+ probe.createNewFile();
+ probe.delete();
+ fail("able to create probe!");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ public static void assertFileReadOnlyAccess(File path) {
+ try {
+ new FileInputStream(path).close();
+ } catch (IOException e) {
+ fail("failed to read!");
+ }
+
+ try {
+ new FileOutputStream(path, true).close();
+ fail("able to write!");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ public static void assertFileReadWriteAccess(File path) {
+ try {
+ new FileInputStream(path).close();
+ } catch (IOException e) {
+ fail("failed to read!");
+ }
+
+ try {
+ new FileOutputStream(path, true).close();
+ } catch (IOException e) {
+ fail("failed to write!");
+ }
+ }
+
+ public static void assertFileNoAccess(File path) {
+ try {
+ new FileInputStream(path).close();
+ fail("able to read!");
+ } catch (IOException e) {
+ // expected
+ }
+
+ try {
+ new FileOutputStream(path, true).close();
+ fail("able to write!");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ public static void deleteContents(File dir) throws IOException {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ deleteContents(file);
+ }
+ assertTrue(file.delete());
+ }
+ assertEquals(0, dir.listFiles().length);
+ }
+ }
+
+ public static void writeInt(File file, int value) throws IOException {
+ final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
+ try {
+ os.writeInt(value);
+ } finally {
+ os.close();
+ }
+ }
+
+ public static int readInt(File file) throws IOException {
+ final DataInputStream is = new DataInputStream(new FileInputStream(file));
+ try {
+ return is.readInt();
+ } finally {
+ is.close();
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
index a3fcf4a..9d24f98 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
@@ -16,43 +16,69 @@
package com.android.cts.externalstorageapp;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
+
import android.os.Environment;
import android.test.AndroidTestCase;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.util.List;
/**
- * Test if {@link Environment#getExternalStorageDirectory()} is readable.
+ * Test external storage from an application that has no external storage
+ * permissions.
*/
public class ExternalStorageTest extends AndroidTestCase {
- private static final String TEST_FILE = "meow";
-
- private void assertExternalStorageMounted() {
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ public void testPrimaryNoAccess() throws Exception {
+ assertDirNoAccess(Environment.getExternalStorageDirectory());
}
- private void readExternalStorage() throws IOException {
- final File file = new File(Environment.getExternalStorageDirectory(), TEST_FILE);
- final InputStream is = new FileInputStream(file);
- try {
- is.read();
- } finally {
- is.close();
+ /**
+ * Verify that above our package directories we always have no access.
+ */
+ public void testAllWalkingUpTreeNoAccess() throws Exception {
+ final List<File> paths = getAllPackageSpecificPaths(getContext());
+ final String packageName = getContext().getPackageName();
+
+ for (File path : paths) {
+ assertTrue(path.getAbsolutePath().contains(packageName));
+
+ // Walk up until we drop our package
+ while (path.getAbsolutePath().contains(packageName)) {
+ assertDirReadWriteAccess(path);
+ path = path.getParentFile();
+ }
+
+ // Keep walking up until we leave device
+ while (Environment.MEDIA_MOUNTED.equals(Environment.getStorageState(path))) {
+ assertDirNoAccess(path);
+ path = path.getParentFile();
+ }
}
}
- public void testFailReadExternalStorage() throws Exception {
- assertExternalStorageMounted();
- try {
- readExternalStorage();
- fail("able read external file");
- } catch (IOException e) {
- // expected
- e.printStackTrace();
- }
+ /**
+ * Verify we can read only our gifts.
+ */
+ public void doVerifyGifts() throws Exception {
+ final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
+ assertFileReadWriteAccess(none);
+ assertEquals(100, readInt(none));
+
+ final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
+ assertFileNoAccess(read);
+
+ final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
+ assertFileNoAccess(write);
}
}
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
new file mode 100644
index 0000000..44e4bef
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2013 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+
+LOCAL_PACKAGE_NAME := CtsReadExternalStorageApp
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/AndroidManifest.xml
new file mode 100644
index 0000000..f6582b9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.readexternalstorageapp">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.cts.readexternalstorageapp" />
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
new file mode 100644
index 0000000..d315651
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 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.readexternalstorageapp;
+
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadOnlyAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
+
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Test external storage from an application that has
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
+ */
+public class ReadExternalStorageTest extends AndroidTestCase {
+
+ public void testPrimaryReadOnly() throws Exception {
+ assertDirReadOnlyAccess(Environment.getExternalStorageDirectory());
+ }
+
+ /**
+ * Verify that above our package directories we always have read only
+ * access.
+ */
+ public void testAllWalkingUpTreeReadOnly() throws Exception {
+ final List<File> paths = getAllPackageSpecificPaths(getContext());
+ final String packageName = getContext().getPackageName();
+
+ for (File path : paths) {
+ assertTrue(path.getAbsolutePath().contains(packageName));
+
+ // Walk up until we drop our package
+ while (path.getAbsolutePath().contains(packageName)) {
+ assertDirReadWriteAccess(path);
+ path = path.getParentFile();
+ }
+
+ // Keep walking up until we leave device
+ while (Environment.MEDIA_MOUNTED.equals(Environment.getStorageState(path))) {
+ assertDirReadOnlyAccess(path);
+ path = path.getParentFile();
+ }
+ }
+ }
+
+ /**
+ * Verify we can read all gifts.
+ */
+ public void doVerifyGifts() throws Exception {
+ final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
+ assertFileReadOnlyAccess(none);
+ assertEquals(100, readInt(none));
+
+ final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
+ assertFileReadWriteAccess(read);
+ assertEquals(101, readInt(read));
+
+ final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
+ assertFileReadOnlyAccess(write);
+ assertEquals(102, readInt(write));
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index 9e056a9..4352bfb 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -17,9 +17,11 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 10
+LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+
LOCAL_PACKAGE_NAME := CtsWriteExternalStorageApp
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 3f103b6..ff2f1b7 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -16,19 +16,30 @@
package com.android.cts.writeexternalstorageapp;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getPrimaryPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getSecondaryPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
+
import android.os.Environment;
import android.test.AndroidTestCase;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.util.List;
import java.util.Random;
/**
- * Test if {@link Environment#getExternalStorageDirectory()} is writable.
+ * Test external storage from an application that has
+ * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}.
*/
public class WriteExternalStorageTest extends AndroidTestCase {
@@ -57,6 +68,10 @@
}
}
+ private void assertExternalStorageMounted() {
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ }
+
public void testReadExternalStorage() throws Exception {
assertExternalStorageMounted();
Environment.getExternalStorageDirectory().list();
@@ -93,25 +108,124 @@
}
}
- private static void assertExternalStorageMounted() {
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ public void testPrimaryReadWrite() throws Exception {
+ assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
}
- private static void writeInt(File file, int value) throws IOException {
- final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
- try {
- os.writeInt(value);
- } finally {
- os.close();
+ /**
+ * Verify that above our package directories (on primary storage) we always
+ * have write access.
+ */
+ public void testPrimaryWalkingUpTreeReadWrite() throws Exception {
+ final List<File> paths = getPrimaryPackageSpecificPaths(getContext());
+ final String packageName = getContext().getPackageName();
+
+ for (File path : paths) {
+ assertTrue(path.getAbsolutePath().contains(packageName));
+
+ // Walk until we leave device, writing the whole way
+ while (Environment.MEDIA_MOUNTED.equals(Environment.getStorageState(path))) {
+ assertDirReadWriteAccess(path);
+ path = path.getParentFile();
+ }
}
}
- private static int readInt(File file) throws IOException {
- final DataInputStream is = new DataInputStream(new FileInputStream(file));
- try {
- return is.readInt();
- } finally {
- is.close();
+ /**
+ * Verify that we have write access in other packages on primary external
+ * storage.
+ */
+ public void testPrimaryOtherPackageWriteAccess() throws Exception {
+ deleteContents(Environment.getExternalStorageDirectory());
+
+ final File ourCache = getContext().getExternalCacheDir();
+ final File otherCache = new File(ourCache.getAbsolutePath()
+ .replace(getContext().getPackageName(), PACKAGE_NONE));
+
+ assertTrue(otherCache.mkdirs());
+ assertDirReadWriteAccess(otherCache);
+ }
+
+ /**
+ * Verify that we have write access in our package-specific directories on
+ * secondary storage devices, but it becomes read-only access above them.
+ */
+ public void testSecondaryWalkingUpTreeReadOnly() throws Exception {
+ final List<File> paths = getSecondaryPackageSpecificPaths(getContext());
+ final String packageName = getContext().getPackageName();
+
+ for (File path : paths) {
+ assertTrue(path.getAbsolutePath().contains(packageName));
+
+ // Walk up until we drop our package
+ while (path.getAbsolutePath().contains(packageName)) {
+ assertDirReadWriteAccess(path);
+ path = path.getParentFile();
+ }
+
+ // Keep walking up until we leave device
+ while (Environment.MEDIA_MOUNTED.equals(Environment.getStorageState(path))) {
+ assertDirReadOnlyAccess(path);
+ path = path.getParentFile();
+ }
}
}
+
+ /**
+ * Verify that .nomedia is created correctly.
+ */
+ public void testVerifyNoMediaCreated() throws Exception {
+ deleteContents(Environment.getExternalStorageDirectory());
+
+ final List<File> paths = getAllPackageSpecificPaths(getContext());
+
+ // Require that .nomedia was created somewhere above each dir
+ for (File path : paths) {
+ final File start = path;
+
+ boolean found = false;
+ while (Environment.MEDIA_MOUNTED.equals(Environment.getStorageState(path))) {
+ final File test = new File(path, ".nomedia");
+ if (test.exists()) {
+ found = true;
+ break;
+ }
+ path = path.getParentFile();
+ }
+
+ if (!found) {
+ fail("Missing .nomedia file above package-specific directory " + start
+ + "; gave up at " + path);
+ }
+ }
+ }
+
+ /**
+ * Leave gifts for other packages in their primary external cache dirs.
+ */
+ public void doWriteGifts() throws Exception {
+ final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
+ none.getParentFile().mkdirs();
+ none.createNewFile();
+ assertFileReadWriteAccess(none);
+
+ writeInt(none, 100);
+ assertEquals(100, readInt(none));
+
+ final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
+ read.getParentFile().mkdirs();
+ read.createNewFile();
+ assertFileReadWriteAccess(read);
+
+ writeInt(read, 101);
+ assertEquals(101, readInt(read));
+
+ final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
+ write.getParentFile().mkdirs();
+ write.createNewFile();
+ assertFileReadWriteAccess(write);
+
+ writeInt(write, 102);
+ assertEquals(102, readInt(write));
+ }
}
diff --git a/tests/tests/app/src/android/app/cts/FragmentTest.java b/tests/tests/app/src/android/app/cts/FragmentTest.java
index c5c0d6c..006f0a9 100644
--- a/tests/tests/app/src/android/app/cts/FragmentTest.java
+++ b/tests/tests/app/src/android/app/cts/FragmentTest.java
@@ -47,7 +47,8 @@
Fragment.instantiate(getContext(), TestNotFragment.class.getName());
fail();
} catch (Exception e) {
- assertTrue(e instanceof IllegalStateException);
+ // Should get an exception and it shouldn't be an IllegalStateException
+ assertFalse(e instanceof IllegalStateException);
}
}
}
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index a06b603..87d9039 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -16,11 +16,13 @@
package android.content.cts;
+import android.app.DownloadManager;
import android.app.SearchManager;
import android.content.ContentUris;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.media.RingtoneManager;
import android.net.Uri;
import android.provider.AlarmClock;
import android.provider.MediaStore;
@@ -197,4 +199,33 @@
intent.putExtra(AlarmClock.EXTRA_MINUTES, 0);
assertCanBeHandled(intent);
}
+
+ public void testOpenDocumentAny() {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("*/*");
+ assertCanBeHandled(intent);
+ }
+
+ public void testOpenDocumentImage() {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("image/*");
+ assertCanBeHandled(intent);
+ }
+
+ public void testCreateDocument() {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("text/plain");
+ assertCanBeHandled(intent);
+ }
+
+ public void testRingtonePicker() {
+ assertCanBeHandled(new Intent(RingtoneManager.ACTION_RINGTONE_PICKER));
+ }
+
+ public void testViewDownloads() {
+ assertCanBeHandled(new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS));
+ }
}
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/MediaStoreIntentsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java
new file mode 100644
index 0000000..4cad6e4
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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 android.provider.cts;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Tests to verify that common actions on {@link MediaStore} content are
+ * available.
+ */
+public class MediaStoreIntentsTest extends AndroidTestCase {
+ public void assertCanBeHandled(Intent intent) {
+ List<ResolveInfo> resolveInfoList = getContext()
+ .getPackageManager().queryIntentActivities(intent, 0);
+ assertNotNull("Missing ResolveInfo", resolveInfoList);
+ assertTrue("No ResolveInfo found for " + intent.toInsecureString(),
+ resolveInfoList.size() > 0);
+ }
+
+ public void testPickImage() {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+ assertCanBeHandled(intent);
+ }
+
+ public void testPickVideo() {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setData(MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
+ assertCanBeHandled(intent);
+ }
+
+ public void testPickAudio() {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
+ assertCanBeHandled(intent);
+ }
+
+ public void testViewImage() {
+ final String[] schemes = new String[] {
+ "file", "http", "https", "content" };
+ final String[] mimes = new String[] {
+ "image/bmp", "image/jpeg", "image/png", "image/gif", "image/webp" };
+
+ for (String scheme : schemes) {
+ for (String mime : mimes) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ final Uri uri = new Uri.Builder().scheme(scheme)
+ .authority("example.com").path("image").build();
+ intent.setDataAndType(uri, mime);
+ assertCanBeHandled(intent);
+ }
+ }
+ }
+
+ public void testViewVideo() {
+ final String[] schemes = new String[] {
+ "file", "http", "https", "content" };
+ final String[] mimes = new String[] {
+ "video/mpeg4", "video/mp4", "video/3gp", "video/3gpp", "video/3gpp2",
+ "video/webm" };
+
+ for (String scheme : schemes) {
+ for (String mime : mimes) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ final Uri uri = new Uri.Builder().scheme(scheme)
+ .authority("example.com").path("video").build();
+ intent.setDataAndType(uri, mime);
+ assertCanBeHandled(intent);
+ }
+ }
+ }
+
+ public void testViewAudio() {
+ final String[] schemes = new String[] {
+ "file", "http", "content" };
+ final String[] mimes = new String[] {
+ "audio/mpeg", "audio/mp4", "audio/ogg", "audio/webm", "application/ogg",
+ "application/x-ogg" };
+
+ for (String scheme : schemes) {
+ for (String mime : mimes) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ final Uri uri = new Uri.Builder().scheme(scheme)
+ .authority("example.com").path("audio").build();
+ intent.setDataAndType(uri, mime);
+ assertCanBeHandled(intent);
+ }
+ }
+ }
+
+ public void testSearchActions() {
+ assertCanBeHandled(new Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH));
+ assertCanBeHandled(new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH));
+ assertCanBeHandled(new Intent(MediaStore.INTENT_ACTION_TEXT_OPEN_FROM_SEARCH));
+ assertCanBeHandled(new Intent(MediaStore.INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH));
+ }
+}
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) {