Merge "Revert "Add a few test cases in SensorBatchingTests into knownfailures"" into marshmallow-cts-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 701b3a8..c0404b8 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.verifier"
android:versionCode="5"
- android:versionName="6.0_r4">
+ android:versionName="6.0_r5">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23"/>
@@ -73,20 +73,7 @@
<uses-library android:name="android.test.runner"/>
- <activity android:name=".TestListActivity" android:label="@string/app_name">
- <!--
- TestListActivity will have the USB accessory Test in its test list, but it
- does not have any code to handle the USB accessory. The test has to be started
- from TestListActivity or the pass/fail status won't be properly recorded. Also
- this is to prevent the dialog saying there is no application able to support the
- accessory from being shown.
- -->
- <intent-filter>
- <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
- </intent-filter>
- <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/accessory_filter" />
- </activity>
+ <activity android:name=".TestListActivity" android:label="@string/app_name" />
<activity android:name=".ReportViewerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
@@ -441,8 +428,7 @@
</activity>
<activity android:name=".net.ConnectivityScreenOffTestActivity"
- android:label="@string/network_screen_off_test"
- android:screenOrientation="portrait">
+ android:label="@string/network_screen_off_test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
@@ -718,7 +704,8 @@
A DeviceAdmin receiver for sensor tests, it allows sensor tests to turn off the screen.
-->
<receiver android:name=".sensors.helpers.SensorDeviceAdminReceiver"
- android:label="@string/snsr_device_admin_receiver">
+ android:label="@string/snsr_device_admin_receiver"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="@xml/sensor_device_admin" />
<intent-filter>
@@ -1037,11 +1024,17 @@
<activity android:name=".usb.UsbAccessoryTestActivity"
android:label="@string/usb_accessory_test"
- android:configChanges="keyboardHidden|orientation|screenSize">
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
<meta-data android:name="test_category" android:value="@string/test_category_hardware" />
<meta-data android:name="test_required_features" android:value="android.hardware.usb.accessory" />
<meta-data android:name="test_excluded_features"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 013eb1e..3f5af45 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -864,18 +864,24 @@
<string name="usb_accessory_test">USB Accessory Test</string>
<string name="sensor_power_test">Sensor Power Test</string>
<string name="usb_accessory_test_info">
- 1. Connect your Android device to a computer and run the \'cts-usb-accessory\' program
- included with the CTS Verifier bundle.
- \n\n2. If you have not started the CTS Verifier, press \'OK\' when asked to open the CTS
+ 1. Connect your Android device to a computer and ensure that the connection is set
+ to charging only from the Android device.
+ \n\n2.Run the \'cts-usb-accessory\' program included with the CTS Verifier bundle.
+ \n\n3. If you have not started the CTS Verifier, press \'OK\' when asked to open the CTS
Verifier when the accessory is connected. \n\nIf you are already in this test,
then you can press \'Cancel\' but press \'OK\' in the next dialog asking whether to allow
CTS Verifier to access the accessory.
- \n\n3. You should see the accessory and the CTS Verifier display a series of messages
+ \n\n4. You should see the accessory and the CTS Verifier display a series of messages
which indicates that the accessory support is working properly.
</string>
<string name="usb_not_available_title">USB accessory feature is not available?</string>
<string name="usb_not_available_message">If your device is supposed to support USB accessories, your API implementation is not behaving correctly!</string>
<string name="usb_received_messages">Received Messages</string>
+ <string name="usb_reconnect_title">Disconnect and Reconnect</string>
+ <string name="usb_disconnect_message">Please disconnect the Android device and the computer.</string>
+ <string name="usb_connect_message">Please connect the Android device and the computer.</string>
+ <string name="usb_reconnect_abort">Abort Test</string>
+ <string name="usb_wait_for_done">Could not find USB accessory. Try waiting longer.</string>
<string name="usb_sent_messages">Sent Messages</string>
<string name="usb_no_messages">No messages</string>
<string name="usb_message_thread_started">Starting message processing...</string>
@@ -883,6 +889,7 @@
<string name="usb_message_thread_ended">Stopping message processing...</string>
<string name="usb_test_passed">Received all expected messages. Pass button enabled!</string>
<string name="usb_file_descriptor_error">Could not open file descriptor for USB accessory... try reconnecting and restarting the accessory?</string>
+ <string name="usb_test_abort">Test lost focus, aborting test.</string>
<!-- Strings for the Camera ITS test activity -->
<string name="camera_its_test">Camera ITS Test</string>
@@ -1647,8 +1654,9 @@
Please press the Go button to open the Security page in Settings.
Navigate to Device administrators and confirm that:\n
\n
- - Both Personal and Work categories exist.\n
+ - Device administrators outside of the work profile (if any) appear in the list, and the managed profile administrators are badged correctly.\n
- \"CTS Verifier\" exists under the Work category, and is activated.\n
+ - Attempting to uncheck badged \"CTS Verifier\" shows an alert dialog informing you that this admin can be deactivated only if you remove the managed profile.\n
\n
Use the Back button to return to this page.
</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
index e5af6ba..44029a9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
@@ -74,6 +74,7 @@
private Size mSurfaceSize;
private boolean mCameraInitialized = false;
private boolean mPreviewActive = false;
+ private boolean mTakingPicture = false;
private int mResolutionSpinnerIndex = -1;
private WakeLock mWakeLock;
private long shutterStartTime;
@@ -148,15 +149,18 @@
previewView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- shutterStartTime = System.currentTimeMillis();
+ if (!mTakingPicture) {
+ mTakingPicture = true;
+ shutterStartTime = System.currentTimeMillis();
- mCamera.takePicture(new ShutterCallback() {
- @Override
- public void onShutter() {
- long dT = System.currentTimeMillis() - shutterStartTime;
- Log.d("CTS", "Shutter Lag: " + dT);
- }
- }, null, PhotoCaptureActivity.this);
+ mCamera.takePicture(new ShutterCallback() {
+ @Override
+ public void onShutter() {
+ long dT = System.currentTimeMillis() - shutterStartTime;
+ Log.d("CTS", "Shutter Lag: " + dT);
+ }
+ }, null, PhotoCaptureActivity.this);
+ }
}
});
@@ -268,6 +272,7 @@
String message = getResources().getString(R.string.camera_fov_reported_fov_problem_message);
dialogBuilder.setMessage(String.format(message, mReportedFovPrePictureTaken, mReportedFovDegrees));
mActiveDialog = dialogBuilder.show();
+ mTakingPicture = false;
return;
}
@@ -285,8 +290,8 @@
Log.e(TAG, "Could not save picture file.", e);
Toast.makeText(this, "Could not save picture file: " + e.getMessage(),
Toast.LENGTH_LONG).show();
- return;
}
+ mTakingPicture = false;
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
index e529b67..6109893 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/net/ConnectivityScreenOffTestActivity.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -89,7 +90,7 @@
private final ScreenAndPlugStateReceiver mReceiver;
private final IntentFilter mIntentFilter;
- private boolean mHasBattery;
+ private boolean mWaitForPowerDisconnected;
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
@@ -159,10 +160,11 @@
null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// Whether or not this device (currently) has a battery.
- mHasBattery = batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+ mWaitForPowerDisconnected =
+ batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false) && !isLeanback();
// Check if the device is already on battery power.
- if (mHasBattery) {
+ if (mWaitForPowerDisconnected) {
BatteryManager battMgr = (BatteryManager) getSystemService(Context.BATTERY_SERVICE);
if (!battMgr.isCharging()) {
mState.setPowerDisconnected();
@@ -286,7 +288,8 @@
/**
* TODO(ek): Evaluate reworking the code roughly as follows:
- * - Move all the shared state here, including mHasBattery (and mTestingThread).
+ * - Move all the shared state here, including mWaitForPowerDisconnected
+ * (and mTestingThread).
* - Move from synchronizing on mLock to synchronizing on this since the
* AppState object is final, and delete mLock.
* - Synchronize the methods below, and add some required new methods.
@@ -311,7 +314,9 @@
void setPowerConnected() { mPowerDisconnectTime = 0; }
void setPowerDisconnected() { mPowerDisconnectTime = SystemClock.elapsedRealtime(); }
- boolean validPowerStateForTesting() { return !mHasBattery || (mPowerDisconnectTime > 0); }
+ boolean validPowerStateForTesting() {
+ return !mWaitForPowerDisconnected || (mPowerDisconnectTime > 0);
+ }
}
class ScreenAndPlugStateReceiver extends BroadcastReceiver {
@@ -453,7 +458,7 @@
continue;
}
- if (mHasBattery) {
+ if (mWaitForPowerDisconnected) {
final long delta = SystemClock.elapsedRealtime() - localState.mPowerDisconnectTime;
if (delta < MIN_POWER_DISCONNECT_MS) {
nextSleepDurationMs = (int) (MIN_POWER_DISCONNECT_MS - delta);
@@ -629,4 +634,9 @@
return new HttpResult(rcode, msg);
}
+
+ private boolean isLeanback() {
+ final PackageManager pm = this.getPackageManager();
+ return (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
index ab8546b..5a83601 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
@@ -89,6 +89,9 @@
// Ignore.
}
LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
+ if (mDeviceSuspendLock != null && mDeviceSuspendLock.isHeld()) {
+ mDeviceSuspendLock.release();
+ }
}
@Override
@@ -98,9 +101,6 @@
mScreenManipulator.releaseScreenOn();
mScreenManipulator.close();
}
- if (mDeviceSuspendLock.isHeld()) {
- mDeviceSuspendLock.release();
- }
}
public static class AlarmReceiver extends BroadcastReceiver {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java
index 4132807..84e0ced 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/UsbAccessoryTestActivity.java
@@ -57,6 +57,11 @@
private static final String TAG = UsbAccessoryTestActivity.class.getSimpleName();
private static final int FILE_DESCRIPTOR_PROBLEM_DIALOG_ID = 1;
+ private static final int STATE_START = 0;
+ private static final int STATE_CONNECTED = 1;
+ private static final int STATE_WAITING_FOR_RECONNECT = 2;
+ private static final int STATE_RECONNECTED = 3;
+ private static final int STATE_PASSED = 4;
private static final String ACTION_USB_PERMISSION =
"com.android.cts.verifier.usb.USB_PERMISSION";
@@ -69,12 +74,24 @@
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private UsbReceiver mUsbReceiver;
+ private int mState = STATE_START;
+ private AlertDialog mDisconnectDialog;
+ private AlertDialog mConnectDialog;
+ private UsbAccessory mAccessory;
private ParcelFileDescriptor mFileDescriptor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Test success only works properly if launched from TestListActivity
+ String action = getIntent().getAction();
+ if (ACTION_USB_PERMISSION.equals(action)
+ || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
+ finish();
+ return;
+ }
+
setContentView(R.layout.usb_main);
setInfoResources(R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
setPassFailButtonClickListeners();
@@ -96,10 +113,28 @@
mUsbReceiver = new UsbReceiver();
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
- filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
setupListViews();
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.usb_reconnect_title)
+ .setCancelable(false)
+ .setNegativeButton(R.string.usb_reconnect_abort,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ setTestResultAndFinish(false);
+ }
+ });
+ mConnectDialog = builder
+ .setMessage(R.string.usb_connect_message)
+ .create();
+ mDisconnectDialog = builder
+ .setMessage(R.string.usb_disconnect_message)
+ .create();
}
private boolean hasUsbAccessorySupport() {
@@ -137,21 +172,42 @@
class UsbReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_USB_PERMISSION.equals(intent.getAction())
- || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
- UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
openAccessory(accessory);
} else {
Log.i(TAG, "Permission denied...");
}
mPermissionRequestPending = false;
+ } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(intent.getAction())) {
+ UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory.equals(mAccessory)) {
+ closeAccessory();
+ mDisconnectDialog.dismiss();
+ mConnectDialog.show();
+ }
}
}
}
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
+ UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ openAccessory(accessory);
+ }
+ }
+
private void openAccessory(UsbAccessory accessory) {
+ mAccessory = accessory;
mFileDescriptor = mUsbManager.openAccessory(accessory);
+ if (mState == STATE_START) {
+ mState = STATE_CONNECTED;
+ } else if (mState == STATE_WAITING_FOR_RECONNECT) {
+ mState = STATE_RECONNECTED;
+ mConnectDialog.dismiss();
+ }
if (mFileDescriptor != null) {
FileDescriptor fileDescriptor = mFileDescriptor.getFileDescriptor();
FileInputStream inputStream = new FileInputStream(fileDescriptor);
@@ -162,6 +218,19 @@
}
}
+ private void closeAccessory() {
+ mAccessory = null;
+ if (mFileDescriptor != null) {
+ try {
+ mFileDescriptor.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Exception while closing file descriptor", e);
+ } finally {
+ mFileDescriptor = null;
+ }
+ }
+ }
+
static class MessageThread extends Thread {
private final InputStream mInputStream;
@@ -190,10 +259,11 @@
// Wait for response and send message acks...
int numRead = 0;
byte[] buffer = new byte[16384];
- while (numRead >= 0) {
+ boolean done = false;
+ while (numRead >= 0 && !done) {
numRead = mInputStream.read(buffer);
if (numRead > 0) {
- handleReceivedMessage(buffer, numRead);
+ done = handleReceivedMessage(buffer, numRead);
}
}
} catch (IOException e) {
@@ -206,7 +276,7 @@
mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_ENDING);
}
- private void handleReceivedMessage(byte[] buffer, int numRead) throws IOException {
+ private boolean handleReceivedMessage(byte[] buffer, int numRead) throws IOException {
// TODO: Check the contents of the message?
String text = new String(buffer, 0, numRead).trim();
mHandler.sendReceivedMessage(text);
@@ -214,8 +284,10 @@
// Send back a response..
if (mNextMessageNumber <= 10) {
sendMessage();
+ return false;
} else {
- mHandler.sendEmptyMessage(MessageHandler.TEST_PASSED);
+ mHandler.sendEmptyMessage(MessageHandler.STAGE_PASSED);
+ return true;
}
}
@@ -238,7 +310,7 @@
static final int MESSAGE_THREAD_ENDING = 5;
- static final int TEST_PASSED = 6;
+ static final int STAGE_PASSED = 6;
@Override
public void handleMessage(Message msg) {
@@ -264,9 +336,15 @@
showToast(R.string.usb_message_thread_ended);
break;
- case TEST_PASSED:
- showToast(R.string.usb_test_passed);
- getPassButton().setEnabled(true);
+ case STAGE_PASSED:
+ if (mState == STATE_RECONNECTED) {
+ showToast(R.string.usb_test_passed);
+ getPassButton().setEnabled(true);
+ mState = STATE_PASSED;
+ } else if (mState == STATE_CONNECTED) {
+ mDisconnectDialog.show();
+ mState = STATE_WAITING_FOR_RECONNECT;
+ }
break;
default:
@@ -294,34 +372,34 @@
@Override
protected void onResume() {
super.onResume();
- UsbAccessory[] accessories = mUsbManager.getAccessoryList();
- UsbAccessory accessory = accessories != null && accessories.length > 0
- ? accessories[0]
- : null;
- if (accessory != null) {
- if (mUsbManager.hasPermission(accessory)) {
- openAccessory(accessory);
- } else {
- if (!mPermissionRequestPending) {
- mUsbManager.requestPermission(accessory, mPermissionIntent);
- mPermissionRequestPending = true;
+ if (mState == STATE_START) {
+ UsbAccessory[] accessories = mUsbManager.getAccessoryList();
+ UsbAccessory accessory = accessories != null && accessories.length > 0
+ ? accessories[0]
+ : null;
+ if (accessory != null) {
+ if (mUsbManager.hasPermission(accessory)) {
+ openAccessory(accessory);
+ } else {
+ if (!mPermissionRequestPending) {
+ mUsbManager.requestPermission(accessory, mPermissionIntent);
+ mPermissionRequestPending = true;
+ }
}
}
+ } else if (mState != STATE_CONNECTED && mState != STATE_RECONNECTED) {
+ // Prevent the user from opening any dialogs to change the USB mode
+ closeAccessory();
+ setTestResultAndFinish(false);
+ Toast.makeText(this, R.string.usb_test_abort, Toast.LENGTH_SHORT).show();
+ mState = STATE_START;
}
}
@Override
- protected void onPause() {
- super.onPause();
- if (mFileDescriptor != null) {
- try {
- mFileDescriptor.close();
- } catch (IOException e) {
- Log.e(TAG, "Exception while closing file descriptor", e);
- } finally {
- mFileDescriptor = null;
- }
- }
+ protected void onStop() {
+ super.onStop();
+ closeAccessory();
}
@Override
@@ -349,6 +427,9 @@
@Override
protected void onDestroy() {
super.onDestroy();
- unregisterReceiver(mUsbReceiver);
+ if (mUsbReceiver != null) {
+ unregisterReceiver(mUsbReceiver);
+ }
}
+
}
diff --git a/apps/cts-usb-accessory/cts-usb-accessory.c b/apps/cts-usb-accessory/cts-usb-accessory.c
index 4e747bb..c5da3ef 100644
--- a/apps/cts-usb-accessory/cts-usb-accessory.c
+++ b/apps/cts-usb-accessory/cts-usb-accessory.c
@@ -29,7 +29,9 @@
#include <usbhost/usbhost.h>
#include <linux/usb/f_accessory.h>
-struct usb_device *sDevice = NULL;
+static struct usb_device *sDevice = NULL;
+static int sAfterUnplug = 0;
+static char* sDeviceSerial = NULL;
static void* message_thread(void* arg) {
int *endpoints = (int *)arg;
@@ -67,12 +69,13 @@
nanosleep(&tm, NULL);
}
-static void send_string(struct usb_device *device, int index, const char* string) {
+static int send_string(struct usb_device *device, int index, const char* string) {
int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
- ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0);
+ ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 1000);
// some devices can't handle back-to-back requests, so delay a bit
milli_sleep(10);
+ return ret;
}
static int usb_device_added(const char *devname, void* client_data) {
@@ -88,6 +91,13 @@
return 0;
}
+ char* serial = usb_device_get_serial(device);
+ if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) {
+ free(serial);
+ return 0;
+ }
+ free(serial);
+
vendorId = usb_device_get_vendor_id(device);
productId = usb_device_get_product_id(device);
@@ -101,6 +111,7 @@
printf("Found Android device in accessory mode (%x:%x)...\n",
vendorId, productId);
sDevice = device;
+ sDeviceSerial = usb_device_get_serial(sDevice);
usb_descriptor_iter_init(device, &iter);
while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
@@ -143,22 +154,33 @@
uint16_t protocol = 0;
ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
- ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
- if (ret == 2)
+ ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000);
+ if (ret == 2) {
printf("Device supports protocol version %d\n", protocol);
- else
+ } else {
fprintf(stderr, "Failed to read protocol version\n");
+ }
- send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS");
- send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory");
- send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory");
- send_string(device, ACCESSORY_STRING_VERSION, "1.0");
- send_string(device, ACCESSORY_STRING_URI,
- "http://source.android.com/compatibility/cts-intro.html");
- send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_URI,
+ "http://source.android.com/compatibility/cts-intro.html");
+ ret = (ret < 0) ? ret :
+ send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
- ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
- ACCESSORY_START, 0, 0, 0, 0, 0);
+ ret = (ret < 0) ? ret :
+ usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
+ ACCESSORY_START, 0, 0, 0, 0, 1000);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to start accessory mode\n");
+ }
return 0;
}
@@ -172,8 +194,13 @@
if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
usb_device_close(sDevice);
sDevice = NULL;
- // exit when we are disconnected
- return 1;
+ if (sAfterUnplug) {
+ // exit when we are disconnected the second time
+ free(sDeviceSerial);
+ return 1;
+ } else {
+ sAfterUnplug = 1;
+ }
}
return 0;
}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
index 2ae2e10..6bf2a01 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
@@ -26,6 +26,7 @@
import com.android.cts.appsecurity.SplitTests.BaseInstallMultiple;
import com.android.cts.tradefed.build.CtsBuildHelper;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
@@ -33,6 +34,7 @@
import com.android.tradefed.testtype.IBuildReceiver;
import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
/**
* Set of tests that verify behavior of adopted storage media, if supported.
@@ -147,7 +149,10 @@
final LocalVolumeInfo vol = getAdoptionVolume();
// Move storage there and verify that data went along for ride
- assertSuccess(getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid));
+ final CollectingOutputReceiver out = new CollectingOutputReceiver();
+ getDevice().executeShellCommand("pm move-primary-storage " + vol.uuid, out, 2,
+ TimeUnit.HOURS, 1);
+ assertSuccess(out.getOutput());
runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
diff --git a/libs/testserver/src/android/webkit/cts/CtsTestServer.java b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
index de88f3b..321b44d 100644
--- a/libs/testserver/src/android/webkit/cts/CtsTestServer.java
+++ b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
@@ -54,34 +54,31 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
-import java.net.URLConnection;
-import java.security.KeyManagementException;
import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.Vector;
-import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@@ -115,7 +112,6 @@
private static final String COOKIE_PREFIX = "/cookie";
private static final String LINKED_SCRIPT_PREFIX = "/linkedscriptprefix";
private static final String AUTH_PREFIX = "/auth";
- private static final String SHUTDOWN_PREFIX = "/shutdown";
public static final String NOLENGTH_POSTFIX = "nolength";
private static final int DELAY_MILLIS = 2000;
@@ -223,74 +219,13 @@
* Terminate the http server.
*/
public void shutdown() {
+ mServerThread.shutDownOnClientThread();
+
try {
- // Avoid a deadlock between two threads where one is trying to call
- // close() and the other one is calling accept() by sending a GET
- // request for shutdown and having the server's one thread
- // sequentially call accept() and close().
- URL url = new URL(mServerUri + SHUTDOWN_PREFIX);
- if (url.getProtocol().equalsIgnoreCase("http")) {
- // Use Socket instead of HttpURLConnection when the server is in cleartext HTTP mode
- // to avoid the request being blocked by NetworkSecurityPolicy.
- Socket socket = null;
- try {
- socket = new Socket(url.getHost(), url.getPort());
- socket.getOutputStream().write(
- ("GET " + SHUTDOWN_PREFIX + " HTTP/1.0\r\n\r\n").getBytes("US-ASCII"));
- socket.getOutputStream().flush();
- } finally {
- if (socket != null) {
- try {
- socket.close();
- } catch (Exception ignored) {}
- }
- }
- } else {
- URLConnection connection = openConnection(url);
- connection.connect();
-
- // Read the input from the stream to send the request.
- InputStream is = connection.getInputStream();
- is.close();
- }
-
// Block until the server thread is done shutting down.
mServerThread.join();
-
- } catch (MalformedURLException e) {
- throw new IllegalStateException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException(e);
- } catch (KeyManagementException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private URLConnection openConnection(URL url)
- throws IOException, NoSuchAlgorithmException, KeyManagementException {
- if (mSsl == SslMode.INSECURE) {
- return url.openConnection();
- } else {
- // Install hostname verifiers and trust managers that don't do
- // anything in order to get around the client not trusting
- // the test server due to a lack of certificates.
-
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
- connection.setHostnameVerifier(new CtsHostnameVerifier());
-
- SSLContext context = SSLContext.getInstance("TLS");
- try {
- context.init(ServerThread.getKeyManagers(), getTrustManagers(), null);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- connection.setSSLSocketFactory(context.getSocketFactory());
-
- return connection;
}
}
@@ -775,11 +710,6 @@
response.setEntity(createPage(agent, agent));
} else if (path.equals(TEST_DOWNLOAD_PATH)) {
response = createTestDownloadResponse(Uri.parse(uriString));
- } else if (path.equals(SHUTDOWN_PREFIX)) {
- response = createResponse(HttpStatus.SC_OK);
- // We cannot close the socket here, because we need to respond.
- // Status must be set to OK, or else the test will fail due to
- // a RunTimeException.
} else if (path.equals(APPCACHE_PATH)) {
response = createResponse(HttpStatus.SC_OK);
response.setEntity(createEntity("<!DOCTYPE HTML>" +
@@ -924,9 +854,12 @@
private CtsTestServer mServer;
private ServerSocket mSocket;
private SslMode mSsl;
- private boolean mIsCancelled;
+ private boolean mWillShutDown = false;
private SSLContext mSslContext;
private ExecutorService mExecutorService = Executors.newFixedThreadPool(20);
+ private Object mLock = new Object();
+ // All the sockets bound to an open connection.
+ private Set<Socket> mSockets = new HashSet<Socket>();
/**
* Defines the keystore contents for the server, BKS version. Holds just a
@@ -1012,10 +945,14 @@
}
public void run() {
- while (!mIsCancelled) {
+ while (!mWillShutDown) {
try {
Socket socket = mSocket.accept();
+ synchronized(mLock) {
+ mSockets.add(socket);
+ }
+
DefaultHttpServerConnection conn = mServer.createHttpServerConnection();
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
@@ -1025,17 +962,17 @@
// parsing the response since conn.close() will crash
// for SSL requests due to UnsupportedOperationException.
HttpRequest request = conn.receiveRequestHeader();
- if (isShutdownRequest(request)) {
- mIsCancelled = true;
- }
if (request instanceof HttpEntityEnclosingRequest) {
conn.receiveRequestEntity( (HttpEntityEnclosingRequest) request);
}
- mExecutorService.execute(new HandleResponseTask(conn, request));
+ mExecutorService.execute(new HandleResponseTask(conn, request, socket));
} catch (IOException e) {
// normal during shutdown, ignore
Log.w(TAG, e);
+ } catch (RejectedExecutionException e) {
+ // normal during shutdown, ignore.
+ Log.w(TAG, e);
} catch (HttpException e) {
Log.w(TAG, e);
} catch (UnsupportedOperationException e) {
@@ -1044,10 +981,26 @@
Log.w(TAG, e);
}
}
+ }
+
+ /**
+ * Shutdown the socket and the executor service.
+ * Note this method is called on the client thread, instead of the server thread.
+ */
+ public void shutDownOnClientThread() {
try {
+ mWillShutDown = true;
mExecutorService.shutdown();
mExecutorService.awaitTermination(1L, TimeUnit.MINUTES);
mSocket.close();
+ // To prevent the server thread from being blocked on read from socket,
+ // which is called when the server tries to receiveRequestHeader,
+ // close all the sockets here.
+ synchronized(mLock) {
+ for (Socket socket : mSockets) {
+ socket.close();
+ }
+ }
} catch (IOException ignored) {
// safe to ignore
} catch (InterruptedException e) {
@@ -1055,24 +1008,19 @@
}
}
- private static boolean isShutdownRequest(HttpRequest request) {
- RequestLine requestLine = request.getRequestLine();
- String uriString = requestLine.getUri();
- URI uri = URI.create(uriString);
- String path = uri.getPath();
- return path.equals(SHUTDOWN_PREFIX);
- }
-
private class HandleResponseTask implements Runnable {
private DefaultHttpServerConnection mConnection;
private HttpRequest mRequest;
+ private Socket mSocket;
+
public HandleResponseTask(DefaultHttpServerConnection connection,
- HttpRequest request) {
+ HttpRequest request, Socket socket) {
this.mConnection = connection;
this.mRequest = request;
+ this.mSocket = socket;
}
@Override
@@ -1082,6 +1030,10 @@
mConnection.sendResponseHeader(response);
mConnection.sendResponseEntity(response);
mConnection.close();
+
+ synchronized(mLock) {
+ ServerThread.this.mSockets.remove(mSocket);
+ }
} catch (Exception e) {
Log.e(TAG, "Error handling request:", e);
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
index d78b3b5..c29f866 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -257,7 +257,11 @@
image = reader.acquireNextImage();
} finally {
if (image != null) {
- validateImage(image, mSize.getWidth(), mSize.getHeight(), mFormat, null);
+ // Should only do some quick sanity check in callback, as the ImageReader
+ // could be closed asynchronously, which will close all images acquired from
+ // this ImageReader.
+ checkImage(image, mSize.getWidth(), mSize.getHeight(), mFormat);
+ checkAndroidImageFormat(image);
image.close();
}
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 9f4e75c..49bbff1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -525,11 +525,22 @@
(maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false;
+ float croppedWidth = (float)sensorSize.getWidth();
+ float croppedHeight = (float)sensorSize.getHeight();
+ float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
+ float maxYuvAspectRatio = (float)maxYuvSize.getWidth() / (float)maxYuvSize.getHeight();
+ if (sensorAspectRatio < maxYuvAspectRatio) {
+ croppedHeight = (float)sensorSize.getWidth() / maxYuvAspectRatio;
+ } else if (sensorAspectRatio > maxYuvAspectRatio) {
+ croppedWidth = (float)sensorSize.getHeight() * maxYuvAspectRatio;
+ }
+ Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
+
boolean maxYuvMatchSensor =
- (maxYuvSize.getWidth() <= sensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) &&
- maxYuvSize.getWidth() >= sensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) &&
- maxYuvSize.getHeight() <= sensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
- maxYuvSize.getHeight() >= sensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
+ (maxYuvSize.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) &&
+ maxYuvSize.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN));
// No need to do null check since framework will generate the key if HAL don't supply
boolean haveAeLock = CameraTestUtils.getValueNotNull(
@@ -613,8 +624,9 @@
haveFastSyncLatency);
assertTrue(
String.format("BURST-capable camera device %s max YUV size %s should be" +
- "close to active array size %s",
- mIds[counter], maxYuvSize.toString(), sensorSize.toString()),
+ "close to active array size %s or cropped active array size %s",
+ mIds[counter], maxYuvSize.toString(), sensorSize.toString(),
+ croppedSensorSize.toString()),
maxYuvMatchSensor);
assertTrue(
String.format("BURST-capable camera device %s does not support AE lock",
diff --git a/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
index 2795bde..15ff414 100644
--- a/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -102,10 +102,13 @@
prior = e;
} finally {
try {
+ // Close camera device first. This will give some more time for
+ // ImageVerifierListener to finish the validation before yuvReader is closed
+ // (all image will be closed after that)
+ closeCamera(cameraId);
if (yuvReader != null) {
yuvReader.close();
}
- closeCamera(cameraId);
} catch (Exception e) {
if (prior != null) {
Log.e(TAG, "Prior exception received: " + prior);
diff --git a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
index 3e3e81e..5e029edb 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -108,9 +108,19 @@
// Max jpeg resolution must be very close to sensor resolution
Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+ float croppedWidth = (float)sensorSize.getWidth();
+ float croppedHeight = (float)sensorSize.getHeight();
+ float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
+ float maxJpegAspectRatio = (float)maxJpegSize.getWidth() / (float)maxJpegSize.getHeight();
+ if (sensorAspectRatio < maxJpegAspectRatio) {
+ croppedHeight = (float)sensorSize.getWidth() / maxJpegAspectRatio;
+ } else if (sensorAspectRatio > maxJpegAspectRatio) {
+ croppedWidth = (float)sensorSize.getHeight() * maxJpegAspectRatio;
+ }
+ Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
mCollector.expectSizesAreSimilar(
- "Active array size and max JPEG size should be similar",
- sensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
+ "Active array size or cropped active array size and max JPEG size should be similar",
+ croppedSensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
}
// TODO: test all the keys mandatory for all capability devices.
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 19360e9..d7710bb 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -24,13 +24,6 @@
bug: 17595050
},
{
- description: "test fails on devices with no telephony",
- names: [
- "android.calllog.cts.CallLogBackupTest#testSingleCallBackup"
- ],
- bug: 23776099
-},
-{
description: "test fails on some devices",
names: [
"android.dumpsys.cts.DumpsysHostTest#testBatterystatsOutput",
@@ -158,6 +151,14 @@
bug: 17508787
},
{
+ description: "This test is not working on Android Player",
+ names: [
+ "com.android.cts.devicepolicy.MixedDeviceOwnerTest#testPackageInstallUserRestrictions",
+ "com.android.cts.devicepolicy.MixedProfileOwnerTest#testPackageInstallUserRestrictions"
+ ],
+ bug: 27949133
+},
+{
description: "Test is not yet properly implemented",
names: [
"android.voicesettings.cts.ZenModeTest#testAll"
diff --git a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 4e57d31..39b1713 100644
--- a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -420,22 +420,22 @@
* Check that the {@link TelephonyManager#getPhoneType()} matches the reported features.
*/
public void testTelephonyFeatures() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
int phoneType = mTelephonyManager.getPhoneType();
switch (phoneType) {
case TelephonyManager.PHONE_TYPE_GSM:
- assertAvailable(PackageManager.FEATURE_TELEPHONY);
assertAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
break;
case TelephonyManager.PHONE_TYPE_CDMA:
- assertAvailable(PackageManager.FEATURE_TELEPHONY);
assertAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
break;
case TelephonyManager.PHONE_TYPE_NONE:
- assertNotAvailable(PackageManager.FEATURE_TELEPHONY);
- assertNotAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
- assertNotAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
+ fail("FEATURE_TELEPHONY is present; phone type should not be PHONE_TYPE_NONE");
break;
default:
diff --git a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
index 5b0e0c7..695a138 100644
--- a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
+++ b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
@@ -19,9 +19,11 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
+import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -53,6 +55,7 @@
private static final String LOCAL_BACKUP_COMPONENT =
"android/com.android.internal.backup.LocalTransport";
private static final String CALLLOG_BACKUP_PACKAGE = "com.android.providers.calllogbackup";
+ private static final String ALT_CALLLOG_BACKUP_PACKAGE = "com.android.calllogbackup";
private static final String TEST_NUMBER = "555-1234";
private static final int CALL_START_TIME = 0;
@@ -88,9 +91,18 @@
int presentation;
}
+ private String mCallLogBackupPackageName;
+
@Override
protected void setUp() throws Exception {
super.setUp();
+ PackageManager pm = getContext().getPackageManager();
+ try {
+ pm.getPackageInfo(CALLLOG_BACKUP_PACKAGE, 0);
+ mCallLogBackupPackageName = CALLLOG_BACKUP_PACKAGE;
+ } catch (PackageManager.NameNotFoundException e) {
+ mCallLogBackupPackageName = ALT_CALLLOG_BACKUP_PACKAGE;
+ }
}
/**
@@ -103,16 +115,23 @@
* 6) Verify that we the call from step (2)
*/
public void testSingleCallBackup() throws Exception {
+ if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ Log.i(TAG, "Skipping calllog tests: no telephony feature");
+ return;
+ }
// This CTS test depends on the local transport and so if it is not present,
// skip the test with success.
if (!hasBackupTransport(LOCAL_BACKUP_COMPONENT)) {
- Log.i(TAG, "skipping calllog tests");
+ Log.i(TAG, "skipping calllog tests: no local transport");
return;
}
// Turn on backup and set to the local backup agent.
boolean previouslyEnabled = enableBackup(true /* enable */);
String oldTransport = setBackupTransport(LOCAL_BACKUP_COMPONENT);
+ int previousFullDataBackupAware = Settings.Secure.getInt(getContext().getContentResolver(),
+ "user_full_data_backup_aware", 0);
+ enableFullDataBackupAware(1);
// Clear the call log
Log.i(TAG, "Clearing the call log");
@@ -125,7 +144,7 @@
// Run backup for the call log (saves the single call).
Log.i(TAG, "Running backup");
- runBackupFor(CALLLOG_BACKUP_PACKAGE);
+ runBackupFor(mCallLogBackupPackageName);
Thread.sleep(TIMEOUT_BACKUP); // time for backup
// Clear the call log and verify that it is empty
@@ -135,7 +154,7 @@
// Restore from the previous backup and verify we have the new call again.
Log.i(TAG, "Restoring the single call");
- runRestoreFor(CALLLOG_BACKUP_PACKAGE);
+ runRestoreFor(mCallLogBackupPackageName);
Thread.sleep(TIMEOUT_BACKUP); // time for restore
verifyCall();
@@ -144,6 +163,7 @@
Log.i(TAG, "Reseting backup");
setBackupTransport(oldTransport);
enableBackup(previouslyEnabled);
+ enableFullDataBackupAware(previousFullDataBackupAware);
}
private Call verifyCall() {
@@ -183,6 +203,10 @@
exec("bmgr restore " + packageName);
}
+ private void enableFullDataBackupAware(int status) throws Exception {
+ exec("settings put secure user_full_data_backup_aware " + status);
+ }
+
private String setBackupTransport(String transport) throws Exception {
String output = exec("bmgr transport " + transport);
Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
diff --git a/tests/tests/graphics/assets/bombfont2.ttf b/tests/tests/graphics/assets/bombfont2.ttf
new file mode 100644
index 0000000..604a698
--- /dev/null
+++ b/tests/tests/graphics/assets/bombfont2.ttf
Binary files differ
diff --git a/tests/tests/graphics/assets/bombfont2.ttx b/tests/tests/graphics/assets/bombfont2.ttx
new file mode 100644
index 0000000..ccac1b6
--- /dev/null
+++ b/tests/tests/graphics/assets/bombfont2.ttx
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ <GlyphID id="2" name="b"/>
+ <GlyphID id="3" name="c"/>
+ <GlyphID id="4" name="d"/>
+ <GlyphID id="5" name="e"/>
+ <GlyphID id="6" name="BombEmoji"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0xaf28220f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Sep 9 08:01:17 2015"/>
+ <modified value="Tue Dec 8 03:58:55 2015"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="0"/>
+ <yMax value="0"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="500"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="7"/>
+ <maxPoints value="0"/>
+ <maxContours value="0"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="12"/>
+ <maxStorage value="28"/>
+ <maxFunctionDefs value="119"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="61"/>
+ <maxSizeOfInstructions value="2967"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="97"/>
+ <usLastCharIndex value="65535"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="BombEmoji" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ <mtx name="b" width="500" lsb="93"/>
+ <mtx name="c" width="500" lsb="93"/>
+ <mtx name="d" width="500" lsb="93"/>
+ <mtx name="e" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap ERROR="decompilation error" raw="True">
+ <!-- An error occurred during the decompilation of this table -->
+ <hexdata>
+ 00000002 00030001 00000014 00030001
+ 00000034 00040020 00000004 00040001
+ 00000065 ffff0000 0061ffff ffa00001
+ 00000000 000c0000 00000028 00000000
+ 00000002 00000063 0000005f 00000001
+ 0001f4a3 0001f4a3 00000006
+ </hexdata>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="BombEmoji"/><!-- contains no outline data -->
+
+ <TTGlyph name="a"/><!-- contains no outline data -->
+
+ <TTGlyph name="b"/><!-- contains no outline data -->
+
+ <TTGlyph name="c"/><!-- contains no outline data -->
+
+ <TTGlyph name="d"/><!-- contains no outline data -->
+
+ <TTGlyph name="e"/><!-- contains no outline data -->
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFontTest-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFontTest-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-166"/>
+ <underlineThickness value="20"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ <psName name="BombEmoji"/>
+ </extraNames>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index 2c1b132..5528372 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -192,4 +192,15 @@
float widthCustomTypeface = p.measureText(testString);
assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
}
+
+ public void testInvalidCmapFont2() {
+ Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "bombfont2.ttf");
+ assertNotNull(typeface);
+ Paint p = new Paint();
+ final String testString = "abcde";
+ float widthDefaultTypeface = p.measureText(testString);
+ p.setTypeface(typeface);
+ float widthCustomTypeface = p.measureText(testString);
+ assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
index 9bf1fd6..1399cee 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
@@ -90,6 +90,7 @@
context,
sensorType,
shouldEmulateSensorUnderLoad(),
+ true, /* isIntegrationTest */
sensor.getMinDelay(),
MAX_REPORTING_LATENCY_US);
TestSensorOperation batchingOperation =
@@ -143,6 +144,7 @@
context,
sensorType,
shouldEmulateSensorUnderLoad(),
+ true, /* isIntegrationTest */
generateSamplingRateInUs(sensorType),
generateReportLatencyInUs());
TestSensorOperation sensorOperation =
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 2bbf053..171bef4 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -314,10 +314,14 @@
// TODO: remove when parameterized tests are supported (see SensorBatchingTests.java)
@TimeoutReq(minutes=20)
public void testBatchAndFlush() throws Exception {
+ // TODO - replace this constant once method to do so is made available
+ final int SENSOR_TYPE_DEVICE_PRIVATE_BASE = 0x10000;
SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
ArrayList<Throwable> errorsFound = new ArrayList<>();
for (Sensor sensor : mSensorList) {
- verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
+ if (sensor.getType() < SENSOR_TYPE_DEVICE_PRIVATE_BASE) {
+ verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
+ }
}
assertOnErrors(errorsFound);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
index 47c8313..6ef7938 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
@@ -23,6 +23,8 @@
import java.util.concurrent.TimeUnit;
+/* TODO: Refactor constructors into a builder */
+
/**
* A class that encapsulates base environment information for the {@link SensorOperation}.
* The environment is self contained and carries its state around all the sensor test framework.
@@ -41,6 +43,7 @@
private final int mSamplingPeriodUs;
private final int mMaxReportLatencyUs;
private final boolean mIsDeviceSuspendTest;
+ private final boolean mIsIntegrationTest;
/**
* Constructs an environment for sensor testing.
@@ -131,6 +134,34 @@
* Constructs an environment for sensor testing.
*
* @param context The context for the test
+ * @param sensorType The type of the sensor under test
+ * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
+ * @param isIntegrationTest Whether this is an integration test (more than one sensor actived)
+ * @param samplingPeriodUs The requested collection period for the sensor under test
+ * @param maxReportLatencyUs The requested collection report latency for the sensor under test
+ *
+ * @deprecated Use variants with {@link Sensor} objects.
+ */
+ @Deprecated
+ public TestSensorEnvironment(
+ Context context,
+ int sensorType,
+ boolean sensorMightHaveMoreListeners,
+ boolean isIntegrationTest,
+ int samplingPeriodUs,
+ int maxReportLatencyUs) {
+ this(context,
+ getSensor(context, sensorType),
+ sensorMightHaveMoreListeners,
+ isIntegrationTest,
+ samplingPeriodUs,
+ maxReportLatencyUs);
+ }
+
+ /**
+ * Constructs an environment for sensor testing.
+ *
+ * @param context The context for the test
* @param sensor The sensor under test
* @param samplingPeriodUs The requested collection period for the sensor under test
* @param maxReportLatencyUs The requested collection report latency for the sensor under test
@@ -176,15 +207,46 @@
Context context,
Sensor sensor,
boolean sensorMightHaveMoreListeners,
+ boolean isIntegrationTest,
+ int samplingPeriodUs,
+ int maxReportLatencyUs) {
+ this(context,
+ sensor,
+ sensorMightHaveMoreListeners,
+ samplingPeriodUs,
+ maxReportLatencyUs,
+ false /* isDeviceSuspendTest */,
+ isIntegrationTest);
+ }
+
+ public TestSensorEnvironment(
+ Context context,
+ Sensor sensor,
+ boolean sensorMightHaveMoreListeners,
int samplingPeriodUs,
int maxReportLatencyUs,
boolean isDeviceSuspendTest) {
+ this(context, sensor, sensorMightHaveMoreListeners,
+ samplingPeriodUs, maxReportLatencyUs,
+ false /* isDeviceSuspendTest */,
+ false /* isIntegrationTest */);
+ }
+
+ public TestSensorEnvironment(
+ Context context,
+ Sensor sensor,
+ boolean sensorMightHaveMoreListeners,
+ int samplingPeriodUs,
+ int maxReportLatencyUs,
+ boolean isDeviceSuspendTest,
+ boolean isIntegrationTest) {
mContext = context;
mSensor = sensor;
mSensorMightHaveMoreListeners = sensorMightHaveMoreListeners;
mSamplingPeriodUs = samplingPeriodUs;
mMaxReportLatencyUs = maxReportLatencyUs;
mIsDeviceSuspendTest = isDeviceSuspendTest;
+ mIsIntegrationTest = isIntegrationTest;
}
/**
@@ -265,6 +327,7 @@
}
/**
+ * Calculate the maximum expected sampling period in us.
* @return The maximum acceptable actual sampling period of this sensor.
* For continuous sensors, this is higher than {@link #getExpectedSamplingPeriodUs()}
* because sensors are allowed to run up to 10% slower than requested.
@@ -282,6 +345,20 @@
return (int) (expectedSamplingPeriodUs / MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER);
}
+
+ /**
+ * Calculate the allowed sensor start delay.
+ *
+ * CDD Section 7.3:
+ * MUST report the first sensor sample within 400 milliseconds + 2 * sample_time of the
+ * sensor being activated. It is acceptable for this sample to have an accuracy of 0.
+ *
+ * [CDD] Keep this updated with CDD.
+ */
+ public long getAllowedSensorStartDelay() {
+ return TimeUnit.MILLISECONDS.toMicros(400) + 2 * getMaximumExpectedSamplingPeriodUs();
+ }
+
/**
* @return The number of axes in the coordinate system of the sensor under test.
*/
@@ -378,5 +455,9 @@
public boolean isDeviceSuspendTest() {
return mIsDeviceSuspendTest;
}
+
+ public boolean isIntegrationTest() {
+ return mIsIntegrationTest;
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index e8df1ab..2da6a3b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -61,6 +61,9 @@
private final Handler mHandler;
private final TestSensorEnvironment mEnvironment;
+
+ // Wakelock for keeping the system running after terminate criterion is met.
+ // Useful for CtsVerifier test cases in which cpu can sleep if usb is not connected.
private final PowerManager.WakeLock mTestSensorEventListenerWakeLock;
/**
@@ -191,7 +194,8 @@
* It will overwrite the file if it already exists, the file is created in a relative directory
* named 'events' under the sensor test directory (part of external storage).
*/
- public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs)
+ public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs,
+ long testStartTimeMs, long testStopTimeMs)
throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
@@ -200,7 +204,11 @@
builder.append("RequestedSamplingPeriod=")
.append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
builder.append("MaxReportLatency=")
- .append(mEnvironment.getMaxReportLatencyUs()).append("us");
+ .append(mEnvironment.getMaxReportLatencyUs()).append("us, ");
+ builder.append("StartedTimestamp=")
+ .append(testStartTimeMs).append("ms, ");
+ builder.append("StoppedTimestamp=")
+ .append(testStopTimeMs).append("ms");
synchronized (mCollectedEvents) {
int i = 0, j = 0;
while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
@@ -262,6 +270,9 @@
/**
* Wait for {@link #onFlushCompleted(Sensor)} to be called.
*
+ * A wake lock may be acquired at the return if operation is successful. Do
+ * {@link releaseWakeLock()} if the wakelock is not necessary.
+ *
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForFlushComplete(CountDownLatch latch,
@@ -286,6 +297,9 @@
/**
* Collect a specific number of {@link TestSensorEvent}s.
*
+ * A wake lock may be acquired at the return if operation is successful. Do
+ * {@link releaseWakeLock()} if the wakelock is not necessary.
+ *
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForEvents(CountDownLatch latch, int eventCount,
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
index 23580de..7c69649 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -151,6 +151,7 @@
}
mSensorManager.unregisterListener(mTestSensorEventListener, mEnvironment.getSensor());
mTestSensorEventListener.assertEventsReceivedInHandler();
+ mTestSensorEventListener.releaseWakeLock(); // clean up wakelock if it is acquired
mTestSensorEventListener = null;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index bc01064..5ef2d3c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -66,6 +66,8 @@
private final Executor mExecutor;
private final Handler mHandler;
private long mDeviceWakeUpTimeMs = -1;
+ private long mStartTimeMs = -1;
+ private long mStopTimeMs = -1;
/**
* An interface that defines an abstraction for operations to be performed by the
@@ -124,20 +126,21 @@
getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
+ mStartTimeMs = SystemClock.elapsedRealtime();
if (mEnvironment.isDeviceSuspendTest()) {
SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
- long startTimeMs = SystemClock.elapsedRealtime();
// Device should go into suspend here.
mExecutor.execute(mSensorManager, listener);
- long endTimeMs = SystemClock.elapsedRealtime();
+ mStopTimeMs = SystemClock.elapsedRealtime();
// Check if the device has gone into suspend during test execution.
mDeviceWakeUpTimeMs = suspendStateMonitor.getLastWakeUpTime();
suspendStateMonitor.cancel();
Assert.assertTrue("Device did not go into suspend during test execution",
- startTimeMs < mDeviceWakeUpTimeMs &&
- mDeviceWakeUpTimeMs < endTimeMs);
+ mStartTimeMs < mDeviceWakeUpTimeMs &&
+ mDeviceWakeUpTimeMs < mStopTimeMs);
} else {
mExecutor.execute(mSensorManager, listener);
+ mStopTimeMs = SystemClock.elapsedRealtime();
}
boolean failed = false;
@@ -147,8 +150,8 @@
failed |= evaluateResults(collectedEvents, verification, sb);
}
+ trySaveCollectedEvents(parent, listener);
if (failed) {
- trySaveCollectedEvents(parent, listener);
String msg = SensorCtsHelper
.formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
getStats().addValue(SensorStats.ERROR, msg);
@@ -213,7 +216,8 @@
}
try {
- listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs);
+ listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs,
+ mStartTimeMs, mStopTimeMs);
} catch (IOException e) {
Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
}
@@ -246,6 +250,9 @@
/**
* Creates an operation that will wait for a given amount of events to arrive.
*
+ * After the execution of this type of test operation, the wakelock passed in will be acquired.
+ * Make sure it is released at clean up.
+ *
* @param environment The test environment.
* @param eventCount The number of events to wait for.
*/
@@ -268,14 +275,17 @@
environment.toString(),
listener.getCollectedEvents().size() - initialNumEvents1 > 0);
}
+ // acknowledge waitForFlushComplete
+ listener.releaseWakeLock();
Log.i(TAG, "Collected sensor events size1=" +
listener.getCollectedEvents().size());
int initialNumEvents2 = listener.getCollectedEvents().size();
+
+ // allow device to go to sleep
if (wakeLock.isHeld()) {
wakeLock.release();
}
- listener.releaseWakeLock();
SuspendStateMonitor suspendMonitor = new SuspendStateMonitor();
long approxStartTimeMs = SystemClock.elapsedRealtime();
@@ -283,6 +293,7 @@
suspendMonitor.waitForWakeUp(15);
suspendMonitor.cancel();
+ // keep device awake for processing
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
@@ -315,10 +326,10 @@
Log.i(TAG, "Collected sensor events size3=" +
listener.getCollectedEvents().size());
} finally {
+ // make sure the device can run until the test activity take over.
if(!wakeLock.isHeld()) {
wakeLock.acquire();
}
- listener.releaseWakeLock();
sensorManager.unregisterListener();
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
index 1e82b78..670c065 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
@@ -18,6 +18,7 @@
import junit.framework.Assert;
+import android.os.Build;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.cts.helpers.SensorStats;
@@ -28,15 +29,23 @@
import java.util.concurrent.TimeUnit;
/**
- * A {@link ISensorVerification} which verifies if the collected sensor events have any obvious
+ * A {@link ISensorVerification} which verifies if the collected sensor events have any obvious
* problems, such as no sample, wrong sensor type, etc.
*/
public class EventBasicVerification extends AbstractSensorVerification {
public static final String PASSED_KEY = "event_basic_passed";
- private static final long ALLOWED_SENSOR_DELIVERING_DELAY_US =
+ // allowed time from registration to sensor start sampling
+ private static final long ALLOWED_SENSOR_START_DELAY_US =
TimeUnit.MILLISECONDS.toMicros(1000);
+ // allowed time for entire sensor system to send sample to test app
+ private static final long ALLOWED_SENSOR_EVENT_LATENCY_US =
+ TimeUnit.MILLISECONDS.toMicros(1000);
+
+ // mercy added for recently added test. remove this mercy factor for next letter release.
+ private final float NUM_EVENT_MERCY_FACTOR; // 0~1, 0 means most strict
+
private final long mExpectedMinNumEvent;
private final Object mSensor;
private long mNumEvent;
@@ -56,6 +65,12 @@
mNumEvent = 0;
mWrongSensorObserved = false;
+
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ NUM_EVENT_MERCY_FACTOR = 0;
+ } else {
+ NUM_EVENT_MERCY_FACTOR = 0.3f;
+ }
}
/**
@@ -69,25 +84,79 @@
TestSensorEnvironment environment,
long testDurationUs) {
- long minTestDurationUs;
- long batchUs = environment.getMaxReportLatencyUs();
+ // The calculation is still OK if sampleUs is not the actual sensor hardware
+ // sample period since the actual sample period by definition only goes smaller, which
+ // result in more samples.
long sampleUs = environment.getExpectedSamplingPeriodUs();
- if (batchUs > 0) {
- // test duration deduct allowed delivering latency and portion of time to deliver batch
- // (which will be 10% of the batching time)
- long effectiveTime = testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US - batchUs/10;
- // allow part of last batch to be partially delivered (>80%)
- minTestDurationUs = Math.max(
- effectiveTime/batchUs * batchUs - batchUs/5,
- environment.getExpectedSamplingPeriodUs());
+ long askedBatchUs = environment.getMaxReportLatencyUs();
+
+ long reservedFifoUs = sampleUs * environment.getSensor().getFifoReservedEventCount(); //>=0
+
+ // max() prevent loop-hole if HAL specify smaller max fifo than reserved fifo.
+ long maximumFifoUs = Math.max(
+ sampleUs * environment.getSensor().getFifoMaxEventCount(), reservedFifoUs); //>=0
+
+ long effectiveDurationUs = Math.max(testDurationUs -
+ Math.max(ALLOWED_SENSOR_START_DELAY_US, environment.getAllowedSensorStartDelay()) -
+ ALLOWED_SENSOR_EVENT_LATENCY_US, 0);
+
+ boolean isSingleSensorTest = !environment.isIntegrationTest();
+
+ long expectedMinUs;
+ if (isSingleSensorTest) {
+ // When the sensor under test is the only one active, max fifo size is assumed to be
+ // available.
+ long expectedBatchUs = Math.min(maximumFifoUs, askedBatchUs);
+ if (expectedBatchUs > 0) {
+ // This sensor should be running in batching mode.
+ expectedMinUs =
+ effectiveDurationUs / expectedBatchUs * expectedBatchUs
+ - expectedBatchUs / 5;
+ } else {
+ // streaming, allow actual rate to be as slow as 80% of the asked rate.
+ expectedMinUs = effectiveDurationUs * 4 / 5;
+ }
} else {
- minTestDurationUs =
- Math.max(testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US,
- environment.getExpectedSamplingPeriodUs());
- }
+ // More convoluted case. Batch size can vary from reserved fifo length to max fifo size.
+ long minBatchUs = Math.min(reservedFifoUs, askedBatchUs);
+ long maxBatchUs = Math.min(maximumFifoUs, askedBatchUs);
- long expectedMinNumEvent = minTestDurationUs / environment.getExpectedSamplingPeriodUs();
+ // The worst scenario happens when the sensor batch time being just above half of the
+ // test time, then the test can only receive one batch which halves the expected number
+ // of samples. The expected number of samples received have a lower bound like the
+ // figure below.
+ //
+ // expected samples
+ // ^
+ // | ______
+ // |\ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \ /
+ // | \/
+ // |
+ // |
+ // |
+ // |
+ // +------------+-----------+-------> actual batch size in time
+ // 0 1/2*testDuration testDuration
+ //
+ long worstBatchUs = effectiveDurationUs / 2 + 1;
+ if ((minBatchUs > worstBatchUs) == (maxBatchUs > worstBatchUs)) {
+ // same side
+ double ratio = Math.min(Math.abs(worstBatchUs - minBatchUs),
+ Math.abs(worstBatchUs - maxBatchUs)) / (double)worstBatchUs;
+ expectedMinUs = (long)((ratio + 1) / 2 * testDurationUs) * 4 / 5;
+ } else {
+ // the worst case is possible
+ expectedMinUs = worstBatchUs * 4 / 5;
+ }
+ }
+ long expectedMinNumEvent = expectedMinUs/sampleUs;
+
return new EventBasicVerification(expectedMinNumEvent, environment.getSensor());
}
@@ -103,7 +172,7 @@
stats.addValue(SensorStats.EVENT_COUNT_EXPECTED_KEY, mExpectedMinNumEvent);
stats.addValue(SensorStats.WRONG_SENSOR_KEY, mWrongSensorObserved);
- boolean enoughSample = mNumEvent >= mExpectedMinNumEvent;
+ boolean enoughSample = mNumEvent >= mExpectedMinNumEvent * ( 1 - NUM_EVENT_MERCY_FACTOR );
boolean noWrongSensor = !mWrongSensorObserved;
boolean success = enoughSample && noWrongSensor;
@@ -111,7 +180,8 @@
if (!success) {
Assert.fail(String.format("Failed due to (%s%s)",
- enoughSample?"":"insufficient events, ",
+ enoughSample?"":"insufficient events " + mNumEvent + "/" +
+ mExpectedMinNumEvent + ", ",
noWrongSensor?"":"wrong sensor observed, "));
}
}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
index 6f4ebdd..b33451b 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
-import android.media.CamcorderProfile;
import android.cts.util.MediaUtils;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
index a37d4c2..ca935c4 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaActivity.java
@@ -20,7 +20,6 @@
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.SurfaceTexture;
-import android.media.CamcorderProfile;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
@@ -34,7 +33,7 @@
import junit.framework.Assert;
public class NativeMediaActivity extends Activity implements OnSurfaceChangedListener {
- public static final String EXTRA_VIDEO_QUALITY = "videoQuality";
+ public static final String EXTRA_VIDEO_HEIGHT = "videoHeight";
// should be long enough. time-out can be treated as error
public static final long NATIVE_MEDIA_LIFECYCLE_TIMEOUT_MS = 10000;
static final String TAG = "NativeMedia";
@@ -51,8 +50,7 @@
private SurfaceTextureGLSurfaceView mGLView;
private volatile boolean mNativeCreated = false;
- /** 0 for default (480x360), other value can be CamcorderProfile.QUALITY_480P / 720P / 1080P */
- private int mVideoQuality = 0;
+ private int mVideoHeight = 360;
// native media status queued whenever there is a change in life.
private final BlockingQueue<Boolean> mNativeWaitQ = new LinkedBlockingQueue<Boolean>();
@@ -61,7 +59,7 @@
super.onCreate(icicle);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- mVideoQuality = getIntent().getIntExtra(EXTRA_VIDEO_QUALITY, mVideoQuality);
+ mVideoHeight = getIntent().getIntExtra(EXTRA_VIDEO_HEIGHT, mVideoHeight);
mGLView = new SurfaceTextureGLSurfaceView(this, this);
setContentView(mGLView);
}
@@ -159,14 +157,14 @@
private String getMediaString() {
int mediaIndex = 0; // default: 480x360
- switch(mVideoQuality) {
- case CamcorderProfile.QUALITY_1080P:
+ switch(mVideoHeight) {
+ case 1080:
mediaIndex = 3;
break;
- case CamcorderProfile.QUALITY_720P:
+ case 720:
mediaIndex = 2;
break;
- case CamcorderProfile.QUALITY_480P:
+ case 480:
mediaIndex = 1;
break;
}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
index 05145f5..40284a6 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NativeMediaTest.java
@@ -18,7 +18,6 @@
import android.app.Instrumentation;
import android.content.Intent;
import android.cts.util.MediaUtils;
-import android.media.CamcorderProfile;
import android.media.MediaFormat;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
@@ -40,37 +39,30 @@
}
public void test1080pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_1080P);
+ runPlayTest(1920, 1080);
}
public void test720pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_720P);
+ runPlayTest(1280, 720);
}
public void test480pPlay() throws InterruptedException {
- runPlayTest(CamcorderProfile.QUALITY_480P);
+ runPlayTest(720, 480);
}
public void testDefaultPlay() throws InterruptedException {
- runPlayTest(0);
+ runPlayTest(480, 360);
}
- private void runPlayTest(int quality) throws InterruptedException {
+ private void runPlayTest(int width, int height) throws InterruptedException {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
// Don't run the test if the codec isn't supported.
- if (!MediaUtils.checkDecoder(MIME_TYPE)) {
+ if (!MediaUtils.canDecode(format)) {
return; // skip
}
- // Don't run the test if the quality level isn't supported.
- if (quality != 0) {
- if (!isResolutionSupported(quality)) {
- Log.w(TAG, "Quality level " + quality + " not supported.");
- return;
- }
- }
Intent intent = new Intent();
- intent.putExtra(NativeMediaActivity.EXTRA_VIDEO_QUALITY,
- quality);
+ intent.putExtra(NativeMediaActivity.EXTRA_VIDEO_HEIGHT, height);
setActivityIntent(intent);
final NativeMediaActivity activity = getActivity();
final Instrumentation instrumentation = getInstrumentation();
@@ -98,17 +90,4 @@
Assert.assertNotNull(status); // null means time-out
Assert.assertEquals(expectAlive, status.booleanValue());
}
-
- private boolean isResolutionSupported(int quality) {
- Assert.assertEquals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
- if (!CamcorderProfile.hasProfile(quality)) {
- return false;
- }
- CamcorderProfile profile = CamcorderProfile.get(quality);
- if ((profile != null) && (profile.videoCodec == VIDEO_CODEC) &&
- (profile.audioCodec == AudioEncoder.AAC)) {
- return true;
- }
- return false;
- }
}
diff --git a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java b/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
index 5b93bee..a8dd8ac 100755
--- a/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
+++ b/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
@@ -215,7 +215,7 @@
if (deltaTxOtherPackets > 0 || deltaRxOtherPackets > 0) {
Log.i(LOG_TAG, "lingering traffic data: " + deltaTxOtherPackets + "/" + deltaRxOtherPackets);
// Make sure that not too many non-localhost packets are accounted for
- assertTrue("too many non-localhost packets on the sam UID", deltaTxOtherPackets + deltaTxOtherPackets < 20);
+ assertTrue("too many non-localhost packets on the same UID", deltaTxOtherPackets + deltaRxOtherPackets < 20);
}
assertTrue("uidtxp: " + uidTxPacketsBefore + " -> " + uidTxPacketsAfter + " delta=" + uidTxDeltaPackets +
diff --git a/tests/tests/os/src/android/os/cts/SecurityPatchTest.java b/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
index 7e85a33..5516a19 100644
--- a/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
+++ b/tests/tests/os/src/android/os/cts/SecurityPatchTest.java
@@ -32,7 +32,7 @@
private static final String SECURITY_PATCH_DATE_ERROR =
"ro.build.version.security_patch should be \"%d-%02d\" or later. Found \"%s\"";
private static final int SECURITY_PATCH_YEAR = 2016;
- private static final int SECURITY_PATCH_MONTH = 03;
+ private static final int SECURITY_PATCH_MONTH = 04;
private boolean mSkipTests = false;
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index d8d8dfa..3039f81 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
index c916122..3f21408 100644
--- a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
@@ -197,45 +197,6 @@
return true;
}
-jboolean android_security_cts_AudioFlinger_test_listAudioPatches(JNIEnv* env __unused,
- jobject thiz __unused)
-{
- sp<IAudioFlinger> af;
- sp<MyDeathClient> dr;
-
- if (!connectAudioFlinger(af, dr)) {
- return false;
- }
-
- unsigned int num_patches = TEST_ARRAY_SIZE;
- struct audio_patch *patches =
- (struct audio_patch *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_patch));
-
- memset(patches, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_patch));
-
- status_t status = af->listAudioPatches(&num_patches, patches);
-
- sleep(1);
-
- // Check that the memory content above the max allowed array size was not changed
- char *ptr = (char *)(patches + MAX_ARRAY_SIZE);
- for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
- if (ptr[i * sizeof(struct audio_patch)] != TEST_PATTERN) {
- free(patches);
- return false;
- }
- }
-
- free(patches);
-
- // Check that mediaserver did not crash
- if (dr->afIsDead()) {
- return false;
- }
-
- return true;
-}
-
jboolean android_security_cts_AudioFlinger_test_createEffect(JNIEnv* env __unused,
jobject thiz __unused)
{
@@ -290,8 +251,6 @@
(void *) android_security_cts_AudioFlinger_test_setMasterVolume },
{ "native_test_listAudioPorts", "()Z",
(void *) android_security_cts_AudioFlinger_test_listAudioPorts },
- { "native_test_listAudioPatches", "()Z",
- (void *) android_security_cts_AudioFlinger_test_listAudioPatches },
{ "native_test_createEffect", "()Z",
(void *) android_security_cts_AudioFlinger_test_createEffect },
};
diff --git a/tests/tests/security/res/raw/bug_26366256.midi b/tests/tests/security/res/raw/bug_26366256.midi
new file mode 100644
index 0000000..5114d92
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_26366256.midi
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3862_b_22954006.mp3 b/tests/tests/security/res/raw/cve_2015_3862_b_22954006.mp3
new file mode 100644
index 0000000..cc964e9
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3862_b_22954006.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3867.mp4 b/tests/tests/security/res/raw/cve_2015_3867.mp4
new file mode 100644
index 0000000..44f906a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3867.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3867_b_23213430.mp4 b/tests/tests/security/res/raw/cve_2015_3867_b_23213430.mp4
new file mode 100644
index 0000000..44f906a
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3867_b_23213430.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3869.ogg b/tests/tests/security/res/raw/cve_2015_3869.ogg
new file mode 100644
index 0000000..bc680f9
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3869.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3873_b_20718524.ogg b/tests/tests/security/res/raw/cve_2015_3873_b_20718524.ogg
new file mode 100644
index 0000000..9122852
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3873_b_20718524.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3873_b_21814993.mp4 b/tests/tests/security/res/raw/cve_2015_3873_b_21814993.mp4
new file mode 100644
index 0000000..7340dc5
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3873_b_21814993.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3873_b_23248776.mp3 b/tests/tests/security/res/raw/cve_2015_3873_b_23248776.mp3
new file mode 100644
index 0000000..2f683bc
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3873_b_23248776.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/drm_uaf.dm b/tests/tests/security/res/raw/drm_uaf.dm
new file mode 100644
index 0000000..50f42bc
--- /dev/null
+++ b/tests/tests/security/res/raw/drm_uaf.dm
Binary files differ
diff --git a/tests/tests/security/res/raw/midi_crash.midi b/tests/tests/security/res/raw/midi_crash.midi
new file mode 100644
index 0000000..1880229
--- /dev/null
+++ b/tests/tests/security/res/raw/midi_crash.midi
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
index 202bd65..3cf4a2a 100644
--- a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
+++ b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
@@ -49,14 +49,6 @@
}
/**
- * Checks that IAudioFlinger::listAudioPatches() does not cause a memory overflow when passed a
- * large number of ports.
- */
- public void test_listAudioPatches() throws Exception {
- assertTrue(native_test_listAudioPatches());
- }
-
- /**
* Checks that IAudioFlinger::createEffect() does not leak information on the server side.
*/
public void test_createEffect() throws Exception {
@@ -66,6 +58,5 @@
private static native boolean native_test_setMasterMute();
private static native boolean native_test_setMasterVolume();
private static native boolean native_test_listAudioPorts();
- private static native boolean native_test_listAudioPatches();
private static native boolean native_test_createEffect();
}
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
new file mode 100644
index 0000000..9dff6dd
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2015 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.security.cts;
+
+import android.content.res.AssetFileDescriptor;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.media.MediaPlayer;
+import android.os.ConditionVariable;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import com.android.cts.security.R;
+
+public class MediaServerCrashTest extends AndroidTestCase {
+ private static final String TAG = "MediaServerCrashTest";
+
+ private static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+
+ private String mFlFilePath;
+
+ private final MediaPlayer mMediaPlayer = new MediaPlayer();
+ private final ConditionVariable mOnPrepareCalled = new ConditionVariable();
+ private final ConditionVariable mOnCompletionCalled = new ConditionVariable();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mFlFilePath = new File(Environment.getExternalStorageDirectory(),
+ "temp.fl").getAbsolutePath();
+
+ mOnPrepareCalled.close();
+ mOnCompletionCalled.close();
+ mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ assertTrue(mp == mMediaPlayer);
+ assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ Log.w(TAG, "onError " + what);
+ return false;
+ }
+ });
+
+ mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ assertTrue(mp == mMediaPlayer);
+ mOnPrepareCalled.open();
+ }
+ });
+
+ mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ assertTrue(mp == mMediaPlayer);
+ mOnCompletionCalled.open();
+ }
+ });
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ File flFile = new File(mFlFilePath);
+ if (flFile.exists()) {
+ flFile.delete();
+ }
+ }
+
+ public void testInvalidMidiNullPointerAccess() throws Exception {
+ testIfMediaServerDied(R.raw.midi_crash);
+ }
+
+ private void testIfMediaServerDied(int res) throws Exception {
+ AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
+ mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ try {
+ mMediaPlayer.prepareAsync();
+ if (!mOnPrepareCalled.block(5000)) {
+ Log.w(TAG, "testIfMediaServerDied: Timed out waiting for prepare");
+ return;
+ }
+ mMediaPlayer.start();
+ if (!mOnCompletionCalled.block(5000)) {
+ Log.w(TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "playback failed", e);
+ } finally {
+ mMediaPlayer.release();
+ }
+ }
+
+ public void testDrmManagerClientReset() throws Exception {
+ checkIfMediaServerDiedForDrm(R.raw.drm_uaf);
+ }
+
+ private void checkIfMediaServerDiedForDrm(int res) throws Exception {
+ if (!convertDmToFl(res, mFlFilePath)) {
+ fail("Can not convert dm to fl");
+ }
+ Log.d(TAG, "intermediate fl file is " + mFlFilePath);
+
+ ParcelFileDescriptor flFd = null;
+ try {
+ flFd = ParcelFileDescriptor.open(new File(mFlFilePath),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ fail("Could not find file: " + mFlFilePath + e);
+ }
+
+ mMediaPlayer.setDataSource(flFd.getFileDescriptor(), 0, flFd.getStatSize());
+ flFd.close();
+ try {
+ mMediaPlayer.prepare();
+ } catch (Exception e) {
+ Log.d(TAG, "Prepare failed", e);
+ }
+
+ try {
+ mMediaPlayer.reset();
+ if (!mOnCompletionCalled.block(5000)) {
+ Log.w(TAG, "checkIfMediaServerDiedForDrm: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ fail("reset failed" + e);
+ } finally {
+ mMediaPlayer.release();
+ }
+ }
+
+ private boolean convertDmToFl(int res, String flFilePath) throws Exception {
+ AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
+ FileInputStream inputStream = afd.createInputStream();
+ int inputLength = (int)afd.getLength();
+ byte[] fileData = new byte[inputLength];
+ int readSize = inputStream.read(fileData, 0, inputLength);
+ assertEquals("can not pull in all data", readSize, inputLength);
+ inputStream.close();
+ afd.close();
+
+ FileOutputStream flStream = new FileOutputStream(new File(flFilePath));
+
+ DrmManagerClient drmClient = null;
+ try {
+ drmClient = new DrmManagerClient(mContext);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "DrmManagerClient instance could not be created, context is Illegal.");
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+ return false;
+ }
+
+ if (drmClient == null) {
+ Log.w(TAG, "Failed to create DrmManagerClient.");
+ return false;
+ }
+
+ int convertSessionId = -1;
+ try {
+ convertSessionId = drmClient.openConvertSession(MIMETYPE_DRM_MESSAGE);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Conversion of Mimetype: " + MIMETYPE_DRM_MESSAGE
+ + " is not supported.", e);
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not access Open DrmFramework.", e);
+ return false;
+ }
+
+ if (convertSessionId < 0) {
+ Log.w(TAG, "Failed to open session.");
+ return false;
+ }
+
+ DrmConvertedStatus convertedStatus = null;
+ try {
+ convertedStatus = drmClient.convertData(convertSessionId, fileData);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+ + convertSessionId, e);
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not convert data. Convertsession: " + convertSessionId, e);
+ return false;
+ }
+
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ Log.w(TAG, "Error in converting data. Convertsession: " + convertSessionId);
+ try {
+ drmClient.closeConvertSession(convertSessionId);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not close session. Convertsession: " +
+ convertSessionId, e);
+ }
+ return false;
+ }
+
+ flStream.write(convertedStatus.convertedData, 0, convertedStatus.convertedData.length);
+ flStream.close();
+
+ try {
+ convertedStatus = drmClient.closeConvertSession(convertSessionId);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not close convertsession. Convertsession: " +
+ convertSessionId, e);
+ return false;
+ }
+
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ Log.w(TAG, "Error in closing session. Convertsession: " + convertSessionId);
+ return false;
+ }
+
+ RandomAccessFile flRandomAccessFile = null;
+ try {
+ flRandomAccessFile = new RandomAccessFile(flFilePath, "rw");
+ flRandomAccessFile.seek(convertedStatus.offset);
+ flRandomAccessFile.write(convertedStatus.convertedData);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "File: " + flFilePath + " could not be found.", e);
+ return false;
+ } catch (IOException e) {
+ Log.w(TAG, "Could not access File: " + flFilePath + " .", e);
+ return false;
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Could not open file in mode: rw", e);
+ return false;
+ } catch (SecurityException e) {
+ Log.w(TAG, "Access to File: " + flFilePath +
+ " was denied denied by SecurityManager.", e);
+ return false;
+ } finally {
+ if (flRandomAccessFile != null) {
+ try {
+ flRandomAccessFile.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to close File:" + flFilePath + ".", e);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 069fa72..71ef064 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -77,6 +77,11 @@
}
private static final Set<String> WHITELISTED_PACKAGES = new HashSet<String>(Arrays.asList(
+ // APKS are installed before beigning test
+ "android.netsecpolicy.usescleartext.false.cts",
+ "android.netsecpolicy.usescleartext.unspecified.cts",
+ "android.netsecpolicy.usescleartext.true.cts",
+
// The accessibility APK required to be installed while running CTS
"android.accessibilityservice.delegate",
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 0f79860..f8dd20b 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -43,6 +43,8 @@
public class StagefrightTest extends InstrumentationTestCase {
static final String TAG = "StagefrightTest";
+ private final long TIMEOUT_NS = 10000000000L; // 10 seconds.
+
public StagefrightTest() {
}
@@ -94,6 +96,38 @@
doStagefrightTest(R.raw.cve_2015_6598);
}
+ public void testStagefright_bug_26366256() throws Exception {
+ doStagefrightTest(R.raw.bug_26366256);
+ }
+
+ public void testStagefright_cve_2015_3867() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3867);
+ }
+
+ public void testStagefright_cve_2015_3869() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3869);
+ }
+
+ public void testStagefright_cve_2015_3873_b_23248776() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3873_b_23248776);
+ }
+
+ public void testStagefright_cve_2015_3873_b_20718524() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3873_b_20718524);
+ }
+
+ public void testStagefright_cve_2015_3862_b_22954006() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3862_b_22954006);
+ }
+
+ public void testStagefright_cve_2015_3867_b_23213430() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3867_b_23213430);
+ }
+
+ public void testStagefright_cve_2015_3873_b_21814993() throws Exception {
+ doStagefrightTest(R.raw.cve_2015_3873_b_21814993);
+ }
+
private void doStagefrightTest(final int rid) throws Exception {
class MediaPlayerCrashListener
implements MediaPlayer.OnErrorListener,
@@ -124,7 +158,9 @@
public int waitForError() throws InterruptedException {
lock.lock();
- condition.await();
+ if (condition.awaitNanos(TIMEOUT_NS) <= 0) {
+ Log.d(TAG, "timed out on waiting for error");
+ }
lock.unlock();
return what;
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 35aae62..d874dbf 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -138,7 +138,9 @@
}
protected void tearDownConnectionService(PhoneAccountHandle accountHandle) throws Exception {
- assertNumConnections(this.connectionService, 0);
+ if (this.connectionService != null) {
+ assertNumConnections(this.connectionService, 0);
+ }
mTelecomManager.unregisterPhoneAccount(accountHandle);
CtsConnectionService.tearDown();
assertCtsConnectionServiceUnbound();
@@ -814,12 +816,12 @@
new Condition() {
@Override
public Object expected() {
- return true;
+ return false;
}
@Override
public Object actual() {
- return CtsConnectionService.isServiceUnbound();
+ return CtsConnectionService.isServiceBound();
}
},
WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index d8d5773..2364986 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -16,7 +16,7 @@
package android.telecom.cts;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.content.Intent;
import android.telecom.Conference;
@@ -52,11 +52,13 @@
private static ConnectionService sConnectionService;
// This is the connection service registered with Telecom
private static ConnectionService sTelecomConnectionService;
- private static boolean mIsServiceUnbound;
+ private static boolean mIsServiceBound = false;
public CtsConnectionService() throws Exception {
super();
sTelecomConnectionService = this;
+ // Cant override the onBind method for ConnectionService, so reset it here.
+ mIsServiceBound = true;
}
// ConnectionService used by default as a fallback if no connection service is specified
@@ -77,13 +79,12 @@
throw new Exception("Mock ConnectionService exists. Failed to call tearDown().");
}
sConnectionService = connectionService;
- // Cant override the onBind method for ConnectionService, so reset it here.
- mIsServiceUnbound = false;
}
}
public static void tearDown() {
synchronized(sLock) {
+ sTelecomConnectionService = null;
sConnectionService = null;
}
}
@@ -188,13 +189,17 @@
@Override
public boolean onUnbind(Intent intent) {
- Log.i(LOG_TAG, "Service unbounded");
- assertFalse(mIsServiceUnbound);
- mIsServiceUnbound = true;
+ Log.i(LOG_TAG, "Service has been unbound");
+ assertTrue(mIsServiceBound);
+ mIsServiceBound = false;
return super.onUnbind(intent);
}
- public static boolean isServiceUnbound() {
- return mIsServiceUnbound;
+ public static boolean isServiceBound() {
+ return mIsServiceBound;
+ }
+
+ public static boolean isServiceRegisteredToTelecom() {
+ return sTelecomConnectionService != null;
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
new file mode 100644
index 0000000..7f5e7ce
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 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.telecom.cts;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.telecom.Connection;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+
+import java.util.Collection;
+
+import static android.telecom.cts.TestUtils.COMPONENT;
+import static android.telecom.cts.TestUtils.PACKAGE;
+
+/**
+ * Tests valid/invalid incoming calls that are received from the ConnectionService
+ * and registered through TelecomManager
+ */
+public class IncomingCallTest extends BaseTelecomTestWithMockServices {
+
+ private static final PhoneAccountHandle TEST_INVALID_HANDLE = new PhoneAccountHandle(
+ new ComponentName(PACKAGE, COMPONENT), "WRONG_ID");
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getInstrumentation().getContext();
+ }
+
+ public void testAddNewIncomingCall_CorrectPhoneAccountHandle() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
+ final Connection connection3 = verifyConnectionForIncomingCall();
+ Collection<Connection> connections = CtsConnectionService.getAllConnectionsFromTelecom();
+ assertEquals(1, connections.size());
+ assertTrue(connections.contains(connection3));
+ }
+
+ /**
+ * Tests to be sure that new incoming calls can only be added using a valid PhoneAccountHandle
+ * (b/26864502). If a PhoneAccount has not been registered for the PhoneAccountHandle, then
+ * a SecurityException will be thrown.
+ */
+ public void testAddNewIncomingCall_IncorrectPhoneAccountHandle() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, createTestNumber());
+ try {
+ mTelecomManager.addNewIncomingCall(TEST_INVALID_HANDLE, extras);
+ fail();
+ } catch (SecurityException e) {
+ // This should create a security exception!
+ }
+
+ assertFalse(CtsConnectionService.isServiceRegisteredToTelecom());
+ }
+
+ /**
+ * Tests to be sure that new incoming calls can only be added if a PhoneAccount is enabled
+ * (b/26864502). If a PhoneAccount is not enabled for the PhoneAccountHandle, then
+ * a SecurityException will be thrown.
+ */
+ public void testAddNewIncomingCall_PhoneAccountNotEnabled() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ // Do not enable PhoneAccount
+ setupConnectionService(null, FLAG_REGISTER);
+ assertFalse(mTelecomManager.getPhoneAccount(TEST_PHONE_ACCOUNT_HANDLE).isEnabled());
+ try {
+ addAndVerifyNewIncomingCall(createTestNumber(), null);
+ fail();
+ } catch (SecurityException e) {
+ // This should create a security exception!
+ }
+
+ assertFalse(CtsConnectionService.isServiceRegisteredToTelecom());
+ }
+}
diff --git a/tests/tests/telephony/AndroidManifest.xml b/tests/tests/telephony/AndroidManifest.xml
index a87a54b..15b19b7 100644
--- a/tests/tests/telephony/AndroidManifest.xml
+++ b/tests/tests/telephony/AndroidManifest.xml
@@ -34,6 +34,56 @@
<provider android:name="android.telephony.cts.MmsPduProvider"
android:authorities="telephonyctstest"
android:grantUriPermissions="true" />
+
+ <!-- SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ classes don't do anything, they are needed to make this a valid candidate for default SMS
+ app. -->
+ <!-- BroadcastReceiver that listens for incoming SMS messages -->
+ <receiver android:name=".SmsReceiver"
+ android:permission="android.permission.BROADCAST_SMS">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.SMS_DELIVER" />
+ </intent-filter>
+ </receiver>
+
+ <!-- BroadcastReceiver that listens for incoming MMS messages -->
+ <receiver android:name=".MmsReceiver"
+ android:permission="android.permission.BROADCAST_WAP_PUSH">
+ <intent-filter>
+ <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+ <data android:mimeType="application/vnd.wap.mms-message" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Activity that allows the user to send new SMS/MMS messages -->
+ <activity android:name=".ComposeSmsActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.SEND" />
+ <action android:name="android.intent.action.SENDTO" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+ </activity>
+
+ <!-- Service that delivers messages from the phone "quick response" -->
+ <service android:name=".HeadlessSmsSendService"
+ android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="sms" />
+ <data android:scheme="smsto" />
+ <data android:scheme="mms" />
+ <data android:scheme="mmsto" />
+ </intent-filter>
+ </service>
+
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.java b/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.java
new file mode 100644
index 0000000..df1f0a9
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/ComposeSmsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.telephony.cts;
+
+import android.app.Activity;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class ComposeSmsActivity extends Activity {
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.java b/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.java
new file mode 100644
index 0000000..f3fadb31
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/HeadlessSmsSendService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 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.telephony.cts;
+
+import android.annotation.Nullable;
+import android.app.IntentService;
+import android.content.Intent;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class HeadlessSmsSendService extends IntentService {
+ /**
+ * Creates an IntentService. Invoked by your subclass's constructor.
+ *
+ * @param name Used to name the worker thread, important only for debugging.
+ */
+ public HeadlessSmsSendService(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void onHandleIntent(@Nullable Intent intent) {
+
+ }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.java b/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.java
new file mode 100644
index 0000000..d7d4b86
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 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.telephony.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * SmsReceiver, MmsReceiver, ComposeSmsActivity, HeadlessSmsSendService together make
+ * this a valid SmsApplication (that can be set as the default SMS app). Although some of these
+ * classes don't do anything, they are needed to make this a valid candidate for default SMS
+ * app. -->
+ */
+public class MmsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index 6b72b82..db7a974 100755
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -25,7 +25,7 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.SystemClock;
-import android.telephony.SmsManager;
+import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
@@ -57,6 +57,7 @@
private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION";
private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION";
private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+ public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP";
// List of network operators that don't support SMS delivery report
private static final List<String> NO_DELIVERY_REPORTS =
@@ -190,6 +191,8 @@
private SmsBroadcastReceiver mSendReceiver;
private SmsBroadcastReceiver mDeliveryReceiver;
private SmsBroadcastReceiver mDataSmsReceiver;
+ private SmsBroadcastReceiver mSmsDeliverReceiver;
+ private SmsBroadcastReceiver mSmsReceivedReceiver;
private PendingIntent mSentIntent;
private PendingIntent mDeliveredIntent;
private Intent mSendIntent;
@@ -254,7 +257,7 @@
return longText.equals(actualMessage);
}
- public void testSendMessages() throws InterruptedException {
+ public void testSendAndReceiveMessages() throws InterruptedException {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
@@ -267,16 +270,23 @@
IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION);
IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION);
IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION);
+ IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION);
+ IntentFilter smsReceivedIntentFilter =
+ new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
dataSmsReceivedIntentFilter.addDataScheme("sms");
dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989");
mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION);
mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION);
mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION);
+ mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION);
+ mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
getContext().registerReceiver(mSendReceiver, sendIntentFilter);
getContext().registerReceiver(mDeliveryReceiver, deliveryIntentFilter);
getContext().registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter);
+ getContext().registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter);
+ getContext().registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter);
// send single text sms
init();
@@ -285,6 +295,12 @@
if (mDeliveryReportSupported) {
assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
}
+ // non-default app should receive only SMS_RECEIVED_ACTION
+ assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
+
+ // due to permission restrictions, currently there is no way to make this test app the
+ // default SMS app
if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// TODO: temp workaround, OCTET encoding for EMS not properly supported
@@ -326,6 +342,9 @@
if (mDeliveryReportSupported) {
assertTrue(mDeliveryReceiver.waitForCalls(numParts, TIME_OUT));
}
+ // non-default app should receive only SMS_RECEIVED_ACTION
+ assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
} else {
// This GSM network doesn't support Multipart SMS message.
// Skip the test.
@@ -336,6 +355,8 @@
mSendReceiver.reset();
mDeliveryReceiver.reset();
mDataSmsReceiver.reset();
+ mSmsDeliverReceiver.reset();
+ mSmsReceivedReceiver.reset();
mReceivedDataSms = false;
mSentIntent = PendingIntent.getBroadcast(getContext(), 0, mSendIntent,
PendingIntent.FLAG_ONE_SHOT);
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java b/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java
new file mode 100644
index 0000000..4fdadbb
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.telephony.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Telephony;
+
+public class SmsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && intent.getAction().equals(Telephony.Sms.Intents.SMS_DELIVER_ACTION)) {
+ context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+ }
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index 3962401..01c10e0 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
@Option(name="cts-install-path", description="the path to the cts installation to use")
private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
- public static final String CTS_BUILD_VERSION = "6.0_r4";
+ public static final String CTS_BUILD_VERSION = "6.0_r5";
public static final String CTS_PACKAGE = "com.android.cts.tradefed.testtype";
/**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/HostPreconditionPreparer.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/HostPreconditionPreparer.java
index 3db7cc9..2b85660 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/HostPreconditionPreparer.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/HostPreconditionPreparer.java
@@ -73,6 +73,10 @@
description = "Whether to skip verifying/downloading media files")
protected boolean mSkipMediaDownload = false;
+ @Option(name = "skip-wifi-check",
+ description = "Whether to skip verification of network connection")
+ protected boolean mSkipWifiCheck = false;
+
@Option(name = "local-media-path",
description = "Absolute path of the media files directory on the host, containing" +
"'bbb_short' and 'bbb_full' directories")
@@ -475,17 +479,20 @@
*/
protected void runWifiPrecondition(ITestDevice device)
throws TargetSetupError, DeviceNotAvailableException {
-
+ if (mSkipWifiCheck) {
+ return; // skip this precondition
+ }
if (mWifiSsid == null) {
// no connection to create, check for existing connectivity
if (!device.checkConnectivity()) {
- throw new TargetSetupError("Device has no network connection, no ssid provided");
+ printWarning("Device has no network connection, option --wifi-ssid was not " +
+ "provided. Some CTS tests require an active network connection to pass");
}
} else {
// network provided in options, attempt to create new connection if needed
if (!device.connectToWifiNetworkIfNeeded(mWifiSsid, mWifiPsk)) {
- throw new TargetSetupError("Unable to establish network connection," +
- "some CTS packages require an active network connection");
+ printWarning("Unable to establish network connection, some CTS tests require " +
+ "an active network connection to pass");
}
}
}