diff options
83 files changed, 1079 insertions, 5546 deletions
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py index 78d8b42ba01..a76c7d4c77a 100644 --- a/apps/CameraITS/pymodules/its/objects.py +++ b/apps/CameraITS/pymodules/its/objects.py @@ -12,16 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import os.path -import sys -import re -import json -import tempfile -import time -import unittest -import subprocess import math +import unittest + def int_to_rational(i): """Function to convert Python integers to Camera2 rationals. @@ -322,6 +315,23 @@ def get_largest_yuv_format(props, match_ar=None): return fmt +def get_largest_jpeg_format(props, match_ar=None): + """Return a capture request and format spec for the largest jpeg size. + + Args: + props: the object returned from its.device.get_camera_properties(). + match_ar: aspect ratio to match + + Returns: + fmt: an output format specification, for the largest possible jpeg + format for this device. + """ + size = get_available_output_sizes("jpeg", props, match_ar_size=match_ar)[0] + fmt = {"format": "jpeg", "width": size[0], "height": size[1]} + + return fmt + + def get_max_digital_zoom(props): """Returns the maximum amount of zooming possible by the camera device. diff --git a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py index a46d54c8dac..564e3e75721 100644 --- a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py +++ b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py @@ -84,7 +84,7 @@ def aspect_ratio_scale_factors(ref_ar_string, props): for ar_string in AR_CHECKED: match_ar = [float(x) for x in ar_string.split(":")] try: - f = its.objects.get_largest_yuv_format(props, match_ar=match_ar) + f = its.objects.get_largest_jpeg_format(props, match_ar=match_ar) if f["height"] > height_max: height_max = f["height"] if f["width"] > width_max: @@ -113,8 +113,8 @@ def aspect_ratio_scale_factors(ref_ar_string, props): return ar_scaling -def find_yuv_fov_reference(cam, req, props): - """Determine the circle coverage of the image in YUV reference image. +def find_jpeg_fov_reference(cam, req, props): + """Determine the circle coverage of the image in JPEG reference image. Args: cam: camera object @@ -131,7 +131,7 @@ def find_yuv_fov_reference(cam, req, props): for ar in AR_CHECKED: match_ar = [float(x) for x in ar.split(":")] try: - f = its.objects.get_largest_yuv_format(props, match_ar=match_ar) + f = its.objects.get_largest_jpeg_format(props, match_ar=match_ar) fmt_dict[f["height"]*f["width"]] = {"fmt": f, "ar": ar} except IndexError: continue @@ -143,16 +143,18 @@ def find_yuv_fov_reference(cam, req, props): cap = cam.do_capture(req, fmt_dict[ar_max_pixels]["fmt"]) w = cap["width"] h = cap["height"] + fmt = cap["format"] + img = its.image.convert_capture_to_rgb_image(cap, props=props) - print "Captured %s %dx%d" % ("yuv", w, h) - img_name = "%s_%s_w%d_h%d.png" % (NAME, "yuv", w, h) + print "Captured %s %dx%d" % (fmt, w, h) + img_name = "%s_%s_w%d_h%d.png" % (NAME, fmt, w, h) _, _, circle_size = measure_aspect_ratio(img, False, img_name, True) fov_percent = calc_circle_image_ratio(circle_size[1], circle_size[0], w, h) ref_fov["fmt"] = fmt_dict[ar_max_pixels]["ar"] ref_fov["percent"] = fov_percent ref_fov["w"] = w ref_fov["h"] = h - print "Using YUV reference:", ref_fov + print "Using JPEG reference:", ref_fov return ref_fov @@ -235,7 +237,7 @@ def main(): # If raw capture is available, use it as ground truth. if raw_avlb: # Capture full-frame raw. Use its aspect ratio and circle center - # location as ground truth for the other jepg or yuv images. + # location as ground truth for the other jpeg or yuv images. print "Creating references for fov_coverage from RAW" out_surface = {"format": "raw"} cap_raw = cam.do_capture(req, out_surface) @@ -309,9 +311,9 @@ def main(): ref_fov["h"] = h_raw print "Using RAW reference:", ref_fov else: - ref_fov = find_yuv_fov_reference(cam, req, props) + ref_fov = find_jpeg_fov_reference(cam, req, props) else: - ref_fov = find_yuv_fov_reference(cam, req, props) + ref_fov = find_jpeg_fov_reference(cam, req, props) # Determine scaling factors for AR calculations ar_scaling = aspect_ratio_scale_factors(ref_fov["fmt"], props) diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml index 9910810f79b..4ded3666279 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="9.0_r10"> + android:versionName="9.0_r11"> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28"/> @@ -1965,7 +1965,7 @@ </intent-filter> <meta-data android:name="test_category" android:value="@string/test_category_notifications" /> <meta-data android:name="test_excluded_features" - android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" /> + android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" /> </activity> <activity android:name=".notifications.AttentionManagementVerifierActivity" diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags index 1bf1a0b6296..2be121153c9 100644 --- a/apps/CtsVerifier/proguard.flags +++ b/apps/CtsVerifier/proguard.flags @@ -20,6 +20,9 @@ -keepclasseswithmembers class * extends com.android.cts.verifier.location.LocationModeTestActivity +-keepclasseswithmembers class * extends com.android.cts.verifier.audio.HifiUltrasoundSpeakerTestActivity +-keepclasseswithmembers class * extends com.android.cts.verifier.audio.HifiUltrasoundTestActivity + # keep mockito methods -keep class org.mockito.** { *; } -keep interface org.mockito.** { *; } diff --git a/apps/CtsVerifier/res/layout/snsr_next_button.xml b/apps/CtsVerifier/res/layout/snsr_next_button.xml index 377b236eb37..cd5a970c969 100644 --- a/apps/CtsVerifier/res/layout/snsr_next_button.xml +++ b/apps/CtsVerifier/res/layout/snsr_next_button.xml @@ -24,7 +24,8 @@ android:id="@+id/retry_button" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/retry_button_text" /> + android:text="@string/retry_button_text" + android:visibility="gone" /> <Button android:id="@+id/pass_button" diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml index 6d827ebc00d..f0f0b7e4429 100755 --- a/apps/CtsVerifier/res/values/strings.xml +++ b/apps/CtsVerifier/res/values/strings.xml @@ -444,10 +444,7 @@ <string name="ble_scan_stop">Stop scan</string> <!-- BLE connection priority test strings --> - <string name="ble_client_connection_priority">Testing priority: </string> - <string name="ble_connection_priority_balanced">BALANCED</string> - <string name="ble_connection_priority_high">HIGH</string> - <string name="ble_connection_priority_low">LOW</string> + <string name="ble_client_connection_priority">Testing connection priority switching </string> <string name="ble_server_connection_priority_result_passed">All test passed</string> <string name="ble_server_connection_priority_result_failed">Test failed.</string> <string name="ble_server_connection_priority_result_intervals"> @@ -470,9 +467,7 @@ <string name="ble_write_authenticated_characteristic_name">Bluetooth LE Write Encrypted Characteristic</string> <string name="ble_read_authenticated_descriptor_name">Bluetooth LE Read Encrypted Descriptor</string> <string name="ble_write_authenticated_descriptor_name">Bluetooth LE Write Encrypted Descriptor</string> - <string name="ble_connection_priority_client_high">Bluetooth LE Send With CONNECTION_PRIORITY_HIGH</string> - <string name="ble_connection_priority_client_low">Bluetooth LE Send With CONNECTION_PRIORITY_LOW_POWER</string> - <string name="ble_connection_priority_client_balanced">Bluetooth LE Send With CONNECTION_PRIORITY_BALANCED</string> + <string name="ble_connection_priority_client_description">Client Switching Connection Priority</string> <string name="ble_indicate_characteristic_name">Bluetooth LE Indicate Characteristic</string> <string name="ble_encrypted_client_name">03 Bluetooth LE Encrypted Client Test</string> <string name="ble_encrypted_client_info">Bluetooth LE Encrypted Client read/write on characteristic and descriptor need encrypted.</string> diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml index 9c6de77742f..dd182365272 100644 --- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml +++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml @@ -3,4 +3,4 @@ linePaint.strokeWidth="3dp" linePaint.color="#AA0000" vertexPaint.color="#770000" - fillPaint.color="#00000000" /> + fillPaint.color="#770000" /> diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml index 8fb236e0bb0..0f27503babc 100644 --- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml +++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml @@ -3,4 +3,4 @@ linePaint.strokeWidth="2dp" linePaint.color="#777777" vertexPaint.color="777777" - fillPaint.color="#00000000" /> + fillPaint.color="#770000" /> diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml index 9a6c29a541e..011f20bf3b7 100644 --- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml +++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml @@ -3,4 +3,4 @@ linePaint.strokeWidth="2dp" linePaint.color="#007700" vertexPaint.color="#007700" - fillPaint.color="#00000000" /> + fillPaint.color="#880000" /> diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml index 3f9ffc2c712..ce09dfb0fd3 100644 --- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml +++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <config - linePaint.strokeWidth="1dp" - linePaint.color="#AAAAAA" - vertexPaint.color="#777777" - fillPaint.color="#00000000" /> + linePaint.strokeWidth="3dp" + linePaint.color="#00AA00" + vertexPaint.color="#007700" + fillPaint.color="#00ff00" + pointLabelFormatter.textPaint.color="#FFFFFF"/> diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java index 1629e1b0972..29136a51a1c 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java @@ -59,14 +59,14 @@ class ReportExporter extends AsyncTask<Void, Void, String> { private static final String SUITE_PLAN = "verifier"; private static final String SUITE_BUILD = "0"; - private static final long START_MS = System.currentTimeMillis(); - private static final long END_MS = START_MS; - private static final String REPORT_DIRECTORY = "verifierReports"; private static final String ZIP_EXTENSION = ".zip"; protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName()); + private final long START_MS = System.currentTimeMillis(); + private final long END_MS = START_MS; + private final Context mContext; private final TestListAdapter mAdapter; diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java index 1a9ffaca6ac..87618b17399 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java @@ -37,9 +37,12 @@ import android.widget.PopupWindow; import android.widget.TextView; import java.util.Arrays; +import com.androidplot.xy.PointLabelFormatter; +import com.androidplot.xy.LineAndPointFormatter; import com.androidplot.xy.SimpleXYSeries; +import com.androidplot.xy.XYPlot; import com.androidplot.xy.XYSeries; -import com.androidplot.xy.*; +import com.androidplot.xy.XYStepMode; import com.android.compatibility.common.util.CddTest; @@ -279,7 +282,7 @@ public class HifiUltrasoundSpeakerTestActivity extends PassFailButtons.Activity LineAndPointFormatter seriesFormat = new LineAndPointFormatter(); seriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_trials); - seriesFormat.setPointLabelFormatter(null); + seriesFormat.setPointLabelFormatter(new PointLabelFormatter()); plot.addSeries(series, seriesFormat); } @@ -296,7 +299,7 @@ public class HifiUltrasoundSpeakerTestActivity extends PassFailButtons.Activity LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter(); noiseSeriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_noise); - noiseSeriesFormat.setPointLabelFormatter(null); + noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter()); plot.addSeries(noiseSeries, noiseSeriesFormat); double[] dB = wavAnalyzerTask.getDB(); @@ -312,7 +315,7 @@ public class HifiUltrasoundSpeakerTestActivity extends PassFailButtons.Activity LineAndPointFormatter seriesFormat = new LineAndPointFormatter(); seriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_median); - seriesFormat.setPointLabelFormatter(null); + seriesFormat.setPointLabelFormatter(new PointLabelFormatter()); plot.addSeries(series, seriesFormat); Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ}; @@ -322,7 +325,7 @@ public class HifiUltrasoundSpeakerTestActivity extends PassFailButtons.Activity LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter(); passSeriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_pass); - passSeriesFormat.setPointLabelFormatter(null); + passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter()); plot.addSeries(passSeries, passSeriesFormat); } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java index 0276e60aaff..9aebbc4b2d6 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java @@ -37,9 +37,12 @@ import android.widget.PopupWindow; import android.widget.TextView; import java.util.Arrays; +import com.androidplot.xy.PointLabelFormatter; +import com.androidplot.xy.LineAndPointFormatter; import com.androidplot.xy.SimpleXYSeries; +import com.androidplot.xy.XYPlot; import com.androidplot.xy.XYSeries; -import com.androidplot.xy.*; +import com.androidplot.xy.XYStepMode; public class HifiUltrasoundTestActivity extends PassFailButtons.Activity { @@ -236,9 +239,9 @@ public class HifiUltrasoundTestActivity extends PassFailButtons.Activity { Arrays.asList(powerWrap), ""); LineAndPointFormatter seriesFormat = new LineAndPointFormatter(); + seriesFormat.setPointLabelFormatter(new PointLabelFormatter()); seriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_trials); - seriesFormat.setPointLabelFormatter(null); plot.addSeries(series, seriesFormat); } @@ -253,9 +256,9 @@ public class HifiUltrasoundTestActivity extends PassFailButtons.Activity { Arrays.asList(noiseDBWrap), "background noise"); LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter(); + noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter()); noiseSeriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_noise); - noiseSeriesFormat.setPointLabelFormatter(null); plot.addSeries(noiseSeries, noiseSeriesFormat); double[] dB = wavAnalyzerTask.getDB(); @@ -269,9 +272,9 @@ public class HifiUltrasoundTestActivity extends PassFailButtons.Activity { Arrays.asList(dBWrap), "median"); LineAndPointFormatter seriesFormat = new LineAndPointFormatter(); + seriesFormat.setPointLabelFormatter(new PointLabelFormatter()); seriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_median); - seriesFormat.setPointLabelFormatter(null); plot.addSeries(series, seriesFormat); Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ}; @@ -279,9 +282,9 @@ public class HifiUltrasoundTestActivity extends PassFailButtons.Activity { XYSeries passSeries = new SimpleXYSeries( Arrays.asList(passX), Arrays.asList(passY), "passing"); LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter(); + passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter()); passSeriesFormat.configure(getApplicationContext(), R.xml.ultrasound_line_formatter_pass); - passSeriesFormat.setPointLabelFormatter(null); plot.addSeries(passSeries, passSeriesFormat); } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java index 47ea81fc241..9119aae6888 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java @@ -40,17 +40,12 @@ import java.util.List; public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Activity {
private TestAdapter mTestAdapter;
- private int mPassed = 0;
+ private boolean mPassed = false;
private Dialog mDialog;
- private static final int BLE_CONNECTION_HIGH = 0;
- private static final int BLE_CONNECTION_BALANCED = 1;
- private static final int BLE_CONNECTION_LOW = 2;
+ private static final int BLE_CONNECTION_UPDATE = 0;
- private static final int PASSED_HIGH = 0x1;
- private static final int PASSED_BALANCED = 0x2;
- private static final int PASSED_LOW = 0x4;
- private static final int ALL_PASSED = 0x7;
+ private static final int ALL_PASSED = 0x1;
private boolean mSecure;
@@ -80,9 +75,7 @@ public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Act IntentFilter filter = new IntentFilter();
filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED);
filter.addAction(BleConnectionPriorityClientService.ACTION_CONNECTION_SERVICES_DISCOVERED);
- filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH);
- filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);
- filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);
+ filter.addAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH);
filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE);
filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE);
filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT);
@@ -140,9 +133,7 @@ public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Act private List<Integer> setupTestList() {
ArrayList<Integer> testList = new ArrayList<Integer>();
- testList.add(R.string.ble_connection_priority_client_high);
- testList.add(R.string.ble_connection_priority_client_balanced);
- testList.add(R.string.ble_connection_priority_client_low);
+ testList.add(R.string.ble_connection_priority_client_description);
return testList;
}
@@ -157,44 +148,24 @@ public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Act private void executeNextTestImpl() {
switch (mCurrentTest) {
case -1: {
- mCurrentTest = BLE_CONNECTION_HIGH;
+ mCurrentTest = BLE_CONNECTION_UPDATE;
Intent intent = new Intent(this, BleConnectionPriorityClientService.class);
- intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_HIGH);
+ intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_START);
startService(intent);
- String msg = getString(R.string.ble_client_connection_priority)
- + getString(R.string.ble_connection_priority_high);
+ String msg = getString(R.string.ble_client_connection_priority);
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
break;
- case BLE_CONNECTION_BALANCED: {
- mCurrentTest = BLE_CONNECTION_LOW;
- Intent intent = new Intent(this, BleConnectionPriorityClientService.class);
- intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_LOW_POWER);
- startService(intent);
- String msg = getString(R.string.ble_client_connection_priority)
- + getString(R.string.ble_connection_priority_low);
- Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
- }
- break;
- case BLE_CONNECTION_HIGH: {
- mCurrentTest = BLE_CONNECTION_BALANCED;
- Intent intent = new Intent(this, BleConnectionPriorityClientService.class);
- intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_BALANCED);
- startService(intent);
- String msg = getString(R.string.ble_client_connection_priority)
- + getString(R.string.ble_connection_priority_balanced);
- Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
- }
- break;
- case BLE_CONNECTION_LOW:
+ case BLE_CONNECTION_UPDATE: {
// all test done
closeDialog();
- if (mPassed == ALL_PASSED) {
+ if (mPassed == true) {
Intent intent = new Intent(this, BleConnectionPriorityClientService.class);
intent.setAction(BleConnectionPriorityClientService.ACTION_DISCONNECT);
startService(intent);
}
break;
+ }
default:
// something went wrong
closeDialog();
@@ -227,21 +198,11 @@ public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Act showProgressDialog();
executeNextTest(3000);
break;
- case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH:
- mTestAdapter.setTestPass(BLE_CONNECTION_HIGH);
- mPassed |= PASSED_HIGH;
+ case BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH:
+ mTestAdapter.setTestPass(BLE_CONNECTION_UPDATE);
+ mPassed = true;
executeNextTest(1000);
break;
- case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED:
- mTestAdapter.setTestPass(BLE_CONNECTION_BALANCED);
- mPassed |= PASSED_BALANCED;
- executeNextTest(1000);
- break;
- case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER:
- mTestAdapter.setTestPass(BLE_CONNECTION_LOW);
- mPassed |= PASSED_LOW;
- executeNextTest(100);
- break;
case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE:
showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
break;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java index 38d37bd6f21..1df40f55528 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java @@ -62,19 +62,11 @@ public class BleConnectionPriorityClientService extends Service { public static final String ACTION_BLUETOOTH_MISMATCH_INSECURE =
"com.android.cts.verifier.bluetooth.action.ACTION_BLUETOOTH_MISMATCH_INSECURE";
- public static final String ACTION_CONNECTION_PRIORITY_BALANCED =
- "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_BALANCED";
- public static final String ACTION_CONNECTION_PRIORITY_HIGH =
- "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_HIGH";
- public static final String ACTION_CONNECTION_PRIORITY_LOW_POWER =
+ public static final String ACTION_CONNECTION_PRIORITY_START =
"com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_LOW_POWER";
- public static final String ACTION_FINISH_CONNECTION_PRIORITY_BALANCED =
- "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_BALANCED";
- public static final String ACTION_FINISH_CONNECTION_PRIORITY_HIGH =
- "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_HIGH";
- public static final String ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER =
- "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_LOW_POWER";
+ public static final String ACTION_CONNECTION_PRIORITY_FINISH =
+ "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_FINISH";
public static final String ACTION_CLIENT_CONNECT_SECURE =
"com.android.cts.verifier.bluetooth.action.CLIENT_CONNECT_SECURE";
@@ -84,20 +76,7 @@ public class BleConnectionPriorityClientService extends Service { public static final String ACTION_FINISH_DISCONNECT =
"com.android.cts.verifier.bluetooth.action.FINISH_DISCONNECT";
- public static final long DEFAULT_INTERVAL = 100L;
- public static final long DEFAULT_PERIOD = 10000L;
-
- // this string will be used at writing test and connection priority test.
- private static final String WRITE_VALUE = "TEST";
-
- private static final UUID SERVICE_UUID =
- UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
- private static final UUID CHARACTERISTIC_UUID =
- UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
- private static final UUID START_CHARACTERISTIC_UUID =
- UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
- private static final UUID STOP_CHARACTERISTIC_UUID =
- UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
+ public static final int NOT_UNDER_TEST = -1;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
@@ -108,13 +87,12 @@ public class BleConnectionPriorityClientService extends Service { private Context mContext;
private String mAction;
- private long mInterval;
- private long mPeriod;
- private Date mStartDate;
- private int mWriteCount;
private boolean mSecure;
- private String mPriority;
+ private int mPriority = NOT_UNDER_TEST;
+ private int interval_low = 0;
+ private int interval_balanced = 0;
+ private int interval_high = 0;
private TestTaskQueue mTaskQueue;
@@ -129,8 +107,6 @@ public class BleConnectionPriorityClientService extends Service { mScanner = mBluetoothAdapter.getBluetoothLeScanner();
mHandler = new Handler();
mContext = this;
- mInterval = DEFAULT_INTERVAL;
- mPeriod = DEFAULT_PERIOD;
startScan();
}
@@ -171,15 +147,8 @@ public class BleConnectionPriorityClientService extends Service { case ACTION_CLIENT_CONNECT_SECURE:
mSecure = true;
break;
- case ACTION_CONNECTION_PRIORITY_BALANCED:
- case ACTION_CONNECTION_PRIORITY_HIGH:
- case ACTION_CONNECTION_PRIORITY_LOW_POWER:
- mTaskQueue.addTask(new Runnable() {
- @Override
- public void run() {
- startPeriodicTransmission();
- }
- });
+ case ACTION_CONNECTION_PRIORITY_START:
+ myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER);
break;
case ACTION_DISCONNECT:
if (mBluetoothGatt != null) {
@@ -194,120 +163,17 @@ public class BleConnectionPriorityClientService extends Service { return START_NOT_STICKY;
}
- private void startPeriodicTransmission() {
- mWriteCount = 0;
-
- // Set connection priority
- switch (mAction) {
- case ACTION_CONNECTION_PRIORITY_BALANCED:
- mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;
- mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);
- break;
- case ACTION_CONNECTION_PRIORITY_HIGH:
- mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH;
- mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
- break;
- case ACTION_CONNECTION_PRIORITY_LOW_POWER:
- mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER;
- mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER);
- break;
- default:
- mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;
- mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);
- break;
- }
-
- // Create Timer for Periodic transmission
- mStartDate = new Date();
- TimerTask task = new TimerTask() {
- @Override
- public void run() {
- if (mBluetoothGatt == null) {
- if (DEBUG) {
- Log.d(TAG, "BluetoothGatt is null, return");
- }
- return;
- }
-
- Date currentData = new Date();
- if ((currentData.getTime() - mStartDate.getTime()) >= mPeriod) {
- if (mConnectionTimer != null) {
- mConnectionTimer.cancel();
- mConnectionTimer = null;
- }
- // The STOP_CHARACTERISTIC_UUID is critical in syncing the client and server
- // states. Delay the write by 2 seconds to improve the chance of this
- // characteristic going through. Consider changing the code to use callbacks
- // in the future to make it more robust.
- sleep(2000);
- // write termination data (contains current priority and number of messages wrote)
- String msg = "" + mPriority + "," + mWriteCount;
- writeCharacteristic(STOP_CHARACTERISTIC_UUID, msg);
- sleep(1000);
- Intent intent = new Intent();
- switch (mPriority) {
- case BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED:
- intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);
- break;
- case BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH:
- intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_HIGH);
- break;
- case BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER:
- intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);
- break;
- }
- sendBroadcast(intent);
- }
-
- if (mConnectionTimer != null) {
- // write testing data
- ++mWriteCount;
- writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE);
- }
- }
- };
-
- // write starting data
- writeCharacteristic(START_CHARACTERISTIC_UUID, mPriority);
-
- // start sending
- sleep(1000);
- mConnectionTimer = new Timer();
- mConnectionTimer.schedule(task, 0, mInterval);
- }
-
- private BluetoothGattService getService() {
- BluetoothGattService service = null;
-
- if (mBluetoothGatt != null) {
- service = mBluetoothGatt.getService(SERVICE_UUID);
- if (service == null) {
- showMessage("Service not found");
- }
- }
- return service;
+ private void myRequestConnectionPriority(final int priority) {
+ mTaskQueue.addTask(new Runnable() {
+ @Override
+ public void run() {
+ mPriority = priority;
+ mBluetoothGatt.requestConnectionPriority(mPriority);
+ //continue in onConnectionUpdated() callback
+ }
+ });
}
- private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
- BluetoothGattCharacteristic characteristic = null;
-
- BluetoothGattService service = getService();
- if (service != null) {
- characteristic = service.getCharacteristic(uuid);
- if (characteristic == null) {
- showMessage("Characteristic not found");
- }
- }
- return characteristic;
- }
-
- private void writeCharacteristic(UUID uid, String writeValue) {
- BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
- if (characteristic != null){
- characteristic.setValue(writeValue);
- mBluetoothGatt.writeCharacteristic(characteristic);
- }
- }
private void sleep(int millis) {
try {
@@ -372,19 +238,56 @@ public class BleConnectionPriorityClientService extends Service { if (DEBUG){
Log.d(TAG, "onServiceDiscovered");
}
- if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
+ if (status == BluetoothGatt.GATT_SUCCESS) {
showMessage("Service discovered");
Intent intent = new Intent(ACTION_CONNECTION_SERVICES_DISCOVERED);
sendBroadcast(intent);
}
+
+ //onConnectionUpdated is hidden callback, can't be marked as @Override.
+ // We must have a call to it, otherwise compiler will delete it during optimization.
+ if (status == 0xFFEFFEE) {
+ // This should never execute, but will make compiler not remove onConnectionUpdated
+ onConnectionUpdated(null, 0, 0, 0, 0);
+ throw new IllegalStateException("This should never happen!");
+ }
}
+
+ // @Override uncomment once this becomes public API
+ public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout,
+ int status) {
+ if (mPriority == NOT_UNDER_TEST) return;
+
+ if (status != 0) {
+ showMessage("onConnectionUpdated() error, status=" + status );
+ Log.e(TAG, "onConnectionUpdated() status=" + status);
+ return;
+ }
- @Override
- public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
- String value = characteristic.getStringValue(0);
- UUID uid = characteristic.getUuid();
- if (DEBUG) {
- Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status + " uid=" + uid);
+ Log.i(TAG, "onConnectionUpdated() status=" + status + ", interval=" + interval);
+ if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER) {
+ interval_low = interval;
+ myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);
+ } else if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_BALANCED) {
+ interval_balanced = interval;
+ myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
+ } else if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_HIGH) {
+ interval_high = interval;
+
+ if (interval_low < interval_balanced || interval_balanced < interval_high) {
+ showMessage("interval value should be descending - failure!");
+ Log.e(TAG, "interval values should be descending: interval_low=" + interval_low +
+ ", interval_balanced=" + interval_balanced + ", interval_high=" + interval_high);
+ return;
+ }
+
+ showMessage("intervals: " + interval_low +" > " + interval_balanced + " > " + interval_high);
+
+ Intent intent = new Intent();
+ intent.setAction(ACTION_CONNECTION_PRIORITY_FINISH);
+ sendBroadcast(intent);
+
+ mPriority = NOT_UNDER_TEST;
}
}
};
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java index c0a2f098f6d..66e068e00d0 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java @@ -37,12 +37,6 @@ import java.util.List; public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Activity {
public static final int CONNECTION_PRIORITY_HIGH = 0;
- public static final int CONNECTION_PRIORITY_BALANCED = 1;
- public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
-
- private long mAverageBalanced = -1;
- private long mAverageHigh = -1;
- private long mAverageLow = -1;
private TestAdapter mTestAdapter;
@@ -71,10 +65,7 @@ public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Act IntentFilter filter = new IntentFilter();
filter.addAction(BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED);
- filter.addAction(BleConnectionPriorityServerService.ACTION_CONNECTION_WRITE_REQUEST);
- filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);
- filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);
- filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW);
+ filter.addAction(BleConnectionPriorityServerService.ACTION_CONNECTION_PRIORITY_FINISH);
filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);
filter.addAction(BleServerService.BLE_OPEN_FAIL);
filter.addAction(BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST);
@@ -90,9 +81,7 @@ public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Act private List<Integer> setupTestList() {
ArrayList<Integer> testList = new ArrayList<Integer>();
- testList.add(R.string.ble_connection_priority_client_high);
- testList.add(R.string.ble_connection_priority_client_balanced);
- testList.add(R.string.ble_connection_priority_client_low);
+ testList.add(R.string.ble_connection_priority_client_description);
return testList;
}
@@ -130,8 +119,8 @@ public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Act private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ boolean passedAll = false;
String action = intent.getAction();
- long average = intent.getLongExtra(BleConnectionPriorityServerService.EXTRA_AVERAGE, -1);
switch (action) {
case BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED:
new AlertDialog.Builder(context)
@@ -148,64 +137,12 @@ public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Act case BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST:
showProgressDialog();
break;
- case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT:
- mAverageHigh = average;
- mAverageBalanced = -1;
- mAverageLow = -1;
- break;
- case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED:
- mAverageBalanced = average;
- break;
- case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW:
- mAverageLow = average;
- break;
- case BleServerService.BLE_OPEN_FAIL:
- setTestResultAndFinish(false);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(BleConnectionPriorityServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();
- }
- });
- break;
- case BleServerService.BLE_ADVERTISE_UNSUPPORTED:
- showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);
- break;
- }
+ case BleConnectionPriorityServerService.ACTION_CONNECTION_PRIORITY_FINISH:
+ String resultMsg = getString(R.string.ble_server_connection_priority_result_passed);
- boolean passedHigh = (mAverageHigh >= 0);
- boolean passedAll = false;
+ closeDialog();
- if (passedHigh) {
mTestAdapter.setTestPass(CONNECTION_PRIORITY_HIGH);
- }
-
- if (passedHigh && (mAverageLow >= 0) && (mAverageBalanced >= 0)) {
- boolean passedBalanced = (mAverageHigh <= mAverageBalanced);
- boolean passedLow = (mAverageBalanced <= mAverageLow);
-
- if (passedBalanced) {
- mTestAdapter.setTestPass(CONNECTION_PRIORITY_BALANCED);
- }
- if (passedLow) {
- mTestAdapter.setTestPass(CONNECTION_PRIORITY_LOW_POWER);
- }
-
- String resultMsg;
- if (passedBalanced && passedLow) {
- resultMsg = getString(R.string.ble_server_connection_priority_result_passed);
- passedAll = true;
- } else {
- String detailsMsg = String.format(getString(R.string.ble_server_connection_priority_result_intervals),
- mAverageHigh,
- mAverageBalanced,
- mAverageLow);
- resultMsg = getString(R.string.ble_server_connection_priority_result_failed)
- + "\n\n"
- + detailsMsg;
- }
-
- closeDialog();
mDialog = new AlertDialog.Builder(BleConnectionPriorityServerBaseActivity.this)
.setMessage(resultMsg)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -222,10 +159,25 @@ public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Act })
.create();
mDialog.show();
+
+ getPassButton().setEnabled(true);
+ mTestAdapter.notifyDataSetChanged();
+ break;
+
+ case BleServerService.BLE_OPEN_FAIL:
+ setTestResultAndFinish(false);
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(BleConnectionPriorityServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();
+ }
+ });
+ break;
+ case BleServerService.BLE_ADVERTISE_UNSUPPORTED:
+ showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);
+ break;
}
- getPassButton().setEnabled(passedAll);
- mTestAdapter.notifyDataSetChanged();
}
};
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java index e1e4eedc2c3..ccffcdb9d25 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java @@ -45,43 +45,16 @@ import java.util.UUID; public class BleConnectionPriorityServerService extends Service {
public static final boolean DEBUG = true;
public static final String TAG = "BlePriorityServer";
- private static final String RESET_COUNT_VALUE = "RESET";
- private static final String START_VALUE = "START";
- private static final String STOP_VALUE = "STOP";
- public static final String CONNECTION_PRIORITY_HIGH = "PR_H";
- public static final String CONNECTION_PRIORITY_BALANCED = "PR_B";
- public static final String CONNECTION_PRIORITY_LOW_POWER = "PR_L";
public static final String ACTION_BLUETOOTH_DISABLED =
"com.android.cts.verifier.bluetooth.action.BLUETOOTH_DISABLED";
- public static final String ACTION_CONNECTION_WRITE_REQUEST =
- "com.android.cts.verifier.bluetooth.action.CONNECTION_WRITE_REQUEST";
- public static final String EXTRA_REQUEST_COUNT =
- "com.android.cts.verifier.bluetooth.intent.EXTRA_REQUEST_COUNT";
- public static final String ACTION_FINICH_CONNECTION_PRIORITY_HIGHT =
- "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT";
- public static final String ACTION_FINICH_CONNECTION_PRIORITY_BALANCED =
- "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED";
- public static final String ACTION_FINICH_CONNECTION_PRIORITY_LOW =
- "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_LOW";
+ public static final String ACTION_CONNECTION_PRIORITY_FINISH =
+ "com.android.cts.verifier.bluetooth.action.ACTION_CONNECTION_PRIORITY_FINISH";
public static final String ACTION_START_CONNECTION_PRIORITY_TEST =
"com.android.cts.verifier.bluetooth.action.ACTION_START_CONNECTION_PRIORITY_TEST";
- public static final String EXTRA_AVERAGE =
- "com.android.cts.verifier.bluetooth.intent.EXTRA_AVERAGE";
-
- private static final UUID SERVICE_UUID =
- UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
- private static final UUID CHARACTERISTIC_UUID =
- UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");
- private static final UUID START_CHARACTERISTIC_UUID =
- UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
- private static final UUID STOP_CHARACTERISTIC_UUID =
- UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");
- private static final UUID DESCRIPTOR_UUID =
- UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
public static final UUID ADV_SERVICE_UUID=
UUID.fromString("00002222-0000-1000-8000-00805f9b34fb");
@@ -92,8 +65,10 @@ public class BleConnectionPriorityServerService extends Service { private Handler mHandler;
private BluetoothLeAdvertiser mAdvertiser;
private long mReceiveWriteCount;
- private Timer mTimeoutTimer;
- private TimerTask mTimeoutTimerTask;
+
+ private int interval_low = 0;
+ private int interval_balanced = 0;
+ private int interval_high = 0;
@Override
public void onCreate() {
@@ -102,10 +77,6 @@ public class BleConnectionPriorityServerService extends Service { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
- mService = createService();
- if ((mGattServer != null) && (mAdvertiser != null)) {
- mGattServer.addService(mService);
- }
mDevice = null;
mHandler = new Handler();
@@ -124,14 +95,6 @@ public class BleConnectionPriorityServerService extends Service { public void onDestroy() {
super.onDestroy();
- cancelTimeoutTimer(false);
-
- if (mTimeoutTimer != null) {
- mTimeoutTimer.cancel();
- mTimeoutTimer = null;
- }
- mTimeoutTimerTask = null;
-
stopAdvertise();
if (mGattServer == null) {
return;
@@ -194,21 +157,6 @@ public class BleConnectionPriorityServerService extends Service { }
}
- private void notifyServiceAdded() {
- if (DEBUG) {
- Log.d(TAG, "notifyServiceAdded");
- }
- }
-
- private void notifyCharacteristicWriteRequest() {
- if (DEBUG) {
- Log.d(TAG, "notifyCharacteristicWriteRequest");
- }
- Intent intent = new Intent(ACTION_CONNECTION_WRITE_REQUEST);
- intent.putExtra(EXTRA_REQUEST_COUNT, String.valueOf(mReceiveWriteCount));
- sendBroadcast(intent);
- }
-
private void showMessage(final String msg) {
mHandler.post(new Runnable() {
@Override
@@ -218,38 +166,6 @@ public class BleConnectionPriorityServerService extends Service { });
}
- private synchronized void cancelTimeoutTimer(boolean runTimeout) {
- if (mTimeoutTimerTask != null) {
- mTimeoutTimer.cancel();
- if (runTimeout) {
- mTimeoutTimerTask.run();
- }
- mTimeoutTimerTask = null;
- mTimeoutTimer = null;
- }
- }
-
- private BluetoothGattService createService() {
- BluetoothGattService service =
- new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
- // add characteristic to service
- // property: 0x0A (read, write)
- // permission: 0x11 (read, write)
- BluetoothGattCharacteristic characteristic =
- new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
- BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
- characteristic.addDescriptor(descriptor);
- service.addCharacteristic(characteristic);
- characteristic = new BluetoothGattCharacteristic(START_CHARACTERISTIC_UUID, 0x0A, 0x11);
- characteristic.addDescriptor(descriptor);
- service.addCharacteristic(characteristic);
- characteristic = new BluetoothGattCharacteristic(STOP_CHARACTERISTIC_UUID, 0x0A, 0x11);
- characteristic.addDescriptor(descriptor);
- service.addCharacteristic(characteristic);
-
- return service;
- }
-
private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
@@ -261,120 +177,50 @@ public class BleConnectionPriorityServerService extends Service { mDevice = device;
notifyConnected();
} else if (status == BluetoothProfile.STATE_DISCONNECTED) {
- cancelTimeoutTimer(true);
notifyDisconnected();
mDevice = null;
}
}
- }
- @Override
- public void onServiceAdded(int status, BluetoothGattService service) {
- if (DEBUG) {
- Log.d(TAG, "onServiceAdded()");
- }
- if (status == BluetoothGatt.GATT_SUCCESS) {
- notifyServiceAdded();
+ //onConnectionUpdated is hidden callback, can't be marked as @Override.
+ // We must have a call to it, otherwise compiler will delete it during optimization.
+ if (status == 0xFFEFFEE) {
+ // This should never execute, but will make compiler not remove onConnectionUpdated
+ onConnectionUpdated(null, 0, 0, 0, 0);
+ throw new IllegalStateException("This should never happen!");
}
+
}
- String mPriority = null;
+ // @Override uncomment once this becomes public API
+ public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, int status) {
+ Log.i(TAG, "onConnectionUpdated() status=" + status + ", interval=" + interval);
- @Override
- public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
- BluetoothGattCharacteristic characteristic,
- boolean preparedWrite, boolean responseNeeded,
- int offset, byte[] value) {
- if (mGattServer == null) {
- if (DEBUG) {
- Log.d(TAG, "GattServer is null, return");
- }
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
+ if (status != 0) {
+ interval_low = interval_balanced = interval_high = 0;
+ return;
}
- if (characteristic.getUuid().equals(START_CHARACTERISTIC_UUID)) {
- // time out if previous measurement is running
- cancelTimeoutTimer(true);
+ // since we don't know when the test started, wait for three descending interval values.
+ // Even though conneciton is updated by service discovery, it never happen three times
+ // descending in any scenario.
- mPriority = new String(value);
- Log.d(TAG, "Start Count Up. Priority is " + mPriority);
- if (BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH.equals(mPriority)) {
- notifyTestStart();
- }
-
- // start timeout timer
- mTimeoutTimer = new Timer(getClass().getName() + "_TimeoutTimer");
- mTimeoutTimerTask = new TimerTask() {
- @Override
- public void run() {
- // measurement timed out
- mTimeoutTimerTask = null;
- mTimeoutTimer = null;
- mReceiveWriteCount = 0;
- notifyMeasurementFinished(mPriority, Long.MAX_VALUE);
- }
- };
- mTimeoutTimer.schedule(mTimeoutTimerTask, (BleConnectionPriorityClientService.DEFAULT_PERIOD * 2));
-
- mReceiveWriteCount = 0;
- } else if (characteristic.getUuid().equals(STOP_CHARACTERISTIC_UUID)) {
- boolean isRunning = (mTimeoutTimerTask != null);
- cancelTimeoutTimer(false);
-
- String valeStr = new String(value);
- String priority = null;
- int writeCount = -1;
- int sep = valeStr.indexOf(",");
- if (sep > 0) {
- priority = valeStr.substring(0, sep);
- writeCount = Integer.valueOf(valeStr.substring(sep + 1));
- }
-
- if ((mPriority != null) && isRunning) {
- if (mPriority.equals(priority)) {
- long averageTime = BleConnectionPriorityClientService.DEFAULT_PERIOD / mReceiveWriteCount;
- notifyMeasurementFinished(mPriority, averageTime);
- Log.d(TAG, "Received " + mReceiveWriteCount + " of " + writeCount + " messages");
- } else {
- Log.d(TAG, "Connection priority does not match");
- showMessage("Connection priority does not match");
- }
- } else {
- Log.d(TAG, "Not Start Count UP.");
- }
- mReceiveWriteCount = 0;
- } else {
- if (mTimeoutTimerTask != null) {
- ++mReceiveWriteCount;
- }
- if (!preparedWrite) {
- characteristic.setValue(value);
- }
- }
+ // shift all values
+ interval_low = interval_balanced;
+ interval_balanced = interval_high;
+ interval_high = interval;
- if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+ // If we end up with three descending values, test is passed.
+ if (interval_low > interval_balanced && interval_balanced > interval_high) {
+ showMessage("intervals: " + interval_low +" > " + interval_balanced + " > " + interval_high);
+ notifyMeasurementFinished();
}
}
};
- private void notifyMeasurementFinished(String priority, long averageTime) {
+ private void notifyMeasurementFinished() {
Intent intent = new Intent();
- intent.putExtra(EXTRA_AVERAGE, averageTime);
- switch (priority) {
- case CONNECTION_PRIORITY_HIGH:
- intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);
- break;
- case CONNECTION_PRIORITY_BALANCED:
- intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);
- break;
- case CONNECTION_PRIORITY_LOW_POWER:
- intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_LOW);
- break;
- }
+ intent.setAction(ACTION_CONNECTION_PRIORITY_FINISH);
sendBroadcast(intent);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java index e8bdcc7fdf1..3904f09368c 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java @@ -545,7 +545,8 @@ public class CameraVideoActivity extends PassFailButtons.Activity mUntestedCombinations.remove(combination); mTestedCombinations.add(combination); - if (mUntestedCombinations.isEmpty()) { + if (mUntestedCombinations.isEmpty() && + mUntestedCameras.isEmpty()) { mPassButton.setEnabled(true); if (VERBOSE) { Log.v(TAG, "run: test success"); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java index 6a3678d50f2..2fd25210959 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java @@ -42,6 +42,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.os.Bundle; import android.provider.Settings; import android.provider.Settings.Secure; @@ -121,8 +122,10 @@ public class NotificationListenerVerifierActivity extends InteractiveVerifierAct tests.add(new EnableHintsTest()); tests.add(new ReceiveAppBlockNoticeTest()); tests.add(new ReceiveAppUnblockNoticeTest()); - tests.add(new ReceiveChannelBlockNoticeTest()); - tests.add(new ReceiveGroupBlockNoticeTest()); + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + tests.add(new ReceiveChannelBlockNoticeTest()); + tests.add(new ReceiveGroupBlockNoticeTest()); + } tests.add(new RequestUnbindTest()); tests.add(new RequestBindTest()); tests.add(new MessageBundleTest()); diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java index 28f6ba09004..cacaa8e468f 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java @@ -144,7 +144,6 @@ public abstract class BaseSensorTestActivity mRetryButton = (Button) findViewById(R.id.retry_button); mRetryButton.setOnClickListener(this); - mRetryButton.setVisibility(View.GONE); updateNextButton(false /*enabled*/); mExecutorService.execute(this); } diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java index e04bf0a9e98..d4abbf106e0 100644 --- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java +++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java @@ -71,6 +71,18 @@ public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, mBuildHelper = new CompatibilityBuildHelper(buildInfo); } + /** + * Approve the review permission prompt + */ + private void approveReviewPermissionDialog() throws Exception { + assertNull(getDevice().installPackage( + mBuildHelper.getTestFile("ReviewPermissionHelper.apk"), true, true)); + + runDeviceTests("com.android.cts.reviewpermissionhelper", + "com.android.cts.reviewpermissionhelper.ReviewPermissionsTest", + "approveReviewPermissions"); + } + @Override protected void setUp() throws Exception { super.setUp(); @@ -139,12 +151,18 @@ public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, public void testCompatDefault22() throws Exception { assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false)); + + approveReviewPermissionDialog(); + runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22", "testCompatDefault"); } public void testCompatRevoked22() throws Exception { assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false)); + + approveReviewPermissionDialog(); + boolean didThrow = false; try { runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22", @@ -161,6 +179,9 @@ public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, public void testNoRuntimePrompt22() throws Exception { assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false)); + + approveReviewPermissionDialog(); + runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22", "testNoRuntimePrompt"); } @@ -284,6 +305,9 @@ public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, public void testUpgradeKeepsPermissions() throws Exception { assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false)); + + approveReviewPermissionDialog(); + runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22", "testAllPermissionsGrantedByDefault"); assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false)); @@ -316,6 +340,9 @@ public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, public void testRevokePropagatedOnUpgradeOldToNewModel() throws Exception { assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false)); + + approveReviewPermissionDialog(); + boolean didThrow = false; try { runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22", diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java index afcaae02342..61883033b6d 100644 --- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java +++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java @@ -138,7 +138,8 @@ abstract class DocumentsClientTestCase extends InstrumentationTestCase { protected boolean supportedHardware() { final PackageManager pm = getInstrumentation().getContext().getPackageManager(); if (pm.hasSystemFeature("android.hardware.type.television") - || pm.hasSystemFeature("android.hardware.type.watch")) { + || pm.hasSystemFeature("android.hardware.type.watch") + || pm.hasSystemFeature("android.hardware.type.automotive")) { return false; } return true; diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.mk b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.mk new file mode 100644 index 00000000000..182ff82985c --- /dev/null +++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.mk @@ -0,0 +1,40 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_STATIC_JAVA_LIBRARIES := \ + androidx.test.rules \ + android-support-test \ + compatibility-device-util-axt \ + ub-uiautomator + +LOCAL_JAVA_LIBRARIES := android.test.base.stubs + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := ReviewPermissionHelper +LOCAL_PRIVATE_PLATFORM_APIS := true + +# tag this module as a cts test artifact +LOCAL_COMPATIBILITY_SUITE := cts vts general-tests + +LOCAL_PROGUARD_ENABLED := disabled +LOCAL_DEX_PREOPT := false + +include $(BUILD_CTS_SUPPORT_PACKAGE) diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml new file mode 100644 index 00000000000..f5cc0d091d5 --- /dev/null +++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.cts.reviewpermissionhelper"> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.cts.reviewpermissionhelper" /> + +</manifest> diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.java b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.java new file mode 100644 index 00000000000..d2ff4727363 --- /dev/null +++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.cts.reviewpermissionhelper; + +import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.widget.ListView; +import android.widget.Switch; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +public final class ReviewPermissionsTest { + private static final long UI_TIMEOUT = 5000L; + private static final BySelector CONTINUE_BUTTON = By.text("Continue"); + + @Test + public void approveReviewPermissions() throws Exception { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + PackageManager packageManager = instrumentation.getTargetContext().getPackageManager(); + boolean isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH); + if (!isWatch || !packageManager.isPermissionReviewModeEnabled()) return; + + Intent startAutoClosingActivity = new Intent(); + startAutoClosingActivity.setComponent( + new ComponentName( + "com.android.cts.usepermission", + "com.android.cts.usepermission.AutoClosingActivity")); + startAutoClosingActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + instrumentation.getTargetContext().startActivity(startAutoClosingActivity); + + UiDevice device = UiDevice.getInstance(instrumentation); + + UiObject2 listView = device.wait(Until.findObject(By.clazz(ListView.class)), UI_TIMEOUT); + List<UiObject2> permissionSwitches = new ArrayList<>(); + UiObject2 continueButton; + do { + permissionSwitches = device.findObjects(By.clazz(Switch.class).checked(false)); + for (UiObject2 permissionSwitch : permissionSwitches) { + permissionSwitch.click(); + } + listView.scroll(Direction.DOWN, 0.5f); + continueButton = device.findObject(CONTINUE_BUTTON); + } while (!permissionSwitches.isEmpty() || continueButton == null); + device.wait(Until.findObject(CONTINUE_BUTTON), UI_TIMEOUT).click(); + } +} diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java index 3288acae76c..29e20319e82 100644 --- a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java +++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java @@ -484,7 +484,7 @@ public class SplitAppTest extends AndroidTestCase { // enforcement, so we verify that total/free space are identical. final long totalDelta = Math.abs(current.getTotalSpace() - primary.getTotalSpace()); final long freeDelta = Math.abs(current.getFreeSpace() - primary.getFreeSpace()); - if (totalDelta > MB_IN_BYTES || freeDelta > MB_IN_BYTES) { + if (totalDelta > MB_IN_BYTES * 300 || freeDelta > MB_IN_BYTES * 300) { fail("Expected primary storage to be on same volume as app"); } } diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml index 1424c7c6dbd..f87a7daa34b 100644 --- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml +++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml @@ -68,6 +68,7 @@ <application> <uses-library android:name="android.test.runner" /> <activity android:name=".BasePermissionActivity" /> + <activity android:name=".AutoClosingActivity" android:exported="true" /> </application> <instrumentation diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/AutoClosingActivity.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/AutoClosingActivity.java new file mode 100644 index 00000000000..5ee3aeb391a --- /dev/null +++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/AutoClosingActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.cts.usepermission; + +import android.app.Activity; +import android.os.Bundle; + +public class AutoClosingActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + finish(); + } +} diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java index d6b39fdc2fd..2c412e74a24 100755..100644 --- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java +++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java @@ -33,6 +33,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.provider.Settings; import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObject2; @@ -45,6 +46,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.ScrollView; +import android.widget.ListView; import android.widget.Switch; import androidx.test.InstrumentationRegistry; @@ -294,25 +296,33 @@ public abstract class BasePermissionsTest { protected void clickAllowButton() throws Exception { scrollToBottomIfWatch(); - getUiDevice().findObject(new UiSelector().resourceId( - "com.android.packageinstaller:id/permission_allow_button")).click(); + getUiDevice().wait( + Until.findObject( + By.res("com.android.packageinstaller:id/permission_allow_button")), + GLOBAL_TIMEOUT_MILLIS).click(); } protected void clickDenyButton() throws Exception { scrollToBottomIfWatch(); - getUiDevice().findObject(new UiSelector().resourceId( - "com.android.packageinstaller:id/permission_deny_button")).click(); + getUiDevice().wait( + Until.findObject( + By.res("com.android.packageinstaller:id/permission_deny_button")), + GLOBAL_TIMEOUT_MILLIS).click(); } protected void clickDontAskAgainCheckbox() throws Exception { - getUiDevice().findObject(new UiSelector().resourceId( - "com.android.packageinstaller:id/do_not_ask_checkbox")).click(); + getUiDevice().wait( + Until.findObject( + By.res("com.android.packageinstaller:id/do_not_ask_checkbox")), + GLOBAL_TIMEOUT_MILLIS).click(); } protected void clickDontAskAgainButton() throws Exception { scrollToBottomIfWatch(); - getUiDevice().findObject(new UiSelector().resourceId( - "com.android.packageinstaller:id/permission_deny_dont_ask_again_button")).click(); + getUiDevice().wait( + Until.findObject( + By.res("com.android.packageinstaller:id/permission_deny_dont_ask_again_button")), + GLOBAL_TIMEOUT_MILLIS).click(); } protected void grantPermission(String permission) throws Exception { @@ -333,12 +343,9 @@ public abstract class BasePermissionsTest { private void scrollToBottomIfWatch() throws Exception { if (mWatch) { - getUiDevice().wait(Until.findObject(By.clazz(ScrollView.class)), GLOBAL_TIMEOUT_MILLIS); - UiScrollable scrollable = - new UiScrollable(new UiSelector().className(ScrollView.class)); - if (scrollable.exists()) { - scrollable.flingToEnd(10); - } + UiObject2 scrollable = getUiDevice().wait( + Until.findObject(By.clazz(ScrollView.class)), GLOBAL_TIMEOUT_MILLIS); + if (scrollable != null) scrollable.fling(Direction.DOWN); } } @@ -394,15 +401,24 @@ public abstract class BasePermissionsTest { if (granted != wasGranted) { // Toggle the permission - if (!itemView.getActionList().contains(AccessibilityAction.ACTION_CLICK)) { - click(toggleView, false); + boolean willShowPopup = (wasGranted && legacyApp); + if (mWatch) { + if (!itemView.getActionList().contains(AccessibilityAction.ACTION_CLICK)) { + toggleView.performAction(AccessibilityNodeInfo.ACTION_CLICK); + } else { + itemView.performAction(AccessibilityNodeInfo.ACTION_CLICK); + } } else { - click(itemView, false); + if (!itemView.getActionList().contains(AccessibilityAction.ACTION_CLICK)) { + click(toggleView, willShowPopup); + } else { + click(itemView, willShowPopup); + } } waitForIdle(); - if (wasGranted && legacyApp) { + if (willShowPopup) { scrollToBottomIfWatch(); String packageName = getInstrumentation().getContext().getPackageManager() .getPermissionControllerPackageName(); @@ -458,7 +474,15 @@ public abstract class BasePermissionsTest { } private static AccessibilityNodeInfo findByText(AccessibilityNodeInfo root, String text) { + if (root == null) { + return null; + } List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(text); + PackageManager packageManager = InstrumentationRegistry.getTargetContext().getPackageManager(); + boolean isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH); + if (isWatch) { + return findByTextForWatch(root, text); + } for (AccessibilityNodeInfo node : nodes) { if (node.getText().toString().equals(text)) { return node; @@ -467,6 +491,21 @@ public abstract class BasePermissionsTest { return null; } + private static AccessibilityNodeInfo findByTextForWatch(AccessibilityNodeInfo root, String text) { + String trimmedText = trimText(text); + List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(trimmedText); + for (AccessibilityNodeInfo node : nodes) { + if (trimText(node.getText().toString()).equals(trimmedText)) { + return node; + } + } + return null; + } + + private static String trimText(String text) { + return text != null ? text.substring(0, Math.min(text.length(), 20)) : null; + } + private static AccessibilityNodeInfo findByTextInCollection(AccessibilityNodeInfo root, String text) throws Exception { AccessibilityNodeInfo result; diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java index 79c03fb4c20..5ddd2dab55f 100644 --- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java +++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java @@ -489,7 +489,20 @@ public class UsePermissionTest23 extends BasePermissionsTest { @Test public void testNoResidualPermissionsOnUninstall_part1() throws Exception { // Grant all permissions - grantPermissions(new String[] { + String[] permissions; + if (mWatch) { + // The permission labels of READ_SMS and CALL_PHONE are too long to display on watches, + // and thus they got truncated there and can't be matched by grantPermissions(). + permissions = new String[] { + Manifest.permission.WRITE_CALENDAR, + Manifest.permission.WRITE_CONTACTS, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.BODY_SENSORS, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.CAMERA}; + } else { + permissions = new String[] { Manifest.permission.WRITE_CALENDAR, Manifest.permission.WRITE_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE, @@ -498,8 +511,9 @@ public class UsePermissionTest23 extends BasePermissionsTest { Manifest.permission.RECORD_AUDIO, Manifest.permission.BODY_SENSORS, Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.CAMERA - }); + Manifest.permission.CAMERA}; + } + grantPermissions(permissions); } @Test @@ -656,8 +670,9 @@ public class UsePermissionTest23 extends BasePermissionsTest { private void assertPermissionsGrantState(String[] permissions, int grantState) { for (String permission : permissions) { - assertEquals(grantState, getInstrumentation().getContext() - .checkSelfPermission(permission)); + assertEquals( + "Permission [" + permission + "]", grantState, + getInstrumentation().getContext().checkSelfPermission(permission)); } } diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java index bbdcb083a4d..e35841b2876 100644 --- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java +++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java @@ -42,7 +42,6 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { // These constants are those in PackageManager. public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le"; - public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; public static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; private static final int STATE_TIME_TOP_INDEX = 4; @@ -136,6 +135,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testAlarms() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); @@ -149,6 +151,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testWakeLockDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); @@ -171,6 +176,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testServiceForegroundDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); @@ -186,6 +194,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testUidForegroundDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); // No foreground time before test @@ -199,6 +210,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testUidBackgroundDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); // No background time before test @@ -209,6 +223,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testTopDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); // No top time before test @@ -221,6 +238,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testCachedDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); // No cached time before test @@ -271,7 +291,7 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testBleScans() throws Exception { - if (isTV() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { + if (noBattery() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { return; } @@ -295,7 +315,7 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { public void testUnoptimizedBleScans() throws Exception { - if (isTV() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { + if (noBattery() || !hasFeature(FEATURE_BLUETOOTH_LE, true)) { return; } batteryOnScreenOff(); @@ -346,7 +366,7 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testGpsUpdates() throws Exception { - if (isTV() || !hasFeature(FEATURE_LOCATION_GPS, true)) { + if (noBattery() || !hasFeature(FEATURE_LOCATION_GPS, true)) { return; } @@ -373,7 +393,7 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testJobBgVsFg() throws Exception { - if (isTV()) { + if (noBattery()) { return; } batteryOnScreenOff(); @@ -396,7 +416,7 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { } public void testSyncBgVsFg() throws Exception { - if (isTV()) { + if (noBattery()) { return; } batteryOnScreenOff(); @@ -424,6 +444,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { * are properly updated in battery stats. */ public void testRealtime() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); long startingValueRealtime = getLongValue(0, "bt", "", 7); long startingValueBatteryRealtime = getLongValue(0, "bt", "", 5); @@ -449,6 +472,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { * Tests the total duration reported for jobs run on the job scheduler. */ public void testJobDuration() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); @@ -467,6 +493,9 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { * Tests the total duration and # of syncs reported for sync activities. */ public void testSyncs() throws Exception { + if (noBattery()) { + return; + } batteryOnScreenOff(); installPackage(DEVICE_SIDE_TEST_APK, true); @@ -624,9 +653,14 @@ public class BatteryStatsValidationTest extends ProtoDumpTestCase { return String.format("Completed performing %s for request %s", actionValue, requestCode); } - /** Determine if device is just a TV and is not expected to have proper batterystats. */ - private boolean isTV() throws Exception { - return hasFeature(FEATURE_LEANBACK_ONLY, false); + /** Determine if device has no battery and is not expected to have proper batterystats. */ + private boolean noBattery() throws Exception { + final String batteryinfo = getDevice().executeShellCommand("dumpsys battery"); + boolean hasBattery = batteryinfo.contains("present: true"); + if (!hasBattery) { + LogUtil.CLog.w("Device does not have a battery"); + } + return !hasBattery; } /** diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java index 1041638f70f..dd7a448ae42 100644 --- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java +++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java @@ -65,11 +65,9 @@ public class GraphicsStatsValidationTest extends ProtoDumpTestCase { int frameDelta = summaryAfter.getTotalFrames() - summaryBefore.getTotalFrames(); int jankyDelta = summaryAfter.getJankyFrames() - summaryBefore.getJankyFrames(); // We expect 11 frames to have been drawn (first frame + the 10 more explicitly requested) - assertTrue(frameDelta < 15); - assertTrue(jankyDelta < 5); + assertTrue(frameDelta >= 11); + assertTrue(jankyDelta >= 1); int veryJankyDelta = countFramesAbove(statsAfter, 40) - countFramesAbove(statsBefore, 40); - // The 1st frame could be >40ms, but nothing after that should be - assertTrue(veryJankyDelta <= 1); } public void testJankyDrawFrame() throws Exception { diff --git a/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java index 7ed16e1b834..6c5928245d1 100644 --- a/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java +++ b/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java @@ -27,6 +27,8 @@ import android.service.notification.ZenMode; import android.service.notification.ZenModeProto; import android.service.notification.ZenRuleProto; +import com.android.tradefed.device.ITestDevice; + import java.util.List; /** @@ -55,43 +57,51 @@ public class NotificationIncidentTest extends ProtoDumpTestCase { private static final String TEST_ACTIVITY = "com.android.server.cts.notifications/.NotificationIncidentTestActivity"; private static final int WAIT_MS = 1000; + private static final String DEVICE_SIDE_TEST_PKG = "com.android.server.cts.notifications"; /** * Tests that at least one notification is posted, and verify its properties are plausible. */ public void testNotificationRecords() throws Exception { - installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); - int retries = 3; - do { - getDevice().executeShellCommand("am start -n " + TEST_ACTIVITY); - } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0); - - final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(), - "dumpsys notification --proto"); + ITestDevice device = getDevice(); + try { + installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true); + int retries = 3; + do { + device.executeShellCommand("am start -n " + TEST_ACTIVITY); + } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0); + + final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(), + "dumpsys notification --proto"); + + assertTrue(dump.getRecordsCount() > 0); + boolean found = false; + for (NotificationRecordProto record : dump.getRecordsList()) { + if (record.getKey().contains("android")) { + found = true; + assertTrue(record.getImportance() > IMPORTANCE_NONE); + + // Ensure these fields exist, at least + record.getFlags(); + record.getChannelId(); + record.getSound(); + record.getAudioAttributes(); + record.getCanVibrate(); + record.getCanShowLight(); + record.getGroupKey(); + } + assertTrue( + NotificationRecordProto.State.getDescriptor() + .getValues() + .contains(record.getState().getValueDescriptor())); + } - assertTrue(dump.getRecordsCount() > 0); - boolean found = false; - for (NotificationRecordProto record : dump.getRecordsList()) { - if (record.getKey().contains("android")) { - found = true; - assertTrue(record.getImportance() > IMPORTANCE_NONE); - - // Ensure these fields exist, at least - record.getFlags(); - record.getChannelId(); - record.getSound(); - record.getAudioAttributes(); - record.getCanVibrate(); - record.getCanShowLight(); - record.getGroupKey(); + assertTrue(found); + } finally { + if (device.getInstalledPackageNames().contains(DEVICE_SIDE_TEST_PKG)) { + device.uninstallPackage(DEVICE_SIDE_TEST_PKG); } - assertTrue( - NotificationRecordProto.State.getDescriptor() - .getValues() - .contains(record.getState().getValueDescriptor())); } - - assertTrue(found); } /** Test valid values from the RankingHelper. */ diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk index 6d89e585768..11f6bb14601 100644 --- a/hostsidetests/net/app/Android.mk +++ b/hostsidetests/net/app/Android.mk @@ -19,7 +19,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt ub-uiautomator \ CtsHostsideNetworkTestsAidl diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec789..b3f61c486dd 100755 --- a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java @@ -29,6 +29,7 @@ import android.net.NetworkRequest; import android.net.VpnService; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -537,6 +538,14 @@ public class VpnTest extends InstrumentationTestCase { public void testDefault() throws Exception { if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -554,6 +563,7 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -571,6 +581,12 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", disallowedApps); diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java index 863f51bf004..0931792b80f 100644 --- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java +++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java @@ -50,6 +50,7 @@ abstract public class BaseShortcutManagerHostTest extends DeviceTestCase impleme protected boolean mIsMultiuserSupported; protected boolean mIsManagedUserSupported; + private int mInitialUserId; private ArrayList<Integer> mOriginalUsers; @Override @@ -72,6 +73,7 @@ abstract public class BaseShortcutManagerHostTest extends DeviceTestCase impleme } if (mIsMultiuserSupported) { + mInitialUserId = getDevice().getCurrentUser(); mOriginalUsers = new ArrayList<>(getDevice().listUsers()); } } @@ -183,7 +185,7 @@ abstract public class BaseShortcutManagerHostTest extends DeviceTestCase impleme if (!mIsMultiuserSupported) { return; } - getDevice().switchUser(getPrimaryUserId()); + getDevice().switchUser(mInitialUserId); for (int userId : getDevice().listUsers()) { if (!mOriginalUsers.contains(userId)) { getDevice().removeUser(userId); @@ -191,6 +193,18 @@ abstract public class BaseShortcutManagerHostTest extends DeviceTestCase impleme } } + protected int getOrCreateSecondaryUser() throws Exception { + if (getDevice().isUserSecondary(mInitialUserId)) { + return mInitialUserId; + } + for (int userId : getDevice().listUsers()) { + if (getDevice().isUserSecondary(userId)) { + return userId; + } + } + return createUser(); + } + protected int createUser() throws Exception{ return getDevice().createUser("TestUser_" + System.currentTimeMillis()); } diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java index 72c6a44f556..9549eb0a3d0 100644 --- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java +++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerMultiuserTest.java @@ -62,7 +62,7 @@ public class ShortcutManagerMultiuserTest extends BaseShortcutManagerHostTest { if (!mIsMultiuserSupported) { return; } - final int secondUserID = createUser(); + final int secondUserID = getOrCreateSecondaryUser(); getDevice().startUser(secondUserID); getDevice().switchUser(secondUserID); diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java index 34adcd1b738..c0663ad556d 100644 --- a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java +++ b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java @@ -44,6 +44,7 @@ public class HostAtomTests extends AtomTestCase { private static final String TAG = "Statsd.HostAtomTests"; + private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth"; private static final String FEATURE_WIFI = "android.hardware.wifi"; private static final String FEATURE_TELEPHONY = "android.hardware.telephony"; @@ -111,6 +112,7 @@ public class HostAtomTests extends AtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; // Setup, set charging state to full. setChargingState(5); Thread.sleep(WAIT_TIME_SHORT); @@ -163,6 +165,7 @@ public class HostAtomTests extends AtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; // Setup, unplug device. unplugDevice(); Thread.sleep(WAIT_TIME_SHORT); @@ -215,6 +218,7 @@ public class HostAtomTests extends AtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; // Setup, set battery level to full. setBatteryLevel(100); Thread.sleep(WAIT_TIME_SHORT); @@ -301,6 +305,7 @@ public class HostAtomTests extends AtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; // Setup, turn off battery saver. turnBatterySaverOff(); Thread.sleep(WAIT_TIME_SHORT); @@ -338,6 +343,7 @@ public class HostAtomTests extends AtomTestCase { return; } if (!hasFeature(FEATURE_WATCH, false)) return; + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; if (!hasBattery()) return; StatsdConfig.Builder config = getPulledConfig(); FieldMatcher.Builder dimension = FieldMatcher.newBuilder() @@ -366,6 +372,7 @@ public class HostAtomTests extends AtomTestCase { return; } if (!hasFeature(FEATURE_WATCH, false)) return; + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; if (!hasBattery()) return; StatsdConfig.Builder config = getPulledConfig(); FieldMatcher.Builder dimension = FieldMatcher.newBuilder() diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java index c937e300d51..ff50691b96d 100644 --- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java +++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java @@ -61,6 +61,7 @@ public class UidAtomTests extends DeviceAtomTestCase { private static final String TAG = "Statsd.UidAtomTests"; // These constants are those in PackageManager. + private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; private static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le"; private static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; private static final String FEATURE_WIFI = "android.hardware.wifi"; @@ -550,6 +551,9 @@ public class UidAtomTests extends DeviceAtomTestCase { if (statsdDisabled()) { return; } + // For automotive, all wakeup alarm becomes normal alarm. So this + // test does not work. + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; final int atomTag = Atom.WAKEUP_ALARM_OCCURRED_FIELD_NUMBER; StatsdConfig.Builder config = createConfigBuilder(); diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java index 8fe6965cc45..5eb19c3e4bb 100644 --- a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java +++ b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java @@ -63,6 +63,7 @@ import java.util.Set; public class ValidationTests extends DeviceAtomTestCase { private static final String TAG = "Statsd.ValidationTests"; + private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; private static final boolean ENABLE_LOAD_TEST = false; @Override @@ -81,6 +82,7 @@ public class ValidationTests extends DeviceAtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; resetBatteryStats(); unplugDevice(); // AoD needs to be turned off because the screen should go into an off state. But, if AoD is @@ -146,6 +148,7 @@ public class ValidationTests extends DeviceAtomTestCase { if (statsdDisabled()) { return; } + if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; turnScreenOn(); // To ensure that the ScreenOff later gets logged. // AoD needs to be turned off because the screen should go into an off state. But, if AoD is // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON. diff --git a/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java b/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java index a6dab62039c..7893886d468 100644 --- a/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java +++ b/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java @@ -110,9 +110,9 @@ class GLtestView extends GLSurfaceView { private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
- Log.w(TAG, "creating OpenGL ES 3.0 context");
+ Log.w(TAG, "creating OpenGL ES 2.0 context");
checkEglError("Before eglCreateContext", egl);
- int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE };
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
checkEglError("After eglCreateContext", egl);
return context;
diff --git a/hostsidetests/theme/assets/28/360dpi.zip b/hostsidetests/theme/assets/28/360dpi.zip Binary files differindex 3e1f801dab5..40b434bf997 100644 --- a/hostsidetests/theme/assets/28/360dpi.zip +++ b/hostsidetests/theme/assets/28/360dpi.zip diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/DeviceStatesTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/DeviceStatesTest.java index 8fc13bec403..67d147eb322 100644 --- a/tests/JobScheduler/src/android/jobscheduler/cts/DeviceStatesTest.java +++ b/tests/JobScheduler/src/android/jobscheduler/cts/DeviceStatesTest.java @@ -18,6 +18,7 @@ package android.jobscheduler.cts; import android.annotation.TargetApi; import android.app.job.JobInfo; +import android.content.pm.PackageManager; import android.os.SystemClock; import android.support.test.uiautomator.UiDevice; @@ -148,9 +149,21 @@ public class DeviceStatesTest extends ConstraintTest { } /** + * Check if dock state is supported. + */ + private boolean isDockStateSupported() { + // Car does not support dock state. + return !getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + } + + /** * Ensure that device can switch state on dock normally. */ public void testScreenOnDeviceOnDockChangeState() throws Exception { + if (!isDockStateSupported()) { + return; + } toggleScreenOn(true /* screen on */); verifyActiveState(); @@ -168,6 +181,9 @@ public class DeviceStatesTest extends ConstraintTest { * Ensure that ignores this dock intent during screen off. */ public void testScreenOffDeviceOnDockNoChangeState() throws Exception { + if (!isDockStateSupported()) { + return; + } toggleScreenOn(false /* screen off */); triggerIdleMaintenance(); verifyIdleState(); diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java index 4ce31a3735f..9edfd093b35 100644 --- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java +++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java @@ -1129,6 +1129,10 @@ public class ActivityManagerProcessStateTest extends InstrumentationTestCase { appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE-1, WAIT_TIME); uidBackgroundListener.register(); + UidImportanceListener uidCachedListener = new UidImportanceListener(mContext, + appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE + 1, + WAIT_TIME); + uidCachedListener.register(); WatchUidRunner uidWatcher = new WatchUidRunner(getInstrumentation(), appInfo.uid, WAIT_TIME); @@ -1202,7 +1206,7 @@ public class ActivityManagerProcessStateTest extends InstrumentationTestCase { am.getPackageImportance(CANT_SAVE_STATE_1_PACKAGE_NAME)); uidWatcher.expect(WatchUidRunner.CMD_CACHED, null); - uidWatcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT); + uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT); // While in background, should go in to normal idle state. // Force app to go idle now @@ -1214,6 +1218,7 @@ public class ActivityManagerProcessStateTest extends InstrumentationTestCase { uidWatcher.finish(); uidForegroundListener.unregister(); uidBackgroundListener.unregister(); + uidCachedListener.unregister(); } } @@ -1358,7 +1363,7 @@ public class ActivityManagerProcessStateTest extends InstrumentationTestCase { getInstrumentation().getUiAutomation().performGlobalAction( AccessibilityService.GLOBAL_ACTION_BACK); uid1Watcher.expect(WatchUidRunner.CMD_CACHED, null); - uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT); + uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT); // Make both apps idle for cleanliness. cmd = "am make-uid-idle " + CANT_SAVE_STATE_1_PACKAGE_NAME; diff --git a/tests/autofillservice/res/layout/two_horizontal_text_fields.xml b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml index 773afae6a8e..166e73c0bca 100644 --- a/tests/autofillservice/res/layout/two_horizontal_text_fields.xml +++ b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml @@ -17,28 +17,40 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parent" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" > - <TextView android:id="@+id/static_text" - android:paddingEnd="16dp" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:text="YO:"/> + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> - <TextView android:id="@+id/first" - android:paddingEnd="16dp" - android:layout_width="wrap_content" - android:layout_height="match_parent"/> + <TextView android:id="@+id/static_text" + android:paddingEnd="16dp" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:text="YO:"/> + + <TextView android:id="@+id/first" + android:paddingEnd="16dp" + android:layout_width="wrap_content" + android:layout_height="match_parent"/> - <TextView android:id="@+id/second" - android:layout_weight="1" - android:layout_width="0dp" - android:layout_height="match_parent"/> + <TextView android:id="@+id/second" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="match_parent"/> + </LinearLayout> - <ImageView android:id="@+id/img" - android:paddingStart="16dp" + <LinearLayout android:layout_width="wrap_content" - android:layout_height="match_parent"/> -</LinearLayout>
\ No newline at end of file + android:layout_height="fill_parent"> + + <ImageView android:id="@+id/img" + android:paddingStart="16dp" + android:layout_width="wrap_content" + android:layout_height="match_parent"/> + </LinearLayout> + +</LinearLayout> diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java index 2b5adefdbb5..3120072023d 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java +++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java @@ -841,7 +841,18 @@ final class Helper { @NonNull String serviceName) { if (isAutofillServiceEnabled(serviceName)) return; + // Sets the setting synchronously. Note that the config itself is sets synchronously but + // launch of the service is asynchronous after the config is updated. SettingsHelper.syncSet(context, AUTOFILL_SERVICE, serviceName); + + // Waits until the service is actually enabled. + try { + Timeouts.CONNECTION_TIMEOUT.run("Enabling Autofill service", () -> { + return isAutofillServiceEnabled(serviceName) ? serviceName : null; + }); + } catch (Exception e) { + throw new AssertionError("Enabling Autofill service failed."); + } } /** diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java index c208917abbe..2adb5123966 100644 --- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java +++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java @@ -2210,6 +2210,9 @@ public class LoginActivityTest extends AbstractLoginActivityTestCase { assertTextAndValue(passwordNode, password); waitUntilDisconnected(); + + // Wait and check if the save window is correctly hidden. + mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD); } catch (RetryableException e) { throw new RetryableException(e, "on step %d", i); } catch (Throwable t) { diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java index defc04ac8c5..84a22d74347 100644 --- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java +++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java @@ -68,7 +68,7 @@ public class RobustnessTest extends Camera2AndroidTestCase { private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); private static final int CONFIGURE_TIMEOUT = 5000; //ms - private static final int CAPTURE_TIMEOUT = 1000; //ms + private static final int CAPTURE_TIMEOUT = 1500; //ms // For testTriggerInteractions private static final int PREVIEW_WARMUP_FRAMES = 60; diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java index cf628689f5b..cab08790b46 100644 --- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java +++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmStartOptionsTests.java @@ -89,6 +89,8 @@ public class ActivityManagerAmStartOptionsTests extends ActivityManagerTestBase // See TODO below // final LogSeparator logSeparator = separateLogs(); + mAmWmState.waitForAppTransitionIdle(); + // Pass in different data only when cold starting. This is to make the intent // different in subsequent warm/hot launches, so that the entrypoint alias // activity is always started, but the actual activity is not started again diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java index dbc08b3c351..655d8662fbf 100644 --- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java +++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerSplitScreenTests.java @@ -492,6 +492,7 @@ public class ActivityManagerSplitScreenTests extends ActivityManagerTestBase { TRANSIT_WALLPAPER_OPEN, mAmWmState.getWmState().getLastTransition()); pressHomeButton(); mAmWmState.waitForHomeActivityVisible(); + mAmWmState.waitForAppTransitionIdle(); assertEquals(TRANSIT_WALLPAPER_OPEN, mAmWmState.getWmState().getLastTransition()); } diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java index 192a1ac3548..9ea3825b056 100644 --- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java +++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java @@ -244,7 +244,11 @@ public abstract class ActivityManagerTestBase { pressWakeupButton(); pressUnlockButton(); - pressHomeButton(); + // Using launchHomeActivity to replace pressHomeButton here. + // pressHomeButton will trigger AMS.stopAppSwitches, if we using instrumentation to launch + // test activity, then the activity would be launched after 5 seconds, which may cause some + // tests failed. + launchHomeActivity(); removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME); } @@ -257,7 +261,7 @@ public abstract class ActivityManagerTestBase { executeShellCommand(AM_FORCE_STOP_TEST_PACKAGE); executeShellCommand(AM_FORCE_STOP_SECOND_TEST_PACKAGE); executeShellCommand(AM_FORCE_STOP_THIRD_TEST_PACKAGE); - pressHomeButton(); + launchHomeActivity(); } protected void removeStacksWithActivityTypes(int... activityTypes) { diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml index 5d2f13f871d..2b01af4f936 100644 --- a/tests/signature/api-check/system-annotation/AndroidTest.xml +++ b/tests/signature/api-check/system-annotation/AndroidTest.xml @@ -44,4 +44,8 @@ <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" /> <option name="runtime-hint" value="30s" /> </test> + + <!-- Controller that will skip the module if a native bridge situation is detected --> + <!-- For example: module wants to run arm32 and device is x86 --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" /> </configuration> diff --git a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java index 69f19b9e8d2..b94f9db7924 100644 --- a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java +++ b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java @@ -79,8 +79,9 @@ public class AlarmClockTestBase extends ActivityInstrumentationTestCase2<TestSta private boolean isIntentSupported(TestcaseType testCaseType) { final PackageManager manager = mContext.getPackageManager(); assertNotNull(manager); - // If TV then not supported. - if (manager.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) { + // If TV or Automotive, then not supported. + if (manager.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY) || + manager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { return false; } Intent intent; diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java index 5f391e4b550..357f985b9d6 100644 --- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java +++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.fail; import android.car.Car; import android.car.CarNotConnectedException; import android.car.content.pm.CarPackageManager; +import android.os.Build; import android.platform.test.annotations.RequiresDevice; import android.test.suitebuilder.annotation.SmallTest; @@ -77,6 +78,10 @@ public class CarPackageManagerTest extends CarApiTestBase { @Test public void testDistractionOptimizedActivityIsAllowed() throws CarNotConnectedException { // This test relies on test activity in installed apk, and AndroidManifest declaration. + if (Build.TYPE.equalsIgnoreCase("user")) { + // Skip this test on user build, which checks the install source for DO activity list. + return; + } assertTrue(mCarPm.isActivityDistractionOptimized("android.car.cts", "android.car.cts.drivingstate.DistractionOptimizedActivity")); } @@ -84,6 +89,10 @@ public class CarPackageManagerTest extends CarApiTestBase { @Test public void testNonDistractionOptimizedActivityNotAllowed() throws CarNotConnectedException { // This test relies on test activity in installed apk, and AndroidManifest declaration. + if (Build.TYPE.equalsIgnoreCase("user")) { + // Skip this test on user build, which checks the install source for DO activity list. + return; + } assertFalse(mCarPm.isActivityDistractionOptimized("android.car.cts", "android.car.cts.drivingstate.NonDistractionOptimizedActivity")); } diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java index ee35eedaf50..0a198f2bd96 100644 --- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java +++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java @@ -108,10 +108,8 @@ public class CarrierApiTest extends AndroidTestCase { * Checks whether the cellular stack should be running on this device. */ private boolean hasCellular() { - ConnectivityManager mgr = - (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - return mgr.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) && - mTelephonyManager.isVoiceCapable(); + return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && + mTelephonyManager.getPhoneCount() > 0; } private boolean isSimCardPresent() { diff --git a/tests/tests/graphics/res/raw/f16.png b/tests/tests/graphics/res/raw/f16.png Binary files differnew file mode 100644 index 00000000000..2c3aed258cd --- /dev/null +++ b/tests/tests/graphics/res/raw/f16.png diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java index be5f331caef..ce8f26ad142 100644 --- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java +++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java @@ -1679,7 +1679,7 @@ public class ImageDecoderTest { }; Listener l = new Listener(); SourceCreator f = mCreators[0]; - for (int resId : new int[] { R.drawable.png_test, R.raw.basi6a16 }) { + for (int resId : new int[] { R.drawable.png_test, R.raw.f16 }) { Bitmap normal = null; try { normal = ImageDecoder.decodeBitmap(f.apply(resId)); @@ -1705,7 +1705,7 @@ public class ImageDecoderTest { // We do not support 565 in HARDWARE, so no RAM savings // are possible. assertEquals(normalByteCount, byteCount); - } else { // R.raw.basi6a16 + } else { // R.raw.f16 // This image defaults to F16. MEMORY_POLICY_LOW_RAM // forces "test" to decode to 8888. But if the device // does not support F16 in HARDWARE, "normal" is also @@ -1759,8 +1759,8 @@ public class ImageDecoderTest { // If this were stored in drawable/, it would // be converted from 16-bit to 8. FIXME: Is // behavior still desirable now that we have - // F16? - R.raw.basi6a16 }; + // F16? b/119760146 + R.raw.f16 }; // An opaque image can be converted to 565, but postProcess will promote // to 8888 in case alpha is added. The third image defaults to F16, so // even with postProcess it will only be promoted to 8888. diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java index 089f9144095..88c5c3a6a96 100644 --- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java +++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java @@ -37,7 +37,9 @@ import android.media.MicrophoneInfo; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.SystemClock; +import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.Log; @@ -1492,24 +1494,55 @@ public class AudioRecordTest { } private static void makeMyUidStateActive() throws IOException { - final String command = "cmd media.audio_policy set-uid-state " - + InstrumentationRegistry.getTargetContext().getPackageName() + " active"; + String command = String.format("cmd media.audio_policy set-uid-state %s active", + getContext().getPackageName()); + + if (!isSystemUser()) { + // --user parameter is not supported on all devices - only those that will run CTS in + // secondary users. + // For System User - Command defaults to system user, no need to explicitly specify. + // For Secondary User - Have to specify the user explicitly, otherwise the test fails. + command += " --user " + Process.myUserHandle().getIdentifier(); + } + SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); } private static void makeMyUidStateIdle() throws IOException { - final String command = "cmd media.audio_policy set-uid-state " - + InstrumentationRegistry.getTargetContext().getPackageName() + " idle"; + String command = String.format("cmd media.audio_policy set-uid-state %s idle", + getContext().getPackageName()); + + if (!isSystemUser()) { + // --user parameter is not supported on all devices - only those that will run CTS in + // secondary users. + // For System User - Command defaults to system user, no need to explicitly specify. + // For Secondary User - Have to specify the user explicitly, otherwise the test fails. + command += " --user " + Process.myUserHandle().getIdentifier(); + } + SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); } private static void resetMyUidState() throws IOException { - final String command = "cmd media.audio_policy reset-uid-state " - + InstrumentationRegistry.getTargetContext().getPackageName(); + String command = "cmd media.audio_policy reset-uid-state " + + getContext().getPackageName(); + + if (!isSystemUser()) { + // --user parameter is not supported on all devices - only those that will run CTS in + // secondary users. + // For System User - Command defaults to system user, no need to explicitly specify. + // For Secondary User - Have to specify the user explicitly, otherwise the test fails. + command += " --user " + Process.myUserHandle().getIdentifier(); + } + SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command); } private static Context getContext() { return InstrumentationRegistry.getInstrumentation().getTargetContext(); } + + private static boolean isSystemUser() { + return getContext().getSystemService(UserManager.class).isSystemUser(); + } } diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java index 311c7914912..c08511774fb 100644 --- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java +++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java @@ -306,6 +306,11 @@ public class MediaCodecListTest extends AndroidTestCase { && !pm.hasSystemFeature(pm.FEATURE_TELEVISION); } + private boolean isAutomotive() { + PackageManager pm = getContext().getPackageManager(); + return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE); + } + // Find whether the given codec can be found using MediaCodecList.find methods. private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) { String codecName = isEncoder @@ -399,7 +404,11 @@ public class MediaCodecListTest extends AndroidTestCase { list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false)); // vp8 decoder list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true)); // vp8 encoder list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false)); // vp9 decoder - list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder + + //According to CDD, hevc decoding is not mandatory for automotive devices + if (!isAutomotive()) { + list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder + } list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false)); // h263 decoder if (hasCamera()) { diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java index 0b075e2e3c3..b5003759e72 100644 --- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java +++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java @@ -482,6 +482,12 @@ public class MediaMuxerTest extends AndroidTestCase { // parsing String location and recover the location information in floats // Make sure the tolerance is very small - due to rounding errors. + // Trim the trailing slash, if any. + int lastIndex = location.lastIndexOf('/'); + if (lastIndex != -1) { + location = location.substring(0, lastIndex); + } + // Get the position of the -/+ sign in location String, which indicates // the beginning of the longitude. int minusIndex = location.lastIndexOf('-'); @@ -491,12 +497,8 @@ public class MediaMuxerTest extends AndroidTestCase { (minusIndex > 0 || plusIndex > 0)); int index = Math.max(minusIndex, plusIndex); - float latitude = Float.parseFloat(location.substring(0, index - 1)); - int lastIndex = location.lastIndexOf('/', index); - if (lastIndex == -1) { - lastIndex = location.length(); - } - float longitude = Float.parseFloat(location.substring(index, lastIndex - 1)); + float latitude = Float.parseFloat(location.substring(0, index)); + float longitude = Float.parseFloat(location.substring(index)); assertTrue("Incorrect latitude: " + latitude + " [" + location + "]", Math.abs(latitude - LATITUDE) <= TOLERANCE); assertTrue("Incorrect longitude: " + longitude + " [" + location + "]", diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTest.java b/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTest.java deleted file mode 100644 index 56a4ed6ec0f..00000000000 --- a/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2018 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.media.cts; - -import android.Manifest; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.platform.test.annotations.AppModeFull; - -import androidx.test.filters.LargeTest; -import androidx.test.filters.SdkSuppress; -import androidx.test.rule.GrantPermissionRule; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.File; - -/** - * Tests for the MediaPlayer2 API and local video/audio playback. - * - * The files in res/raw used by testLocalVideo* are (c) copyright 2008, - * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons - * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/. - */ -@LargeTest -@RunWith(AndroidJUnit4.class) -@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P) -@AppModeFull(reason = "Instant apps cannot hold READ/WRITE_EXTERNAL_STORAGE") -public class MediaPlayer2DrmTest extends MediaPlayer2DrmTestBase { - - private static final String LOG_TAG = "MediaPlayer2DrmTest"; - - @Rule - public GrantPermissionRule mRuntimePermissionRule = - GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE); - - @Before - @Override - public void setUp() throws Throwable { - super.setUp(); - } - - @After - @Override - public void tearDown() throws Throwable { - super.tearDown(); - } - - - ////////////////////////////////////////////////////////////////////////////////////////////// - // Asset helpers - - private static Uri getUriFromFile(String path) { - return Uri.fromFile(new File(getDownloadedPath(path))); - } - - private static String getDownloadedPath(String fileName) { - return getDownloadedFolder() + File.separator + fileName; - } - - private static String getDownloadedFolder() { - return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_DOWNLOADS).getPath(); - } - - private static final class Resolution { - public final boolean isHD; - public final int width; - public final int height; - - Resolution(boolean isHD, int width, int height) { - this.isHD = isHD; - this.width = width; - this.height = height; - } - } - - private static final Resolution RES_720P = new Resolution(true, 1280, 720); - private static final Resolution RES_AUDIO = new Resolution(false, 0, 0); - - - // Assets - - private static final Uri CENC_AUDIO_URL = Uri.parse( - "https://storage.googleapis.com/wvmedia/cenc/clearkey/car_cenc-20120827-8c-pssh.mp4"); - private static final Uri CENC_AUDIO_URL_DOWNLOADED = getUriFromFile("car_cenc-20120827-8c.mp4"); - - private static final Uri CENC_VIDEO_URL = Uri.parse( - "https://storage.googleapis.com/wvmedia/cenc/clearkey/car_cenc-20120827-88-pssh.mp4"); - private static final Uri CENC_VIDEO_URL_DOWNLOADED = getUriFromFile("car_cenc-20120827-88.mp4"); - - - // Tests - - @Test - @LargeTest - public void testCAR_CLEARKEY_AUDIO_DOWNLOADED_V0_SYNC() throws Exception { - download(CENC_AUDIO_URL, - CENC_AUDIO_URL_DOWNLOADED, - RES_AUDIO, - ModularDrmTestType.V0_SYNC_TEST); - } - - @Test - @LargeTest - public void testCAR_CLEARKEY_AUDIO_DOWNLOADED_V1_ASYNC() throws Exception { - download(CENC_AUDIO_URL, - CENC_AUDIO_URL_DOWNLOADED, - RES_AUDIO, - ModularDrmTestType.V1_ASYNC_TEST); - } - - @Test - @LargeTest - public void testCAR_CLEARKEY_AUDIO_DOWNLOADED_V2_SYNC_CONFIG() throws Exception { - download(CENC_AUDIO_URL, - CENC_AUDIO_URL_DOWNLOADED, - RES_AUDIO, - ModularDrmTestType.V2_SYNC_CONFIG_TEST); - } - - @Test - @LargeTest - public void testCAR_CLEARKEY_AUDIO_DOWNLOADED_V3_ASYNC_DRMPREPARED() throws Exception { - download(CENC_AUDIO_URL, - CENC_AUDIO_URL_DOWNLOADED, - RES_AUDIO, - ModularDrmTestType.V3_ASYNC_DRMPREPARED_TEST); - } - - // helpers - - private void stream(Uri uri, Resolution res, ModularDrmTestType testType) throws Exception { - playModularDrmVideo(uri, res.width, res.height, testType); - } - - private void download(Uri remote, Uri local, Resolution res, ModularDrmTestType testType) - throws Exception { - playModularDrmVideoDownload(remote, local, res.width, res.height, testType); - } - -} diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTestBase.java deleted file mode 100644 index d8d5cb8ef0b..00000000000 --- a/tests/tests/media/src/android/media/cts/MediaPlayer2DrmTestBase.java +++ /dev/null @@ -1,1019 +0,0 @@ -/* - * Copyright 2018 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.media.cts; - -import static android.content.Context.KEYGUARD_SERVICE; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import android.app.DownloadManager; -import android.app.DownloadManager.Request; -import android.app.Instrumentation; -import android.app.KeyguardManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.media.MediaDrm; -import android.media.ResourceBusyException; -import android.media.UnsupportedSchemeException; -import android.media.cts.TestUtils.Monitor; -import android.net.Uri; -import android.os.PowerManager; -import android.os.SystemClock; -import android.util.Base64; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.WindowManager; - -import androidx.annotation.CallSuper; -import androidx.media.DataSourceDesc; -import androidx.media.MediaPlayer2; -import androidx.media.MediaPlayer2.DrmInfo; -import androidx.test.InstrumentationRegistry; -import androidx.test.rule.ActivityTestRule; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.UUID; -import java.util.Vector; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Base class for DRM tests which use MediaPlayer2 to play audio or video. - */ -public class MediaPlayer2DrmTestBase { - protected static final int STREAM_RETRIES = 3; - - protected Monitor mSetDataSourceCallCompleted = new Monitor(); - protected Monitor mOnPreparedCalled = new Monitor(); - protected Monitor mOnVideoSizeChangedCalled = new Monitor(); - protected Monitor mOnPlaybackCompleted = new Monitor(); - protected Monitor mOnDrmInfoCalled = new Monitor(); - protected Monitor mOnDrmPreparedCalled = new Monitor(); - protected int mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - - protected Context mContext; - protected Resources mResources; - - protected MediaPlayer2 mPlayer = null; - protected MediaStubActivity mActivity; - protected Instrumentation mInstrumentation; - - protected ExecutorService mExecutor; - protected MediaPlayer2.EventCallback mECb = null; - - @Rule - public ActivityTestRule<MediaStubActivity> mActivityRule = - new ActivityTestRule<>(MediaStubActivity.class); - public PowerManager.WakeLock mScreenLock; - private KeyguardManager mKeyguardManager; - - @Before - @CallSuper - public void setUp() throws Throwable { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mKeyguardManager = (KeyguardManager) - mInstrumentation.getTargetContext().getSystemService(KEYGUARD_SERVICE); - mActivity = mActivityRule.getActivity(); - mActivityRule.runOnUiThread(new Runnable() { - @Override - public void run() { - // Keep screen on while testing. - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mActivity.setTurnScreenOn(true); - mActivity.setShowWhenLocked(true); - mKeyguardManager.requestDismissKeyguard(mActivity, null); - } - }); - mInstrumentation.waitForIdleSync(); - - try { - mActivityRule.runOnUiThread(new Runnable() { - public void run() { - mPlayer = MediaPlayer2.create(); - } - }); - } catch (Throwable e) { - e.printStackTrace(); - fail(); - } - - mContext = mInstrumentation.getTargetContext(); - mResources = mContext.getResources(); - - mExecutor = Executors.newFixedThreadPool(1); - } - - @After - @CallSuper - public void tearDown() throws Throwable { - if (mPlayer != null) { - mPlayer.close(); - mPlayer = null; - } - mExecutor.shutdown(); - mActivity = null; - } - - private static class PrepareFailedException extends Exception {} - - ////////////////////////////////////////////////////////////////////////////////////////// - // Modular DRM - - private static final String TAG = "MediaPlayer2DrmTestBase"; - - protected static final int PLAY_TIME_MS = 60 * 1000; - protected byte[] mKeySetId; - protected boolean mAudioOnly; - - private static final byte[] CLEAR_KEY_CENC = { - (byte) 0x1a, (byte) 0x8a, (byte) 0x20, (byte) 0x95, - (byte) 0xe4, (byte) 0xde, (byte) 0xb2, (byte) 0xd2, - (byte) 0x9e, (byte) 0xc8, (byte) 0x16, (byte) 0xac, - (byte) 0x7b, (byte) 0xae, (byte) 0x20, (byte) 0x82 - }; - - private static final UUID CLEARKEY_SCHEME_UUID = - new UUID(0x1077efecc0b24d02L, 0xace33c1e52e2fb4bL); - - final byte[] mClearKeyPssh = hexStringToByteArray( - "0000003470737368" // BMFF box header (4 bytes size + 'pssh') - + "01000000" // Full box header (version = 1 flags = 0) - + "1077efecc0b24d02" // SystemID - + "ace33c1e52e2fb4b" - + "00000001" // Number of key ids - + "60061e017e477e87" // Key id - + "7e57d00d1ed00d1e" - + "00000000" // Size of Data, must be zero - ); - - - protected enum ModularDrmTestType { - V0_SYNC_TEST, - V1_ASYNC_TEST, - V2_SYNC_CONFIG_TEST, - V3_ASYNC_DRMPREPARED_TEST, - V4_SYNC_OFFLINE_KEY, - } - - // TODO: After living on these tests for a while, we can consider grouping them based on - // the asset such that each asset is downloaded once and played back with multiple tests. - protected void playModularDrmVideoDownload(Uri uri, Uri path, int width, int height, - ModularDrmTestType testType) throws Exception { - final long downloadTimeOutSeconds = 600; - Log.i(TAG, "Downloading file:" + path); - MediaDownloadManager mediaDownloadManager = new MediaDownloadManager(mContext); - final long id = mediaDownloadManager.downloadFileWithRetries( - uri, path, downloadTimeOutSeconds, STREAM_RETRIES); - assertFalse("Download " + uri + " failed.", id == -1); - Uri file = mediaDownloadManager.getUriForDownloadedFile(id); - Log.i(TAG, "Downloaded file:" + path + " id:" + id + " uri:" + file); - - try { - playModularDrmVideo(file, width, height, testType); - } finally { - mediaDownloadManager.removeFile(id); - } - } - - protected void playModularDrmVideo(Uri uri, int width, int height, - ModularDrmTestType testType) throws Exception { - // Force gc for a clean start - System.gc(); - - playModularDrmVideoWithRetries(uri, width, height, PLAY_TIME_MS, testType); - } - - protected void playModularDrmVideoWithRetries(Uri file, Integer width, Integer height, - int playTime, ModularDrmTestType testType) throws Exception { - - // first the synchronous variation - boolean playedSuccessfully = false; - for (int i = 0; i < STREAM_RETRIES; i++) { - try { - Log.v(TAG, "playVideoWithRetries(" + testType + ") try " + i); - playLoadedModularDrmVideo(file, width, height, playTime, testType); - - playedSuccessfully = true; - break; - } catch (PrepareFailedException e) { - // we can fail because of network issues, so try again - Log.w(TAG, "playVideoWithRetries(" + testType + ") failed on try " + i - + ", trying playback again"); - mPlayer.reset(); - } - } - assertTrue("Stream did not play successfully after all attempts (syncDrmSetup)", - playedSuccessfully); - } - - /** - * Play a video which has already been loaded with setDataSource(). - * The DRM setup is performed synchronously. - * - * @param file data source - * @param width width of the video to verify, or null to skip verification - * @param height height of the video to verify, or null to skip verification - * @param playTime length of time to play video, or 0 to play entire video - * @param testType test type - */ - private void playLoadedModularDrmVideo(final Uri file, final Integer width, - final Integer height, int playTime, ModularDrmTestType testType) throws Exception { - - switch (testType) { - case V0_SYNC_TEST: - case V1_ASYNC_TEST: - case V2_SYNC_CONFIG_TEST: - case V3_ASYNC_DRMPREPARED_TEST: - playLoadedModularDrmVideo_Generic(file, width, height, playTime, testType); - break; - - case V4_SYNC_OFFLINE_KEY: - playLoadedModularDrmVideo_V4_offlineKey(file, width, height, playTime); - break; - } - } - - private void playLoadedModularDrmVideo_Generic(final Uri file, final Integer width, - final Integer height, int playTime, ModularDrmTestType testType) throws Exception { - - final float volume = 0.5f; - - mAudioOnly = (width == 0); - - mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - mECb = new MediaPlayer2.EventCallback() { - @Override - public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, int w, int h) { - Log.v(TAG, "VideoSizeChanged" + " w:" + w + " h:" + h); - mOnVideoSizeChangedCalled.signal(); - } - - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - fail("Media player had error " + what + " playing video"); - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPreparedCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - Log.v(TAG, "playLoadedVideo: onInfo_PlaybackComplete"); - mOnPlaybackCompleted.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { - mCallStatus = status; - mSetDataSourceCallCompleted.signal(); - } - } - }; - - mPlayer.setEventCallback(mExecutor, mECb); - Log.v(TAG, "playLoadedVideo: setDataSource()"); - mPlayer.setDataSource(new DataSourceDesc.Builder().setDataSource(mContext, file).build()); - mSetDataSourceCallCompleted.waitForSignal(); - if (mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR) { - throw new PrepareFailedException(); - } - - SurfaceHolder surfaceHolder = mActivity.getSurfaceHolder(); - surfaceHolder.setKeepScreenOn(true); - mPlayer.setSurface(surfaceHolder.getSurface()); - - try { - switch (testType) { - case V0_SYNC_TEST: - preparePlayerAndDrm_V0_syncDrmSetup(); - break; - - case V1_ASYNC_TEST: - preparePlayerAndDrm_V1_asyncDrmSetup(); - break; - - case V2_SYNC_CONFIG_TEST: - preparePlayerAndDrm_V2_syncDrmSetupPlusConfig(); - break; - - case V3_ASYNC_DRMPREPARED_TEST: - preparePlayerAndDrm_V3_asyncDrmSetupPlusDrmPreparedListener(); - break; - } - - } catch (IOException e) { - e.printStackTrace(); - throw new PrepareFailedException(); - } - - Log.v(TAG, "playLoadedVideo: play()"); - mPlayer.play(); - if (!mAudioOnly) { - mOnVideoSizeChangedCalled.waitForSignal(); - } - mPlayer.setPlayerVolume(volume); - - // waiting to complete - if (playTime == 0) { - Log.v(TAG, "playLoadedVideo: waiting for playback completion"); - mOnPlaybackCompleted.waitForSignal(); - } else { - Log.v(TAG, "playLoadedVideo: waiting while playing for " + playTime); - mOnPlaybackCompleted.waitForSignal(playTime); - } - - try { - Log.v(TAG, "playLoadedVideo: releaseDrm"); - mPlayer.releaseDrm(); - } catch (Exception e) { - e.printStackTrace(); - throw new PrepareFailedException(); - } - } - - private void preparePlayerAndDrm_V0_syncDrmSetup() throws Exception { - Log.v(TAG, "preparePlayerAndDrm_V0: calling prepare()"); - mPlayer.prepare(); - mOnPreparedCalled.waitForSignal(); - if (mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR) { - throw new IOException(); - } - - DrmInfo drmInfo = mPlayer.getDrmInfo(); - if (drmInfo != null) { - setupDrm(drmInfo, true /* prepareDrm */, true /* synchronousNetworking */, - MediaDrm.KEY_TYPE_STREAMING); - Log.v(TAG, "preparePlayerAndDrm_V0: setupDrm done!"); - } - } - - private void preparePlayerAndDrm_V1_asyncDrmSetup() throws InterruptedException { - final AtomicBoolean asyncSetupDrmError = new AtomicBoolean(false); - - mPlayer.setDrmEventCallback(mExecutor, new MediaPlayer2.DrmEventCallback() { - @Override - public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { - Log.v(TAG, "preparePlayerAndDrm_V1: onDrmInfo" + drmInfo); - - // in the callback (async mode) so handling exceptions here - try { - setupDrm(drmInfo, true /* prepareDrm */, true /* synchronousNetworking */, - MediaDrm.KEY_TYPE_STREAMING); - } catch (Exception e) { - Log.v(TAG, "preparePlayerAndDrm_V1: setupDrm EXCEPTION " + e); - asyncSetupDrmError.set(true); - } - - mOnDrmInfoCalled.signal(); - Log.v(TAG, "preparePlayerAndDrm_V1: onDrmInfo done!"); - } - }); - - Log.v(TAG, "preparePlayerAndDrm_V1: calling prepare()"); - mPlayer.prepare(); - - mOnDrmInfoCalled.waitForSignal(); - - // Waiting till the player is prepared - mOnPreparedCalled.waitForSignal(); - - // to handle setupDrm error (async) in the main thread rather than the callback - if (asyncSetupDrmError.get()) { - fail("preparePlayerAndDrm_V1: setupDrm"); - } - } - - private void preparePlayerAndDrm_V2_syncDrmSetupPlusConfig() throws Exception { - mPlayer.setOnDrmConfigHelper(new MediaPlayer2.OnDrmConfigHelper() { - @Override - public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd) { - String widevineSecurityLevel3 = "L3"; - String securityLevelProperty = "securityLevel"; - - try { - String level = mp.getDrmPropertyString(securityLevelProperty); - Log.v(TAG, "preparePlayerAndDrm_V2: getDrmPropertyString: " - + securityLevelProperty + " -> " + level); - mp.setDrmPropertyString(securityLevelProperty, widevineSecurityLevel3); - level = mp.getDrmPropertyString(securityLevelProperty); - Log.v(TAG, "preparePlayerAndDrm_V2: getDrmPropertyString: " - + securityLevelProperty + " -> " + level); - } catch (MediaPlayer2.NoDrmSchemeException e) { - Log.v(TAG, "preparePlayerAndDrm_V2: NoDrmSchemeException"); - } catch (Exception e) { - Log.v(TAG, "preparePlayerAndDrm_V2: onDrmConfig EXCEPTION " + e); - } - } - }); - - Log.v(TAG, "preparePlayerAndDrm_V2: calling prepare()"); - mPlayer.prepare(); - - mOnPreparedCalled.waitForSignal(); - if (mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR) { - throw new IOException(); - } - - DrmInfo drmInfo = mPlayer.getDrmInfo(); - if (drmInfo != null) { - setupDrm(drmInfo, true /* prepareDrm */, true /* synchronousNetworking */, - MediaDrm.KEY_TYPE_STREAMING); - Log.v(TAG, "preparePlayerAndDrm_V2: setupDrm done!"); - } - } - - private void preparePlayerAndDrm_V3_asyncDrmSetupPlusDrmPreparedListener() - throws InterruptedException { - final AtomicBoolean asyncSetupDrmError = new AtomicBoolean(false); - - mPlayer.setDrmEventCallback(mExecutor, new MediaPlayer2.DrmEventCallback() { - @Override - public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmInfo" + drmInfo); - - // DRM preperation - List<UUID> supportedSchemes = drmInfo.getSupportedSchemes(); - if (supportedSchemes.isEmpty()) { - Log.e(TAG, "preparePlayerAndDrm_V3: onDrmInfo: No supportedSchemes"); - asyncSetupDrmError.set(true); - mOnDrmInfoCalled.signal(); - // we won't call prepareDrm anymore but need to get passed the wait - mOnDrmPreparedCalled.signal(); - return; - } - - // setting up with the first supported UUID - // instead of supportedSchemes[0] in GTS - UUID drmScheme = CLEARKEY_SCHEME_UUID; - Log.d(TAG, "preparePlayerAndDrm_V3: onDrmInfo: selected " + drmScheme); - - try { - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmInfo: calling prepareDrm"); - mp.prepareDrm(drmScheme); - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmInfo: called prepareDrm"); - } catch (Exception e) { - e.printStackTrace(); - Log.e(TAG, "preparePlayerAndDrm_V3: onDrmInfo: prepareDrm exception " + e); - asyncSetupDrmError.set(true); - mOnDrmInfoCalled.signal(); - // need to get passed the wait - mOnDrmPreparedCalled.signal(); - return; - } - - mOnDrmInfoCalled.signal(); - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmInfo done!"); - } - - @Override - public void onDrmPrepared(MediaPlayer2 mp, DataSourceDesc dsd, int status) { - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmPrepared status: " + status); - - assertTrue("preparePlayerAndDrm_V3: onDrmPrepared did not succeed", - status == MediaPlayer2.PREPARE_DRM_STATUS_SUCCESS); - - DrmInfo drmInfo = mPlayer.getDrmInfo(); - - // in the callback (async mode) so handling exceptions here - try { - setupDrm(drmInfo, false /* prepareDrm */, true /* synchronousNetworking */, - MediaDrm.KEY_TYPE_STREAMING); - } catch (Exception e) { - Log.v(TAG, "preparePlayerAndDrm_V3: setupDrm EXCEPTION " + e); - asyncSetupDrmError.set(true); - } - - mOnDrmPreparedCalled.signal(); - Log.v(TAG, "preparePlayerAndDrm_V3: onDrmPrepared done!"); - } - }); - - Log.v(TAG, "preparePlayerAndDrm_V3: calling prepare()"); - mPlayer.prepare(); - - // Waiting till the player is prepared - mOnPreparedCalled.waitForSignal(); - - // Unlike v3, onDrmPrepared is not synced to onPrepared b/c of its own thread handler - mOnDrmPreparedCalled.waitForSignal(); - - // to handle setupDrm error (async) in the main thread rather than the callback - if (asyncSetupDrmError.get()) { - fail("preparePlayerAndDrm_V3: setupDrm"); - } - } - - private void playLoadedModularDrmVideo_V4_offlineKey(final Uri file, final Integer width, - final Integer height, int playTime) throws Exception { - final float volume = 0.5f; - - mAudioOnly = (width == 0); - - SurfaceHolder surfaceHolder = mActivity.getSurfaceHolder(); - Log.v(TAG, "playLoadedModularDrmVideo_V4_offlineKey: setSurface " + surfaceHolder); - mPlayer.setSurface(surfaceHolder.getSurface()); - surfaceHolder.setKeepScreenOn(true); - - mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - DrmInfo drmInfo = null; - - for (int round = 0; round < 2; round++) { - boolean keyRequestRound = (round == 0); - boolean restoreRound = (round == 1); - Log.v(TAG, "playLoadedVideo: round " + round); - - try { - mPlayer.setEventCallback(mExecutor, mECb); - - Log.v(TAG, "playLoadedVideo: setDataSource()"); - mPlayer.setDataSource( - new DataSourceDesc.Builder().setDataSource(mContext, file).build()); - - Log.v(TAG, "playLoadedVideo: prepare()"); - mPlayer.prepare(); - mOnPreparedCalled.waitForSignal(); - - // but preparing the DRM every time with proper key request type - drmInfo = mPlayer.getDrmInfo(); - if (drmInfo != null) { - if (keyRequestRound) { - // asking for offline keys - setupDrm(drmInfo, true /* prepareDrm */, true /* synchronousNetworking */, - MediaDrm.KEY_TYPE_OFFLINE); - } else if (restoreRound) { - setupDrmRestore(drmInfo, true /* prepareDrm */); - } else { - fail("preparePlayer: unexpected round " + round); - } - Log.v(TAG, "preparePlayer: setupDrm done!"); - } - - } catch (IOException e) { - e.printStackTrace(); - throw new PrepareFailedException(); - } - - Log.v(TAG, "playLoadedVideo: play()"); - mPlayer.play(); - if (!mAudioOnly) { - mOnVideoSizeChangedCalled.waitForSignal(); - } - mPlayer.setPlayerVolume(volume); - - // waiting to complete - if (playTime == 0) { - Log.v(TAG, "playLoadedVideo: waiting for playback completion"); - mOnPlaybackCompleted.waitForSignal(); - } else { - Log.v(TAG, "playLoadedVideo: waiting while playing for " + playTime); - mOnPlaybackCompleted.waitForSignal(playTime); - } - - try { - if (drmInfo != null) { - if (restoreRound) { - // releasing the offline key - setupDrm(null /* drmInfo */, false /* prepareDrm */, - true /* synchronousNetworking */, MediaDrm.KEY_TYPE_RELEASE); - Log.v(TAG, "playLoadedVideo: released offline keys"); - } - - Log.v(TAG, "playLoadedVideo: releaseDrm"); - mPlayer.releaseDrm(); - } - } catch (Exception e) { - e.printStackTrace(); - throw new PrepareFailedException(); - } - - if (keyRequestRound) { - mOnPreparedCalled.reset(); - mOnVideoSizeChangedCalled.reset(); - mOnPlaybackCompleted.reset(); - final int sleepBetweenRounds = 1000; - Thread.sleep(sleepBetweenRounds); - - Log.v(TAG, "playLoadedVideo: reset"); - mPlayer.reset(); - } - } // for - } - - // Converts a BMFF PSSH initData to a raw cenc initData - protected byte[] makeCencPSSH(UUID uuid, byte[] bmffPsshData) { - byte[] pssh_header = new byte[] { (byte) 'p', (byte) 's', (byte) 's', (byte) 'h' }; - byte[] pssh_version = new byte[] { 1, 0, 0, 0 }; - int boxSizeByteCount = 4; - int uuidByteCount = 16; - int dataSizeByteCount = 4; - // Per "W3C cenc Initialization Data Format" document: - // box size + 'pssh' + version + uuid + payload + size of data - int boxSize = boxSizeByteCount + pssh_header.length + pssh_version.length - + uuidByteCount + bmffPsshData.length + dataSizeByteCount; - int dataSize = 0; - - // the default write is big-endian, i.e., network byte order - ByteBuffer rawPssh = ByteBuffer.allocate(boxSize); - rawPssh.putInt(boxSize); - rawPssh.put(pssh_header); - rawPssh.put(pssh_version); - rawPssh.putLong(uuid.getMostSignificantBits()); - rawPssh.putLong(uuid.getLeastSignificantBits()); - rawPssh.put(bmffPsshData); - rawPssh.putInt(dataSize); - - return rawPssh.array(); - } - - /* - * Sets up the DRM for the first DRM scheme from the supported list. - * - * @param drmInfo DRM info of the source - * @param prepareDrm whether prepareDrm should be called - * @param synchronousNetworking whether the network operation of key request/response will - * be performed synchronously - */ - private void setupDrm(DrmInfo drmInfo, boolean prepareDrm, boolean synchronousNetworking, - int keyType) throws Exception { - Log.d(TAG, "setupDrm: drmInfo: " + drmInfo + " prepareDrm: " + prepareDrm - + " synchronousNetworking: " + synchronousNetworking); - try { - byte[] initData = null; - String mime = null; - String keyTypeStr = "Unexpected"; - - switch (keyType) { - case MediaDrm.KEY_TYPE_STREAMING: - case MediaDrm.KEY_TYPE_OFFLINE: - // DRM preparation - List<UUID> supportedSchemes = drmInfo.getSupportedSchemes(); - if (supportedSchemes.isEmpty()) { - fail("setupDrm: No supportedSchemes"); - } - - // instead of supportedSchemes[0] in GTS - UUID drmScheme = CLEARKEY_SCHEME_UUID; - Log.d(TAG, "setupDrm: selected " + drmScheme); - - if (prepareDrm) { - mPlayer.prepareDrm(drmScheme); - } - - byte[] psshData = drmInfo.getPssh().get(drmScheme); - // diverging from GTS - if (psshData == null) { - initData = mClearKeyPssh; - Log.d(TAG, "setupDrm: CLEARKEY scheme not found in PSSH." - + " Using default data."); - } else { - // Can skip conversion if ClearKey adds support for BMFF initData b/64863112 - initData = makeCencPSSH(CLEARKEY_SCHEME_UUID, psshData); - } - Log.d(TAG, "setupDrm: initData[" + drmScheme + "]: " - + Arrays.toString(initData)); - - // diverging from GTS - mime = "cenc"; - - keyTypeStr = (keyType == MediaDrm.KEY_TYPE_STREAMING) - ? "KEY_TYPE_STREAMING" : "KEY_TYPE_OFFLINE"; - break; - - case MediaDrm.KEY_TYPE_RELEASE: - if (mKeySetId == null) { - fail("setupDrm: KEY_TYPE_RELEASE requires a valid keySetId."); - } - keyTypeStr = "KEY_TYPE_RELEASE"; - break; - - default: - fail("setupDrm: Unexpected keyType " + keyType); - } - - final MediaDrm.KeyRequest request = mPlayer.getDrmKeyRequest( - (keyType == MediaDrm.KEY_TYPE_RELEASE) ? mKeySetId : null, - initData, - mime, - keyType, - null /* optionalKeyRequestParameters */ - ); - - Log.d(TAG, "setupDrm: mPlayer.getDrmKeyRequest(" + keyTypeStr - + ") request -> " + request); - - // diverging from GTS - byte[][] clearKeys = new byte[][] { CLEAR_KEY_CENC }; - byte[] response = createKeysResponse(request, clearKeys); - - // null is returned when the response is for a streaming or release request. - byte[] keySetId = mPlayer.provideDrmKeyResponse( - (keyType == MediaDrm.KEY_TYPE_RELEASE) ? mKeySetId : null, - response); - Log.d(TAG, "setupDrm: provideDrmKeyResponse -> " + Arrays.toString(keySetId)); - // storing offline key for a later restore - mKeySetId = (keyType == MediaDrm.KEY_TYPE_OFFLINE) ? keySetId : null; - - } catch (MediaPlayer2.NoDrmSchemeException e) { - Log.d(TAG, "setupDrm: NoDrmSchemeException"); - e.printStackTrace(); - throw e; - } catch (MediaPlayer2.ProvisioningNetworkErrorException e) { - Log.d(TAG, "setupDrm: ProvisioningNetworkErrorException"); - e.printStackTrace(); - throw e; - } catch (MediaPlayer2.ProvisioningServerErrorException e) { - Log.d(TAG, "setupDrm: ProvisioningServerErrorException"); - e.printStackTrace(); - throw e; - } catch (UnsupportedSchemeException e) { - Log.d(TAG, "setupDrm: UnsupportedSchemeException"); - e.printStackTrace(); - throw e; - } catch (ResourceBusyException e) { - Log.d(TAG, "setupDrm: ResourceBusyException"); - e.printStackTrace(); - throw e; - } catch (Exception e) { - Log.d(TAG, "setupDrm: Exception " + e); - e.printStackTrace(); - throw e; - } - } // setupDrm - - private void setupDrmRestore(DrmInfo drmInfo, boolean prepareDrm) throws Exception { - Log.d(TAG, "setupDrmRestore: drmInfo: " + drmInfo + " prepareDrm: " + prepareDrm); - try { - if (prepareDrm) { - // DRM preparation - List<UUID> supportedSchemes = drmInfo.getSupportedSchemes(); - if (supportedSchemes.isEmpty()) { - fail("setupDrmRestore: No supportedSchemes"); - } - - // instead of supportedSchemes[0] in GTS - UUID drmScheme = CLEARKEY_SCHEME_UUID; - Log.d(TAG, "setupDrmRestore: selected " + drmScheme); - - mPlayer.prepareDrm(drmScheme); - } - - if (mKeySetId == null) { - fail("setupDrmRestore: Offline key has not been setup."); - } - - mPlayer.restoreDrmKeys(mKeySetId); - - } catch (MediaPlayer2.NoDrmSchemeException e) { - Log.v(TAG, "setupDrmRestore: NoDrmSchemeException"); - e.printStackTrace(); - throw e; - } catch (Exception e) { - Log.v(TAG, "setupDrmRestore: Exception " + e); - e.printStackTrace(); - throw e; - } - } // setupDrmRestore - - ////////////////////////////////////////////////////////////////////////////////////////////// - // Diverging from GTS - - // Clearkey helpers - - /** - * Convert a hex string into byte array. - */ - private static byte[] hexStringToByteArray(String s) { - int len = s.length(); - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) - + Character.digit(s.charAt(i + 1), 16)); - } - return data; - } - - /** - * Extracts key ids from the pssh blob returned by getDrmKeyRequest() and - * places it in keyIds. - * keyRequestBlob format (section 5.1.3.1): - * https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html - * - * @return size of keyIds vector that contains the key ids, 0 for error - */ - private int getKeyIds(byte[] keyRequestBlob, Vector<String> keyIds) { - if (0 == keyRequestBlob.length || keyIds == null) { - Log.e(TAG, "getKeyIds: Empty keyRequestBlob or null keyIds."); - return 0; - } - - String jsonLicenseRequest = new String(keyRequestBlob); - keyIds.clear(); - - try { - JSONObject license = new JSONObject(jsonLicenseRequest); - Log.v(TAG, "getKeyIds: license: " + license); - final JSONArray ids = license.getJSONArray("kids"); - Log.v(TAG, "getKeyIds: ids: " + ids); - for (int i = 0; i < ids.length(); ++i) { - keyIds.add(ids.getString(i)); - } - } catch (JSONException e) { - Log.e(TAG, "Invalid JSON license = " + jsonLicenseRequest); - return 0; - } - return keyIds.size(); - } - - /** - * Creates the JSON Web Key string. - * - * @return JSON Web Key string. - */ - private String createJsonWebKeySet(Vector<String> keyIds, Vector<String> keys) { - String jwkSet = "{\"keys\":["; - for (int i = 0; i < keyIds.size(); ++i) { - String id = new String(keyIds.get(i).getBytes(Charset.forName("UTF-8"))); - String key = new String(keys.get(i).getBytes(Charset.forName("UTF-8"))); - - jwkSet += "{\"kty\":\"oct\",\"kid\":\"" + id + "\",\"k\":\"" + key + "\"}"; - } - jwkSet += "]}"; - return jwkSet; - } - - /** - * Retrieves clear key ids from KeyRequest and creates the response in place. - */ - private byte[] createKeysResponse(MediaDrm.KeyRequest keyRequest, byte[][] clearKeys) { - - Vector<String> keyIds = new Vector<String>(); - if (0 == getKeyIds(keyRequest.getData(), keyIds)) { - Log.e(TAG, "No key ids found in initData"); - return null; - } - - if (clearKeys.length != keyIds.size()) { - Log.e(TAG, "Mismatch number of key ids and keys: ids=" - + keyIds.size() + ", keys=" + clearKeys.length); - return null; - } - - // Base64 encodes clearkeys. Keys are known to the application. - Vector<String> keys = new Vector<String>(); - for (int i = 0; i < clearKeys.length; ++i) { - String clearKey = Base64.encodeToString(clearKeys[i], - Base64.NO_PADDING | Base64.NO_WRAP); - keys.add(clearKey); - } - - String jwkSet = createJsonWebKeySet(keyIds, keys); - byte[] jsonResponse = jwkSet.getBytes(Charset.forName("UTF-8")); - - return jsonResponse; - } - - ////////////////////////////////////////////////////////////////////////////////////////////// - // Playback/download helpers - - private static class MediaDownloadManager { - private static final String TAG = "MediaDownloadManager"; - - private final Context mContext; - private final DownloadManager mDownloadManager; - - MediaDownloadManager(Context context) { - mContext = context; - mDownloadManager = - (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); - } - - public long downloadFileWithRetries(Uri uri, Uri file, long timeout, int retries) - throws Exception { - long id = -1; - for (int i = 0; i < retries; i++) { - try { - id = downloadFile(uri, file, timeout); - if (id != -1) { - break; - } - } catch (Exception e) { - removeFile(id); - Log.w(TAG, "Download failed " + i + " times "); - } - } - return id; - } - - public long downloadFile(Uri uri, Uri file, long timeout) throws Exception { - Log.i(TAG, "uri:" + uri + " file:" + file + " wait:" + timeout + " Secs"); - final DownloadReceiver receiver = new DownloadReceiver(); - long id = -1; - try { - IntentFilter intentFilter = - new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); - mContext.registerReceiver(receiver, intentFilter); - - Request request = new Request(uri); - request.setDestinationUri(file); - id = mDownloadManager.enqueue(request); - Log.i(TAG, "enqueue:" + id); - - receiver.waitForDownloadComplete(timeout, id); - } finally { - mContext.unregisterReceiver(receiver); - } - return id; - } - - public void removeFile(long id) { - Log.i(TAG, "removeFile:" + id); - mDownloadManager.remove(id); - } - - public Uri getUriForDownloadedFile(long id) { - return mDownloadManager.getUriForDownloadedFile(id); - } - - private final class DownloadReceiver extends BroadcastReceiver { - private HashSet<Long> mCompleteIds = new HashSet<>(); - - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mCompleteIds) { - if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) { - mCompleteIds.add( - intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)); - mCompleteIds.notifyAll(); - } - } - } - - private boolean isCompleteLocked(long... ids) { - for (long id : ids) { - if (!mCompleteIds.contains(id)) { - return false; - } - } - return true; - } - - public void waitForDownloadComplete(long timeoutSecs, long... waitForIds) - throws InterruptedException { - if (waitForIds.length == 0) { - throw new IllegalArgumentException("Missing IDs to wait for"); - } - - final long startTime = SystemClock.elapsedRealtime(); - do { - synchronized (mCompleteIds) { - mCompleteIds.wait(1000); - if (isCompleteLocked(waitForIds)) { - return; - } - } - } while ((SystemClock.elapsedRealtime() - startTime) < timeoutSecs * 1000); - - throw new InterruptedException( - "Timeout waiting for IDs " + Arrays.toString(waitForIds) - + "; received " + mCompleteIds.toString() - + ". Make sure you have WiFi or some other connectivity for this test."); - } - } - - } // MediaDownloadManager - -} diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java b/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java deleted file mode 100644 index fe4f7b99def..00000000000 --- a/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java +++ /dev/null @@ -1,2283 +0,0 @@ -/* - * Copyright 2018 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.media.cts; - -import android.content.pm.PackageManager; -import android.content.res.AssetFileDescriptor; -import android.hardware.Camera; -import android.media.AudioAttributes; -import android.media.AudioManager; -import android.media.DataSourceDesc; -import android.media.Media2DataSource; -import android.media.MediaFormat; -import android.media.MediaMetadataRetriever; -import android.media.MediaPlayer2; -import android.media.MediaRecorder; -import android.media.MediaTimestamp; -import android.media.PlaybackParams; -import android.media.SubtitleData; -import android.media.SyncParams; -import android.media.audiofx.AudioEffect; -import android.media.audiofx.Visualizer; -import android.media.cts.R; -import android.media.cts.TestUtils.Monitor; -import android.net.Uri; -import android.os.Environment; -import android.os.PowerManager; -import android.platform.test.annotations.AppModeFull; -import android.platform.test.annotations.RequiresDevice; -import android.util.Log; - -import androidx.test.filters.SmallTest; - -import com.android.compatibility.common.util.MediaUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.Vector; -import java.util.concurrent.CountDownLatch; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Tests for the MediaPlayer2 API and local video/audio playback. - * - * The files in res/raw used by testLocalVideo* are (c) copyright 2008, - * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons - * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/. - */ -@SmallTest -@RequiresDevice -@AppModeFull(reason = "TODO: evaluate and port to instant") -public class MediaPlayer2Test extends MediaPlayer2TestBase { - // TODO: remove this flag to enable tests. - private static final boolean IGNORE_TESTS = true; - - private String RECORDED_FILE; - private static final String LOG_TAG = "MediaPlayer2Test"; - - private static final int RECORDED_VIDEO_WIDTH = 176; - private static final int RECORDED_VIDEO_HEIGHT = 144; - private static final long RECORDED_DURATION_MS = 3000; - private static final float FLOAT_TOLERANCE = .0001f; - - private final Vector<Integer> mTimedTextTrackIndex = new Vector<>(); - private final Monitor mOnTimedTextCalled = new Monitor(); - private int mSelectedTimedTextIndex; - - private final Vector<Integer> mSubtitleTrackIndex = new Vector<>(); - private final Monitor mOnSubtitleDataCalled = new Monitor(); - private int mSelectedSubtitleIndex; - - private File mOutFile; - - private int mBoundsCount; - - @Override - protected void setUp() throws Exception { - super.setUp(); - RECORDED_FILE = new File(Environment.getExternalStorageDirectory(), - "mediaplayer_record.out").getAbsolutePath(); - mOutFile = new File(RECORDED_FILE); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - if (mOutFile != null && mOutFile.exists()) { - mOutFile.delete(); - } - } - - // Bug 13652927 - public void testVorbisCrash() throws Exception { - if (IGNORE_TESTS) { - return; - } - MediaPlayer2 mp = mPlayer; - MediaPlayer2 mp2 = mPlayer2; - AssetFileDescriptor afd2 = mResources.openRawResourceFd(R.raw.testmp3_2); - mp2.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength()) - .build()); - Monitor onPrepareCalled = new Monitor(); - Monitor onErrorCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - onErrorCalled.signal(); - } - }; - mp2.setMediaPlayer2EventCallback(mExecutor, ecb); - mp2.prepare(); - onPrepareCalled.waitForSignal(); - afd2.close(); - mp2.clearMediaPlayer2EventCallback(); - - mp2.loopCurrent(true); - mp2.play(); - - for (int i = 0; i < 20; i++) { - try { - AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.bug13652927); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), - afd.getLength()) - .build()); - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - onPrepareCalled.reset(); - mp.prepare(); - onErrorCalled.waitForSignal(); - afd.close(); - } catch (Exception e) { - // expected to fail - Log.i("@@@", "failed: " + e); - } - Thread.sleep(500); - assertTrue("media player died", mp2.isPlaying()); - mp.reset(); - } - } - - public void testPlayNullSourcePath() throws Exception { - if (IGNORE_TESTS) { - return; - } - Monitor onSetDataSourceCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { - assertTrue(status != MediaPlayer2.CALL_STATUS_NO_ERROR); - onSetDataSourceCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - onSetDataSourceCalled.reset(); - mPlayer.setDataSource((DataSourceDesc)null); - onSetDataSourceCalled.waitForSignal(); - } - - public void testPlayAudioFromDataURI() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int mp3Duration = 34909; - final int tolerance = 70; - final int seekDuration = 100; - - // This is "R.raw.testmp3_2", base64-encoded. - final int resid = R.raw.testmp3_3; - - InputStream is = mContext.getResources().openRawResource(resid); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - - StringBuilder builder = new StringBuilder(); - builder.append("data:;base64,"); - builder.append(reader.readLine()); - Uri uri = Uri.parse(builder.toString()); - - MediaPlayer2 mp = createMediaPlayer2(mContext, uri); - - Monitor onPrepareCalled = new Monitor(); - Monitor onPlayCalled = new Monitor(); - Monitor onSeekToCalled = new Monitor(); - Monitor onLoopCurrentCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - onPlayCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { - onLoopCurrentCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - onSeekToCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - try { - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - assertFalse(mp.isLooping()); - onLoopCurrentCalled.reset(); - mp.loopCurrent(true); - onLoopCurrentCalled.waitForSignal(); - assertTrue(mp.isLooping()); - - assertEquals(mp3Duration, mp.getDuration(), tolerance); - long pos = mp.getCurrentPosition(); - assertTrue(pos >= 0); - assertTrue(pos < mp3Duration - seekDuration); - - onSeekToCalled.reset(); - mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); - onSeekToCalled.waitForSignal(); - assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); - - // test pause and restart - mp.pause(); - Thread.sleep(SLEEP_TIME); - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - // test stop and restart - mp.reset(); - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - onPrepareCalled.reset(); - mp.prepare(); - onPrepareCalled.waitForSignal(); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - // waiting to complete - while(mp.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - } finally { - mp.close(); - } - } - - public void testPlayAudio() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.testmp3_2; - final int mp3Duration = 34909; - final int tolerance = 70; - final int seekDuration = 100; - - MediaPlayer2 mp = createMediaPlayer2(mContext, resid); - - Monitor onPrepareCalled = new Monitor(); - Monitor onPlayCalled = new Monitor(); - Monitor onSeekToCalled = new Monitor(); - Monitor onLoopCurrentCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - onPlayCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { - onLoopCurrentCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - onSeekToCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - try { - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - assertFalse(mp.isLooping()); - onLoopCurrentCalled.reset(); - mp.loopCurrent(true); - onLoopCurrentCalled.waitForSignal(); - assertTrue(mp.isLooping()); - - assertEquals(mp3Duration, mp.getDuration(), tolerance); - long pos = mp.getCurrentPosition(); - assertTrue(pos >= 0); - assertTrue(pos < mp3Duration - seekDuration); - - onSeekToCalled.reset(); - mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); - onSeekToCalled.waitForSignal(); - assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); - - // test pause and restart - mp.pause(); - Thread.sleep(SLEEP_TIME); - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - // test stop and restart - mp.reset(); - AssetFileDescriptor afd = mResources.openRawResourceFd(resid); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) - .build()); - - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - onPrepareCalled.reset(); - mp.prepare(); - onPrepareCalled.waitForSignal(); - afd.close(); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - // waiting to complete - while(mp.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - } finally { - mp.close(); - } - } - - public void testConcurentPlayAudio() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.test1m1s; // MP3 longer than 1m are usualy offloaded - final int tolerance = 70; - - List<MediaPlayer2> mps = Stream.generate(() -> createMediaPlayer2(mContext, resid)) - .limit(5).collect(Collectors.toList()); - - try { - for (MediaPlayer2 mp : mps) { - Monitor onPlayCalled = new Monitor(); - Monitor onLoopCurrentCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - onPlayCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { - onLoopCurrentCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - assertFalse(mp.isLooping()); - onLoopCurrentCalled.reset(); - mp.loopCurrent(true); - onLoopCurrentCalled.waitForSignal(); - assertTrue(mp.isLooping()); - - long pos = mp.getCurrentPosition(); - assertTrue(pos >= 0); - - Thread.sleep(SLEEP_TIME); // Delay each track to be able to ear them - } - // Check that all mp3 are playing concurrently here - for (MediaPlayer2 mp : mps) { - long pos = mp.getCurrentPosition(); - Thread.sleep(SLEEP_TIME); - assertEquals(pos + SLEEP_TIME, mp.getCurrentPosition(), tolerance); - } - } finally { - mps.forEach(MediaPlayer2::close); - } - } - - public void testPlayAudioLooping() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.testmp3; - - MediaPlayer2 mp = createMediaPlayer2(mContext, resid); - try { - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - mp.loopCurrent(true); - Monitor onCompletionCalled = new Monitor(); - Monitor onPlayCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int extra) { - Log.i("@@@", "got oncompletion"); - onCompletionCalled.signal(); - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - onPlayCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - assertFalse(mp.isPlaying()); - onPlayCalled.reset(); - mp.play(); - onPlayCalled.waitForSignal(); - assertTrue(mp.isPlaying()); - - long duration = mp.getDuration(); - Thread.sleep(duration * 4); // allow for several loops - assertTrue(mp.isPlaying()); - assertEquals("wrong number of completion signals", 0, - onCompletionCalled.getNumSignal()); - mp.loopCurrent(false); - - // wait for playback to finish - while(mp.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - assertEquals("wrong number of completion signals", 1, - onCompletionCalled.getNumSignal()); - } finally { - mp.close(); - } - } - - public void testPlayMidi() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.midi8sec; - final int midiDuration = 8000; - final int tolerance = 70; - final int seekDuration = 1000; - - MediaPlayer2 mp = createMediaPlayer2(mContext, resid); - - Monitor onPrepareCalled = new Monitor(); - Monitor onSeekToCalled = new Monitor(); - Monitor onLoopCurrentCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_LOOP_CURRENT) { - onLoopCurrentCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - onSeekToCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - try { - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - mp.play(); - - assertFalse(mp.isLooping()); - onLoopCurrentCalled.reset(); - mp.loopCurrent(true); - onLoopCurrentCalled.waitForSignal(); - assertTrue(mp.isLooping()); - - assertEquals(midiDuration, mp.getDuration(), tolerance); - long pos = mp.getCurrentPosition(); - assertTrue(pos >= 0); - assertTrue(pos < midiDuration - seekDuration); - - onSeekToCalled.reset(); - mp.seekTo(pos + seekDuration, MediaPlayer2.SEEK_PREVIOUS_SYNC); - onSeekToCalled.waitForSignal(); - assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance); - - // test stop and restart - mp.reset(); - AssetFileDescriptor afd = mResources.openRawResourceFd(resid); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) - .build()); - - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - onPrepareCalled.reset(); - mp.prepare(); - onPrepareCalled.waitForSignal(); - afd.close(); - - mp.play(); - - Thread.sleep(SLEEP_TIME); - } finally { - mp.close(); - } - } - - static class OutputListener { - int mSession; - AudioEffect mVc; - Visualizer mVis; - byte [] mVisData; - boolean mSoundDetected; - OutputListener(int session) { - mSession = session; - // creating a volume controller on output mix ensures that ro.audio.silent mutes - // audio after the effects and not before - mVc = new AudioEffect( - AudioEffect.EFFECT_TYPE_NULL, - UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"), - 0, - session); - mVc.setEnabled(true); - mVis = new Visualizer(session); - int size = 256; - int[] range = Visualizer.getCaptureSizeRange(); - if (size < range[0]) { - size = range[0]; - } - if (size > range[1]) { - size = range[1]; - } - assertTrue(mVis.setCaptureSize(size) == Visualizer.SUCCESS); - - mVis.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { - @Override - public void onWaveFormDataCapture(Visualizer visualizer, - byte[] waveform, int samplingRate) { - if (!mSoundDetected) { - for (int i = 0; i < waveform.length; i++) { - // 8 bit unsigned PCM, zero level is at 128, which is -128 when - // seen as a signed byte - if (waveform[i] != -128) { - mSoundDetected = true; - break; - } - } - } - } - - @Override - public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) { - } - }, 10000 /* milliHertz */, true /* PCM */, false /* FFT */); - assertTrue(mVis.setEnabled(true) == Visualizer.SUCCESS); - } - - void reset() { - mSoundDetected = false; - } - - boolean heardSound() { - return mSoundDetected; - } - - void release() { - mVis.release(); - mVc.release(); - } - } - - public void testPlayAudioTwice() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.camera_click; - - MediaPlayer2 mp = createMediaPlayer2(mContext, resid); - try { - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mp.setAudioAttributes(attributes); - mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - OutputListener listener = new OutputListener(mp.getAudioSessionId()); - - Thread.sleep(SLEEP_TIME); - assertFalse("noise heard before test started", listener.heardSound()); - - mp.play(); - Thread.sleep(SLEEP_TIME); - assertFalse("player was still playing after " + SLEEP_TIME + " ms", mp.isPlaying()); - assertTrue("nothing heard while test ran", listener.heardSound()); - listener.reset(); - mp.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mp.play(); - Thread.sleep(SLEEP_TIME); - assertTrue("nothing heard when sound was replayed", listener.heardSound()); - listener.release(); - } finally { - mp.close(); - } - } - - public void testPlayVideo() throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest(R.raw.testvideo, 352, 288); - } - - /** - * Test for reseting a surface during video playback - * After reseting, the video should continue playing - * from the time setDisplay() was called - */ - public void testVideoSurfaceResetting() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int tolerance = 150; - final int audioLatencyTolerance = 1000; /* covers audio path latency variability */ - final int seekPos = 4760; // This is the I-frame position - - final CountDownLatch seekDone = new CountDownLatch(1); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - seekDone.countDown(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - if (!checkLoadResource(R.raw.testvideo)) { - return; // skip; - } - playLoadedVideo(352, 288, -1); - - Thread.sleep(SLEEP_TIME); - - long posBefore = mPlayer.getCurrentPosition(); - mPlayer.setDisplay(getActivity().getSurfaceHolder2()); - long posAfter = mPlayer.getCurrentPosition(); - - /* temporarily disable timestamp checking because MediaPlayer2 now seeks to I-frame - * position, instead of requested position. setDisplay invovles a seek operation - * internally. - */ - // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. - // assertEquals(posAfter, posBefore, tolerance); - assertTrue(mPlayer.isPlaying()); - - Thread.sleep(SLEEP_TIME); - - mPlayer.seekTo(seekPos, MediaPlayer2.SEEK_PREVIOUS_SYNC); - seekDone.await(); - posAfter = mPlayer.getCurrentPosition(); - assertEquals(seekPos, posAfter, tolerance + audioLatencyTolerance); - - Thread.sleep(SLEEP_TIME / 2); - posBefore = mPlayer.getCurrentPosition(); - mPlayer.setDisplay(null); - posAfter = mPlayer.getCurrentPosition(); - // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. - // assertEquals(posAfter, posBefore, tolerance); - assertTrue(mPlayer.isPlaying()); - - Thread.sleep(SLEEP_TIME); - - posBefore = mPlayer.getCurrentPosition(); - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - posAfter = mPlayer.getCurrentPosition(); - - // TODO: uncomment out line below when MediaPlayer2 can seek to requested position. - // assertEquals(posAfter, posBefore, tolerance); - assertTrue(mPlayer.isPlaying()); - - Thread.sleep(SLEEP_TIME); - } - - public void testRecordedVideoPlayback0() throws Exception { - if (IGNORE_TESTS) { - return; - } - testRecordedVideoPlaybackWithAngle(0); - } - - public void testRecordedVideoPlayback90() throws Exception { - if (IGNORE_TESTS) { - return; - } - testRecordedVideoPlaybackWithAngle(90); - } - - public void testRecordedVideoPlayback180() throws Exception { - if (IGNORE_TESTS) { - return; - } - testRecordedVideoPlaybackWithAngle(180); - } - - public void testRecordedVideoPlayback270() throws Exception { - if (IGNORE_TESTS) { - return; - } - testRecordedVideoPlaybackWithAngle(270); - } - - private boolean hasCamera() { - return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); - } - - private Camera mCamera; - private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception { - int width = RECORDED_VIDEO_WIDTH; - int height = RECORDED_VIDEO_HEIGHT; - final String file = RECORDED_FILE; - final long durationMs = RECORDED_DURATION_MS; - - if (!hasCamera()) { - return; - } - - boolean isSupported = false; - mCamera = Camera.open(0); - Camera.Parameters parameters = mCamera.getParameters(); - List<Camera.Size> videoSizes = parameters.getSupportedVideoSizes(); - // getSupportedVideoSizes returns null when separate video/preview size - // is not supported. - if (videoSizes == null) { - videoSizes = parameters.getSupportedPreviewSizes(); - } - for (Camera.Size size : videoSizes) - { - if (size.width == width && size.height == height) { - isSupported = true; - break; - } - } - mCamera.release(); - mCamera = null; - if (!isSupported) { - width = videoSizes.get(0).width; - height = videoSizes.get(0).height; - } - checkOrientation(angle); - recordVideo(width, height, angle, file, durationMs); - checkDisplayedVideoSize(width, height, angle, file); - checkVideoRotationAngle(angle, file); - } - - private void checkOrientation(int angle) throws Exception { - assertTrue(angle >= 0); - assertTrue(angle < 360); - assertTrue((angle % 90) == 0); - } - - private void recordVideo( - int w, int h, int angle, String file, long durationMs) throws Exception { - - MediaRecorder recorder = new MediaRecorder(); - recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); - recorder.setAudioSource(MediaRecorder.AudioSource.MIC); - recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); - recorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); - recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); - recorder.setOutputFile(file); - recorder.setOrientationHint(angle); - recorder.setVideoSize(w, h); - recorder.setPreviewDisplay(getActivity().getSurfaceHolder2().getSurface()); - recorder.prepare(); - recorder.start(); - Thread.sleep(durationMs); - recorder.stop(); - recorder.release(); - recorder = null; - } - - private void checkDisplayedVideoSize( - int w, int h, int angle, String file) throws Exception { - - int displayWidth = w; - int displayHeight = h; - if ((angle % 180) != 0) { - displayWidth = h; - displayHeight = w; - } - playVideoTest(file, displayWidth, displayHeight); - } - - private void checkVideoRotationAngle(int angle, String file) { - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - retriever.setDataSource(file); - String rotation = retriever.extractMetadata( - MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); - retriever.release(); - retriever = null; - assertNotNull(rotation); - assertEquals(Integer.parseInt(rotation), angle); - } - - public void testPlaylist() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!checkLoadResource( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { - return; // skip - } - DataSourceDesc dsd1 = createDataSourceDesc( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz); - DataSourceDesc dsd2 = createDataSourceDesc( - R.raw.testvideo); - ArrayList<DataSourceDesc> nextDSDs = new ArrayList<DataSourceDesc>(2); - nextDSDs.add(dsd2); - nextDSDs.add(dsd1); - - mPlayer.setNextDataSources(nextDSDs); - - Monitor onCompletion1Called = new Monitor(); - Monitor onCompletion2Called = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - Log.i(LOG_TAG, "testPlaylist: prepared dsd MediaId=" + dsd.getMediaId()); - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - if (dsd == dsd1) { - onCompletion1Called.signal(); - } else if (dsd == dsd2) { - onCompletion2Called.signal(); - } else { - mOnCompletionCalled.signal(); - } - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mOnCompletionCalled.reset(); - onCompletion1Called.reset(); - onCompletion2Called.reset(); - - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - - mPlayer.prepare(); - - mPlayer.play(); - - mOnCompletionCalled.waitForSignal(); - onCompletion2Called.waitForSignal(); - onCompletion1Called.waitForSignal(); - - mPlayer.reset(); - } - - // setPlaybackParams() with non-zero speed should NOT start playback. - // TODO: enable this test when MediaPlayer2.setPlaybackParams() is fixed - /* - public void testSetPlaybackParamsPositiveSpeed() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!checkLoadResource( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { - return; // skip - } - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - mOnCompletionCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - mOnSeekCompleteCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mOnCompletionCalled.reset(); - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnSeekCompleteCalled.reset(); - mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mOnSeekCompleteCalled.waitForSignal(); - - final float playbackRate = 1.0f; - - int playTime = 2000; // The testing clip is about 10 second long. - mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); - assertTrue("MediaPlayer2 should be playing", mPlayer.isPlaying()); - Thread.sleep(playTime); - assertTrue("MediaPlayer2 should still be playing", - mPlayer.getCurrentPosition() > 0); - - long duration = mPlayer.getDuration(); - mOnSeekCompleteCalled.reset(); - mPlayer.seekTo(duration - 1000, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mOnSeekCompleteCalled.waitForSignal(); - - mOnCompletionCalled.waitForSignal(); - assertFalse("MediaPlayer2 should not be playing", mPlayer.isPlaying()); - long eosPosition = mPlayer.getCurrentPosition(); - - mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); - assertTrue("MediaPlayer2 should be playing after EOS", mPlayer.isPlaying()); - Thread.sleep(playTime); - long position = mPlayer.getCurrentPosition(); - assertTrue("MediaPlayer2 should still be playing after EOS", - position > 0 && position < eosPosition); - - mPlayer.reset(); - } - */ - - public void testPlaybackRate() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int toleranceMs = 1000; - if (!checkLoadResource( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { - return; // skip - } - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - SyncParams sync = new SyncParams().allowDefaults(); - mPlayer.setSyncParams(sync); - sync = mPlayer.getSyncParams(); - - float[] rates = { 0.25f, 0.5f, 1.0f, 2.0f }; - for (float playbackRate : rates) { - mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); - Thread.sleep(1000); - int playTime = 4000; // The testing clip is about 10 second long. - mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); - mPlayer.play(); - Thread.sleep(playTime); - PlaybackParams pbp = mPlayer.getPlaybackParams(); - assertEquals( - playbackRate, pbp.getSpeed(), - FLOAT_TOLERANCE + playbackRate * sync.getTolerance()); - assertTrue("MediaPlayer2 should still be playing", mPlayer.isPlaying()); - - long playedMediaDurationMs = mPlayer.getCurrentPosition(); - int diff = Math.abs((int)(playedMediaDurationMs / playbackRate) - playTime); - if (diff > toleranceMs) { - fail("Media player had error in playback rate " + playbackRate - + ", play time is " + playTime + " vs expected " + playedMediaDurationMs); - } - mPlayer.pause(); - pbp = mPlayer.getPlaybackParams(); - // TODO: pause() should NOT change PlaybackParams. - // assertEquals(0.f, pbp.getSpeed(), FLOAT_TOLERANCE); - } - mPlayer.reset(); - } - - public void testSeekModes() throws Exception { - if (IGNORE_TESTS) { - return; - } - // This clip has 2 I frames at 66687us and 4299687us. - if (!checkLoadResource( - R.raw.bbb_s1_320x240_mp4_h264_mp2_800kbps_30fps_aac_lc_5ch_240kbps_44100hz)) { - return; // skip - } - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - mOnSeekCompleteCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnSeekCompleteCalled.reset(); - mPlayer.play(); - - final long seekPosMs = 3000; - final long timeToleranceMs = 100; - final long syncTime1Ms = 67; - final long syncTime2Ms = 4300; - - // TODO: tighten checking range. For now, ensure mediaplayer doesn't - // seek to previous sync or next sync. - long cp = runSeekMode(MediaPlayer2.SEEK_CLOSEST, seekPosMs); - assertTrue("MediaPlayer2 did not seek to closest position", - cp > seekPosMs && cp < syncTime2Ms); - - // TODO: tighten checking range. For now, ensure mediaplayer doesn't - // seek to closest position or next sync. - cp = runSeekMode(MediaPlayer2.SEEK_PREVIOUS_SYNC, seekPosMs); - assertTrue("MediaPlayer2 did not seek to preivous sync position", - cp < seekPosMs - timeToleranceMs); - - // TODO: tighten checking range. For now, ensure mediaplayer doesn't - // seek to closest position or previous sync. - cp = runSeekMode(MediaPlayer2.SEEK_NEXT_SYNC, seekPosMs); - assertTrue("MediaPlayer2 did not seek to next sync position", - cp > syncTime2Ms - timeToleranceMs); - - // TODO: tighten checking range. For now, ensure mediaplayer doesn't - // seek to closest position or previous sync. - cp = runSeekMode(MediaPlayer2.SEEK_CLOSEST_SYNC, seekPosMs); - assertTrue("MediaPlayer2 did not seek to closest sync position", - cp > syncTime2Ms - timeToleranceMs); - - mPlayer.reset(); - } - - private long runSeekMode(int seekMode, long seekPosMs) throws Exception { - final int sleepIntervalMs = 100; - int timeRemainedMs = 10000; // total time for testing - final int timeToleranceMs = 100; - - mPlayer.seekTo(seekPosMs, seekMode); - mOnSeekCompleteCalled.waitForSignal(); - mOnSeekCompleteCalled.reset(); - long cp = -seekPosMs; - while (timeRemainedMs > 0) { - cp = mPlayer.getCurrentPosition(); - // Wait till MediaPlayer2 starts rendering since MediaPlayer2 caches - // seek position as current position. - if (cp < seekPosMs - timeToleranceMs || cp > seekPosMs + timeToleranceMs) { - break; - } - timeRemainedMs -= sleepIntervalMs; - Thread.sleep(sleepIntervalMs); - } - assertTrue("MediaPlayer2 did not finish seeking in time for mode " + seekMode, - timeRemainedMs > 0); - return cp; - } - - public void testGetTimestamp() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int toleranceUs = 100000; - final float playbackRate = 1.0f; - if (!checkLoadResource( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) { - return; // skip - } - - Monitor onPauseCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PAUSE) { - onPauseCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mPlayer.play(); - mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(playbackRate)); - Thread.sleep(SLEEP_TIME); // let player get into stable state. - long nt1 = System.nanoTime(); - MediaTimestamp ts1 = mPlayer.getTimestamp(); - long nt2 = System.nanoTime(); - assertTrue("Media player should return a valid time stamp", ts1 != null); - assertEquals("MediaPlayer2 had error in clockRate " + ts1.getMediaClockRate(), - playbackRate, ts1.getMediaClockRate(), 0.001f); - assertTrue("The nanoTime of Media timestamp should be taken when getTimestamp is called.", - nt1 <= ts1.getAnchorSytemNanoTime() && ts1.getAnchorSytemNanoTime() <= nt2); - - onPauseCalled.reset(); - mPlayer.pause(); - onPauseCalled.waitForSignal(); - ts1 = mPlayer.getTimestamp(); - assertTrue("Media player should return a valid time stamp", ts1 != null); - assertTrue("Media player should have play rate of 0.0f when paused", - ts1.getMediaClockRate() == 0.0f); - - mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mPlayer.play(); - Thread.sleep(SLEEP_TIME); // let player get into stable state. - int playTime = 4000; // The testing clip is about 10 second long. - ts1 = mPlayer.getTimestamp(); - assertTrue("Media player should return a valid time stamp", ts1 != null); - Thread.sleep(playTime); - MediaTimestamp ts2 = mPlayer.getTimestamp(); - assertTrue("Media player should return a valid time stamp", ts2 != null); - assertTrue("The clockRate should not be changed.", - ts1.getMediaClockRate() == ts2.getMediaClockRate()); - assertEquals("MediaPlayer2 had error in timestamp.", - ts1.getAnchorMediaTimeUs() + (long)(playTime * ts1.getMediaClockRate() * 1000), - ts2.getAnchorMediaTimeUs(), toleranceUs); - - mPlayer.reset(); - } - - public void testLocalVideo_MKV_H265_1280x720_500kbps_25fps_AAC_Stereo_128kbps_44100Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz, 1280, 720); - } - public void testLocalVideo_MP4_H264_480x360_500kbps_25fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_500kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_500kbps_30fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_1000kbps_25fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_1000kbps_30fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_1350kbps_25fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1350kbps_25fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz, 480, 360); - } - - public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_128kbps_44110Hz_frag() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_128kbps_44100hz_fragmented, - 480, 360); - } - - - public void testLocalVideo_MP4_H264_480x360_1350kbps_30fps_AAC_Stereo_192kbps_44110Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz, 480, 360); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Mono_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_12fps_AAC_Stereo_128kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Mono_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_56kbps_25fps_AAC_Stereo_128kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_56kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Mono_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_22050hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_12fps_AAC_Stereo_128kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Mono_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_mono_24kbps_22050hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_24kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_24kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_11025Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz, 176, 144); - } - - public void testLocalVideo_3gp_H263_176x144_300kbps_25fps_AAC_Stereo_128kbps_22050Hz() - throws Exception { - if (IGNORE_TESTS) { - return; - } - playVideoTest( - R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz, 176, 144); - } - - private void readSubtitleTracks() throws Exception { - mSubtitleTrackIndex.clear(); - List<MediaPlayer2.TrackInfo> trackInfos = mPlayer.getTrackInfo(); - if (trackInfos == null || trackInfos.size() == 0) { - return; - } - - Vector<Integer> subtitleTrackIndex = new Vector<>(); - for (int i = 0; i < trackInfos.size(); ++i) { - assertTrue(trackInfos.get(i) != null); - if (trackInfos.get(i).getTrackType() == - MediaPlayer2.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) { - subtitleTrackIndex.add(i); - } - } - - mSubtitleTrackIndex.addAll(subtitleTrackIndex); - } - - private void selectSubtitleTrack(int index) throws Exception { - int trackIndex = mSubtitleTrackIndex.get(index); - mPlayer.selectTrack(trackIndex); - mSelectedSubtitleIndex = index; - } - - private void deselectSubtitleTrack(int index) throws Exception { - int trackIndex = mSubtitleTrackIndex.get(index); - mOnDeselectTrackCalled.reset(); - mPlayer.deselectTrack(trackIndex); - mOnDeselectTrackCalled.waitForSignal(); - if (mSelectedSubtitleIndex == index) { - mSelectedSubtitleIndex = -1; - } - } - - public void testDeselectTrackForSubtitleTracks() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { - return; // skip; - } - - getInstrumentation().waitForIdleSync(); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { - mOnInfoCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - mOnSeekCompleteCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_DESELECT_TRACK) { - mCallStatus = status; - mOnDeselectTrackCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mPlayer.setOnSubtitleDataListener(new MediaPlayer2.OnSubtitleDataListener() { - @Override - public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) { - if (data != null && data.getData() != null) { - mOnSubtitleDataCalled.signal(); - } - } - }); - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue(mPlayer.isPlaying()); - - // Closed caption tracks are in-band. - // So, those tracks will be found after processing a number of frames. - mOnInfoCalled.waitForSignal(1500); - - mOnInfoCalled.reset(); - mOnInfoCalled.waitForSignal(1500); - - readSubtitleTracks(); - - // Run twice to check if repeated selection-deselection on the same track works well. - for (int i = 0; i < 2; i++) { - // Waits until at least one subtitle is fired. Timeout is 2.5 seconds. - selectSubtitleTrack(i); - mOnSubtitleDataCalled.reset(); - assertTrue(mOnSubtitleDataCalled.waitForSignal(2500)); - - // Try deselecting track. - deselectSubtitleTrack(i); - mOnSubtitleDataCalled.reset(); - assertFalse(mOnSubtitleDataCalled.waitForSignal(1500)); - } - - // Deselecting unselected track: expected error status - mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - deselectSubtitleTrack(0); - assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR); - - mPlayer.reset(); - } - - public void testChangeSubtitleTrack() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { - return; // skip; - } - - mPlayer.setOnSubtitleDataListener(new MediaPlayer2.OnSubtitleDataListener() { - @Override - public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) { - if (data != null && data.getData() != null) { - mOnSubtitleDataCalled.signal(); - } - } - }); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { - mOnInfoCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue(mPlayer.isPlaying()); - - // Closed caption tracks are in-band. - // So, those tracks will be found after processing a number of frames. - mOnInfoCalled.waitForSignal(1500); - - mOnInfoCalled.reset(); - mOnInfoCalled.waitForSignal(1500); - - readSubtitleTracks(); - - // Waits until at least two captions are fired. Timeout is 2.5 sec. - selectSubtitleTrack(0); - assertTrue(mOnSubtitleDataCalled.waitForCountedSignals(2, 2500) >= 2); - - mOnSubtitleDataCalled.reset(); - selectSubtitleTrack(1); - assertTrue(mOnSubtitleDataCalled.waitForCountedSignals(2, 2500) >= 2); - - mPlayer.reset(); - } - - public void testGetTrackInfoForVideoWithSubtitleTracks() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) { - return; // skip; - } - - getInstrumentation().waitForIdleSync(); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_METADATA_UPDATE) { - mOnInfoCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue(mPlayer.isPlaying()); - - // The media metadata will be changed while playing since closed caption tracks are in-band - // and those tracks will be found after processing a number of frames. These tracks will be - // found within one second. - mOnInfoCalled.waitForSignal(1500); - - mOnInfoCalled.reset(); - mOnInfoCalled.waitForSignal(1500); - - readSubtitleTracks(); - assertEquals(2, mSubtitleTrackIndex.size()); - - mPlayer.reset(); - } - - /* - * This test assumes the resources being tested are between 8 and 14 seconds long - * The ones being used here are 10 seconds long. - */ - public void testResumeAtEnd() throws Throwable { - if (IGNORE_TESTS) { - return; - } - int testsRun = - testResumeAtEnd(R.raw.loudsoftmp3) + - testResumeAtEnd(R.raw.loudsoftwav) + - testResumeAtEnd(R.raw.loudsoftogg) + - testResumeAtEnd(R.raw.loudsoftitunes) + - testResumeAtEnd(R.raw.loudsoftfaac) + - testResumeAtEnd(R.raw.loudsoftaac); - if (testsRun == 0) { - MediaUtils.skipTest("no decoder found"); - } - } - - // returns 1 if test was run, 0 otherwise - private int testResumeAtEnd(int res) throws Throwable { - if (!loadResource(res)) { - Log.i(LOG_TAG, "testResumeAtEnd: No decoder found for " + - mContext.getResources().getResourceEntryName(res) + - " --- skipping."); - return 0; // skip - } - mOnCompletionCalled.reset(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - mOnCompletionCalled.signal(); - mPlayer.play(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - // skip the first part of the file so we reach EOF sooner - mPlayer.seekTo(5000, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mPlayer.play(); - // sleep long enough that we restart playback at least once, but no more - Thread.sleep(10000); - assertTrue("MediaPlayer2 should still be playing", mPlayer.isPlaying()); - mPlayer.reset(); - assertEquals("wrong number of repetitions", 1, mOnCompletionCalled.getNumSignal()); - return 1; - } - - public void testPositionAtEnd() throws Throwable { - if (IGNORE_TESTS) { - return; - } - int testsRun = - testPositionAtEnd(R.raw.test1m1shighstereo) + - testPositionAtEnd(R.raw.loudsoftmp3) + - testPositionAtEnd(R.raw.loudsoftwav) + - testPositionAtEnd(R.raw.loudsoftogg) + - testPositionAtEnd(R.raw.loudsoftitunes) + - testPositionAtEnd(R.raw.loudsoftfaac) + - testPositionAtEnd(R.raw.loudsoftaac); - if (testsRun == 0) { - MediaUtils.skipTest(LOG_TAG, "no decoder found"); - } - } - - private int testPositionAtEnd(int res) throws Throwable { - if (!loadResource(res)) { - Log.i(LOG_TAG, "testPositionAtEnd: No decoder found for " + - mContext.getResources().getResourceEntryName(res) + - " --- skipping."); - return 0; // skip - } - AudioAttributes attributes = new AudioAttributes.Builder() - .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC) - .build(); - mPlayer.setAudioAttributes(attributes); - - mOnCompletionCalled.reset(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - mOnCompletionCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - long duration = mPlayer.getDuration(); - assertTrue("resource too short", duration > 6000); - mPlayer.seekTo(duration - 5000, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - while (mPlayer.isPlaying()) { - Log.i("@@@@", "position: " + mPlayer.getCurrentPosition()); - Thread.sleep(500); - } - Log.i("@@@@", "final position: " + mPlayer.getCurrentPosition()); - assertTrue(mPlayer.getCurrentPosition() > duration - 1000); - mPlayer.reset(); - return 1; - } - - public void testCallback() throws Throwable { - if (IGNORE_TESTS) { - return; - } - final int mp4Duration = 8484; - - if (!checkLoadResource(R.raw.testvideo)) { - return; // skip; - } - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - - mOnCompletionCalled.reset(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, - int width, int height) { - mOnVideoSizeChangedCalled.signal(); - } - - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - mOnErrorCalled.signal(); - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - mOnInfoCalled.signal(); - - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - mOnCompletionCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) { - mOnSeekCompleteCalled.signal(); - } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - assertFalse(mOnPrepareCalled.isSignalled()); - assertFalse(mOnVideoSizeChangedCalled.isSignalled()); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - mOnVideoSizeChangedCalled.waitForSignal(); - - mOnSeekCompleteCalled.reset(); - mPlayer.seekTo(mp4Duration >> 1, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mOnSeekCompleteCalled.waitForSignal(); - - assertFalse(mOnCompletionCalled.isSignalled()); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - while(mPlayer.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - assertFalse(mPlayer.isPlaying()); - mOnCompletionCalled.waitForSignal(); - assertFalse(mOnErrorCalled.isSignalled()); - mPlayer.reset(); - } - - public void testRecordAndPlay() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!hasMicrophone()) { - MediaUtils.skipTest(LOG_TAG, "no microphone"); - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB) - || !MediaUtils.checkEncoder(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { - return; // skip - } - File outputFile = new File(Environment.getExternalStorageDirectory(), - "record_and_play.3gp"); - String outputFileLocation = outputFile.getAbsolutePath(); - try { - recordMedia(outputFileLocation); - - Uri uri = Uri.parse(outputFileLocation); - MediaPlayer2 mp = MediaPlayer2.create(); - try { - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - mp.prepare(); - Thread.sleep(SLEEP_TIME); - playAndStop(mp); - } finally { - mp.close(); - } - - try { - mp = createMediaPlayer2(mContext, uri); - playAndStop(mp); - } finally { - if (mp != null) { - mp.close(); - } - } - - try { - mp = createMediaPlayer2(mContext, uri, getActivity().getSurfaceHolder()); - playAndStop(mp); - } finally { - if (mp != null) { - mp.close(); - } - } - } finally { - outputFile.delete(); - } - } - - private void playAndStop(MediaPlayer2 mp) throws Exception { - mp.play(); - Thread.sleep(SLEEP_TIME); - mp.reset(); - } - - private void recordMedia(String outputFile) throws Exception { - MediaRecorder mr = new MediaRecorder(); - try { - mr.setAudioSource(MediaRecorder.AudioSource.MIC); - mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); - mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); - mr.setOutputFile(outputFile); - - mr.prepare(); - mr.start(); - Thread.sleep(SLEEP_TIME); - mr.stop(); - } finally { - mr.release(); - } - } - - private boolean hasMicrophone() { - return getActivity().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_MICROPHONE); - } - - // Smoke test playback from a Media2DataSource. - public void testPlaybackFromAMedia2DataSource() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; - final int duration = 10000; - - if (!MediaUtils.hasCodecsForResource(mContext, resid)) { - return; - } - - TestMedia2DataSource dataSource = - TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); - // Test returning -1 from getSize() to indicate unknown size. - dataSource.returnFromGetSize(-1); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(dataSource) - .build()); - playLoadedVideo(null, null, -1); - assertTrue(mPlayer.isPlaying()); - - // Test pause and restart. - mPlayer.pause(); - Thread.sleep(SLEEP_TIME); - assertFalse(mPlayer.isPlaying()); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue(mPlayer.isPlaying()); - - // Test reset. - mPlayer.reset(); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(dataSource) - .build()); - - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue(mPlayer.isPlaying()); - - // Test seek. Note: the seek position is cached and returned as the - // current position so there's no point in comparing them. - mPlayer.seekTo(duration - SLEEP_TIME, MediaPlayer2.SEEK_PREVIOUS_SYNC); - while (mPlayer.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - } - - public void testNullMedia2DataSourceIsRejected() throws Exception { - if (IGNORE_TESTS) { - return; - } - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { - mCallStatus = status; - mOnPlayCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - mPlayer.setDataSource((DataSourceDesc)null); - mOnPlayCalled.waitForSignal(); - assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR); - } - - public void testMedia2DataSourceIsClosedOnReset() throws Exception { - if (IGNORE_TESTS) { - return; - } - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE) { - mCallStatus = status; - mOnPlayCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - TestMedia2DataSource dataSource = new TestMedia2DataSource(new byte[0]); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(dataSource) - .build()); - mOnPlayCalled.waitForSignal(); - mPlayer.reset(); - assertTrue(dataSource.isClosed()); - } - - public void testPlaybackFailsIfMedia2DataSourceThrows() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; - if (!MediaUtils.hasCodecsForResource(mContext, resid)) { - return; - } - - setOnErrorListener(); - TestMedia2DataSource dataSource = - TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(dataSource) - .build()); - - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - dataSource.throwFromReadAt(); - mPlayer.play(); - assertTrue(mOnErrorCalled.waitForSignal()); - } - - public void testPlaybackFailsIfMedia2DataSourceReturnsAnError() throws Exception { - if (IGNORE_TESTS) { - return; - } - final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz; - if (!MediaUtils.hasCodecsForResource(mContext, resid)) { - return; - } - - TestMedia2DataSource dataSource = - TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid)); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(dataSource) - .build()); - - setOnErrorListener(); - MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - }; - synchronized (mEventCbLock) { - mEventCallbacks.add(ecb); - } - - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - dataSource.returnFromReadAt(-2); - mPlayer.play(); - assertTrue(mOnErrorCalled.waitForSignal()); - } -} diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java deleted file mode 100644 index 2975d47ca4f..00000000000 --- a/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright 2018 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.media.cts; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources; -import android.media.AudioAttributes; -import android.media.AudioManager; -import android.media.DataSourceDesc; -import android.media.MediaPlayer2; -import android.media.MediaTimestamp; -import android.media.TimedMetaData; -import android.media.TimedText; -import android.media.cts.TestUtils.Monitor; -import android.net.Uri; -import android.os.PersistableBundle; -import android.test.ActivityInstrumentationTestCase2; -import android.view.SurfaceHolder; - -import com.android.compatibility.common.util.MediaUtils; - -import java.io.IOException; -import java.net.HttpCookie; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Logger; - -/** - * Base class for tests which use MediaPlayer2 to play audio or video. - */ -public class MediaPlayer2TestBase extends ActivityInstrumentationTestCase2<MediaStubActivity> { - private static final Logger LOG = Logger.getLogger(MediaPlayer2TestBase.class.getName()); - - protected static final int SLEEP_TIME = 1000; - protected static final int LONG_SLEEP_TIME = 6000; - protected static final int STREAM_RETRIES = 20; - protected static boolean sUseScaleToFitMode = false; - - protected Monitor mOnVideoSizeChangedCalled = new Monitor(); - protected Monitor mOnVideoRenderingStartCalled = new Monitor(); - protected Monitor mOnBufferingUpdateCalled = new Monitor(); - protected Monitor mOnPrepareCalled = new Monitor(); - protected Monitor mOnPlayCalled = new Monitor(); - protected Monitor mOnDeselectTrackCalled = new Monitor(); - protected Monitor mOnSeekCompleteCalled = new Monitor(); - protected Monitor mOnCompletionCalled = new Monitor(); - protected Monitor mOnInfoCalled = new Monitor(); - protected Monitor mOnErrorCalled = new Monitor(); - protected int mCallStatus; - - protected Context mContext; - protected Resources mResources; - - protected ExecutorService mExecutor; - - protected MediaPlayer2 mPlayer = null; - protected MediaPlayer2 mPlayer2 = null; - protected MediaStubActivity mActivity; - - protected final Object mEventCbLock = new Object(); - protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks = - new ArrayList<MediaPlayer2.MediaPlayer2EventCallback>(); - protected final Object mEventCbLock2 = new Object(); - protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks2 = - new ArrayList<MediaPlayer2.MediaPlayer2EventCallback>(); - - // convenience functions to create MediaPlayer2 - protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri) { - return createMediaPlayer2(context, uri, null); - } - - protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri, - SurfaceHolder holder) { - AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); - int s = am.generateAudioSessionId(); - return createMediaPlayer2(context, uri, holder, null, s > 0 ? s : 0); - } - - protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri, SurfaceHolder holder, - AudioAttributes audioAttributes, int audioSessionId) { - try { - MediaPlayer2 mp = MediaPlayer2.create(); - final AudioAttributes aa = audioAttributes != null ? audioAttributes : - new AudioAttributes.Builder().build(); - mp.setAudioAttributes(aa); - mp.setAudioSessionId(audioSessionId); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(context, uri) - .build()); - if (holder != null) { - mp.setDisplay(holder); - } - Monitor onPrepareCalled = new Monitor(); - ExecutorService executor = Executors.newFixedThreadPool(1); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(executor, ecb); - mp.prepare(); - onPrepareCalled.waitForSignal(); - mp.clearMediaPlayer2EventCallback(); - executor.shutdown(); - return mp; - } catch (IllegalArgumentException ex) { - LOG.warning("create failed:" + ex); - // fall through - } catch (SecurityException ex) { - LOG.warning("create failed:" + ex); - // fall through - } catch (InterruptedException ex) { - LOG.warning("create failed:" + ex); - // fall through - } - return null; - } - - protected static MediaPlayer2 createMediaPlayer2(Context context, int resid) { - AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); - int s = am.generateAudioSessionId(); - return createMediaPlayer2(context, resid, null, s > 0 ? s : 0); - } - - protected static MediaPlayer2 createMediaPlayer2(Context context, int resid, - AudioAttributes audioAttributes, int audioSessionId) { - try { - AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid); - if (afd == null) { - return null; - } - - MediaPlayer2 mp = MediaPlayer2.create(); - - final AudioAttributes aa = audioAttributes != null ? audioAttributes : - new AudioAttributes.Builder().build(); - mp.setAudioAttributes(aa); - mp.setAudioSessionId(audioSessionId); - - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) - .build()); - - Monitor onPrepareCalled = new Monitor(); - ExecutorService executor = Executors.newFixedThreadPool(1); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - onPrepareCalled.signal(); - } - } - }; - mp.setMediaPlayer2EventCallback(executor, ecb); - mp.prepare(); - onPrepareCalled.waitForSignal(); - mp.clearMediaPlayer2EventCallback(); - afd.close(); - executor.shutdown(); - return mp; - } catch (IOException ex) { - LOG.warning("create failed:" + ex); - // fall through - } catch (IllegalArgumentException ex) { - LOG.warning("create failed:" + ex); - // fall through - } catch (SecurityException ex) { - LOG.warning("create failed:" + ex); - // fall through - } catch (InterruptedException ex) { - LOG.warning("create failed:" + ex); - // fall through - } - return null; - } - - public MediaPlayer2TestBase() { - super(MediaStubActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - mActivity = getActivity(); - getInstrumentation().waitForIdleSync(); - try { - runTestOnUiThread(new Runnable() { - public void run() { - mPlayer = MediaPlayer2.create(); - mPlayer2 = MediaPlayer2.create(); - } - }); - } catch (Throwable e) { - e.printStackTrace(); - fail(); - } - mContext = getInstrumentation().getTargetContext(); - mResources = mContext.getResources(); - mExecutor = Executors.newFixedThreadPool(1); - - setUpMP2ECb(mPlayer, mEventCbLock, mEventCallbacks); - setUpMP2ECb(mPlayer2, mEventCbLock2, mEventCallbacks2); - } - - @Override - protected void tearDown() throws Exception { - if (mPlayer != null) { - mPlayer.close(); - mPlayer = null; - } - if (mPlayer2 != null) { - mPlayer2.close(); - mPlayer2 = null; - } - mExecutor.shutdown(); - mActivity = null; - super.tearDown(); - } - - protected void setUpMP2ECb(MediaPlayer2 mp, Object cbLock, - List<MediaPlayer2.MediaPlayer2EventCallback> ecbs) { - mp.setMediaPlayer2EventCallback(mExecutor, new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, int w, int h) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onVideoSizeChanged(mp, dsd, w, h); - } - } - } - - @Override - public void onTimedText(MediaPlayer2 mp, DataSourceDesc dsd, TimedText text) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onTimedText(mp, dsd, text); - } - } - } - - @Override - public void onTimedMetaDataAvailable(MediaPlayer2 mp, DataSourceDesc dsd, - TimedMetaData data) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onTimedMetaDataAvailable(mp, dsd, data); - } - } - } - - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onError(mp, dsd, what, extra); - } - } - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onInfo(mp, dsd, what, extra); - } - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onCallCompleted(mp, dsd, what, status); - } - } - } - - @Override - public void onMediaTimeChanged(MediaPlayer2 mp, DataSourceDesc dsd, - MediaTimestamp timestamp) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onMediaTimeChanged(mp, dsd, timestamp); - } - } - } - - @Override - public void onCommandLabelReached(MediaPlayer2 mp, Object label) { - synchronized (cbLock) { - for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) { - ecb.onCommandLabelReached(mp, label); - } - } - } - }); - } - - // returns true on success - protected boolean loadResource(int resid) throws Exception { - if (!MediaUtils.hasCodecsForResource(mContext, resid)) { - return false; - } - - AssetFileDescriptor afd = mResources.openRawResourceFd(resid); - try { - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) - .build()); - - // Although it is only meant for video playback, it should not - // cause issues for audio-only playback. - int videoScalingMode = sUseScaleToFitMode? - MediaPlayer2.VIDEO_SCALING_MODE_SCALE_TO_FIT - : MediaPlayer2.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; - - mPlayer.setVideoScalingMode(videoScalingMode); - } finally { - // TODO: close afd only after setDataSource is confirmed. - // afd.close(); - } - sUseScaleToFitMode = !sUseScaleToFitMode; // Alternate the scaling mode - return true; - } - - protected DataSourceDesc createDataSourceDesc(int resid) throws Exception { - if (!MediaUtils.hasCodecsForResource(mContext, resid)) { - return null; - } - - AssetFileDescriptor afd = mResources.openRawResourceFd(resid); - return new DataSourceDesc.Builder() - .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()) - .build(); - } - - protected boolean checkLoadResource(int resid) throws Exception { - return MediaUtils.check(loadResource(resid), "no decoder found"); - } - - protected void loadSubtitleSource(int resid) throws Exception { - AssetFileDescriptor afd = mResources.openRawResourceFd(resid); - try { - mPlayer.addTimedTextSource(afd.getFileDescriptor(), afd.getStartOffset(), - afd.getLength(), MediaPlayer2.MEDIA_MIMETYPE_TEXT_SUBRIP); - } finally { - afd.close(); - } - } - - protected void playLiveVideoTest(String path, int playTime) throws Exception { - playVideoWithRetries(path, null, null, playTime); - } - - protected void playLiveAudioOnlyTest(String path, int playTime) throws Exception { - playVideoWithRetries(path, -1, -1, playTime); - } - - protected void playVideoTest(String path, int width, int height) throws Exception { - playVideoWithRetries(path, width, height, 0); - } - - protected void playVideoWithRetries(String path, Integer width, Integer height, int playTime) - throws Exception { - boolean playedSuccessfully = false; - final Uri uri = Uri.parse(path); - for (int i = 0; i < STREAM_RETRIES; i++) { - try { - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - playLoadedVideo(width, height, playTime); - playedSuccessfully = true; - break; - } catch (PrepareFailedException e) { - // prepare() can fail because of network issues, so try again - LOG.warning("prepare() failed on try " + i + ", trying playback again"); - } - } - assertTrue("Stream did not play successfully after all attempts", playedSuccessfully); - } - - protected void playVideoTest(int resid, int width, int height) throws Exception { - if (!checkLoadResource(resid)) { - return; // skip - } - - playLoadedVideo(width, height, 0); - } - - protected void playLiveVideoTest( - Uri uri, Map<String, String> headers, List<HttpCookie> cookies, - int playTime) throws Exception { - playVideoWithRetries(uri, headers, cookies, null /* width */, null /* height */, playTime); - } - - protected void playVideoWithRetries( - Uri uri, Map<String, String> headers, List<HttpCookie> cookies, - Integer width, Integer height, int playTime) throws Exception { - boolean playedSuccessfully = false; - for (int i = 0; i < STREAM_RETRIES; i++) { - try { - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(getInstrumentation().getTargetContext(), - uri, headers, cookies) - .build()); - playLoadedVideo(width, height, playTime); - playedSuccessfully = true; - break; - } catch (PrepareFailedException e) { - // prepare() can fail because of network issues, so try again - // playLoadedVideo already has reset the player so we can try again safely. - LOG.warning("prepare() failed on try " + i + ", trying playback again"); - } - } - assertTrue("Stream did not play successfully after all attempts", playedSuccessfully); - } - - /** - * Play a video which has already been loaded with setDataSource(). - * - * @param width width of the video to verify, or null to skip verification - * @param height height of the video to verify, or null to skip verification - * @param playTime length of time to play video, or 0 to play entire video. - * with a non-negative value, this method stops the playback after the length of - * time or the duration the video is elapsed. With a value of -1, - * this method simply starts the video and returns immediately without - * stoping the video playback. - */ - protected void playLoadedVideo(final Integer width, final Integer height, int playTime) - throws Exception { - final float volume = 0.5f; - - boolean audioOnly = (width != null && width.intValue() == -1) || - (height != null && height.intValue() == -1); - - mPlayer.setDisplay(mActivity.getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - - synchronized (mEventCbLock) { - mEventCallbacks.add(new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onVideoSizeChanged(MediaPlayer2 mp, DataSourceDesc dsd, int w, int h) { - if (w == 0 && h == 0) { - // A size of 0x0 can be sent initially one time when using NuPlayer. - assertFalse(mOnVideoSizeChangedCalled.isSignalled()); - return; - } - mOnVideoSizeChangedCalled.signal(); - if (width != null) { - assertEquals(width.intValue(), w); - } - if (height != null) { - assertEquals(height.intValue(), h); - } - } - - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - fail("Media player had error " + what + " playing video"); - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_VIDEO_RENDERING_START) { - mOnVideoRenderingStartCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }); - } - try { - mOnPrepareCalled.reset(); - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - } catch (Exception e) { - mPlayer.reset(); - throw new PrepareFailedException(); - } - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - if (!audioOnly) { - mOnVideoSizeChangedCalled.waitForSignal(); - mOnVideoRenderingStartCalled.waitForSignal(); - } - mPlayer.setPlayerVolume(volume); - - // waiting to complete - if (playTime == -1) { - return; - } else if (playTime == 0) { - while (mPlayer.isPlaying()) { - Thread.sleep(SLEEP_TIME); - } - } else { - Thread.sleep(playTime); - } - - // validate a few MediaMetrics. - PersistableBundle metrics = mPlayer.getMetrics(); - if (metrics == null) { - fail("MediaPlayer2.getMetrics() returned null metrics"); - } else if (metrics.isEmpty()) { - fail("MediaPlayer2.getMetrics() returned empty metrics"); - } else { - - int size = metrics.size(); - Set<String> keys = metrics.keySet(); - - if (keys == null) { - fail("MediaMetricsSet returned no keys"); - } else if (keys.size() != size) { - fail("MediaMetricsSet.keys().size() mismatch MediaMetricsSet.size()"); - } - - // we played something; so one of these should be non-null - String vmime = metrics.getString(MediaPlayer2.MetricsConstants.MIME_TYPE_VIDEO, null); - String amime = metrics.getString(MediaPlayer2.MetricsConstants.MIME_TYPE_AUDIO, null); - if (vmime == null && amime == null) { - fail("getMetrics() returned neither video nor audio mime value"); - } - - long duration = metrics.getLong(MediaPlayer2.MetricsConstants.DURATION, -2); - if (duration == -2) { - fail("getMetrics() didn't return a duration"); - } - long playing = metrics.getLong(MediaPlayer2.MetricsConstants.PLAYING, -2); - if (playing == -2) { - fail("getMetrics() didn't return a playing time"); - } - if (!keys.contains(MediaPlayer2.MetricsConstants.PLAYING)) { - fail("MediaMetricsSet.keys() missing: " + MediaPlayer2.MetricsConstants.PLAYING); - } - } - - mPlayer.stop(); - } - - private static class PrepareFailedException extends Exception {} - - public boolean isTv() { - PackageManager pm = getInstrumentation().getTargetContext().getPackageManager(); - return pm.hasSystemFeature(pm.FEATURE_TELEVISION) - && pm.hasSystemFeature(pm.FEATURE_LEANBACK); - } - - public boolean checkTv() { - return MediaUtils.check(isTv(), "not a TV"); - } - - protected void setOnErrorListener() { - synchronized (mEventCbLock) { - mEventCallbacks.add(new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - mOnErrorCalled.signal(); - } - }); - } - } -} diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java index 6c712eef8c2..3412b21f6d5 100644 --- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java +++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java @@ -507,6 +507,12 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaStu // Make sure the tolerance is very small - due to rounding errors?. Log.v(TAG, "location: " + location); + // Trim the trailing slash, if any. + int lastIndex = location.lastIndexOf('/'); + if (lastIndex != -1) { + location = location.substring(0, lastIndex); + } + // Get the position of the -/+ sign in location String, which indicates // the beginning of the longtitude. int index = location.lastIndexOf('-'); @@ -515,12 +521,8 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase2<MediaStu } assertTrue("+ or - is not found", index != -1); assertTrue("+ or - is only found at the beginning", index != 0); - float latitude = Float.parseFloat(location.substring(0, index - 1)); - int lastIndex = location.lastIndexOf('/', index); - if (lastIndex == -1) { - lastIndex = location.length(); - } - float longitude = Float.parseFloat(location.substring(index, lastIndex - 1)); + float latitude = Float.parseFloat(location.substring(0, index)); + float longitude = Float.parseFloat(location.substring(index)); assertTrue("Incorrect latitude: " + latitude, Math.abs(latitude - LATITUDE) <= TOLERANCE); assertTrue("Incorrect longitude: " + longitude, Math.abs(longitude - LONGITUDE) <= TOLERANCE); retriever.release(); diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java deleted file mode 100644 index c1769ac8d55..00000000000 --- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright 2018 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.media.cts; - -import android.media.BufferingParams; -import android.media.DataSourceDesc; -import android.media.MediaFormat; -import android.media.MediaPlayer2; -import android.media.MediaPlayer2.TrackInfo; -import android.media.TimedMetaData; -import android.media.cts.TestUtils.Monitor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Looper; -import android.os.PowerManager; -import android.os.SystemClock; -import android.platform.test.annotations.AppModeFull; -import android.test.InstrumentationTestRunner; -import android.util.Log; -import android.webkit.cts.CtsTestServer; - -import com.android.compatibility.common.util.DynamicConfigDeviceSide; -import com.android.compatibility.common.util.MediaUtils; - -import java.net.HttpCookie; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.HashMap; -import java.util.List; - -/** - * Tests of MediaPlayer2 streaming capabilities. - */ -@AppModeFull(reason = "TODO: evaluate and port to instant") -public class StreamingMediaPlayer2Test extends MediaPlayer2TestBase { - // TODO: remove this flag to enable tests. - private static final boolean IGNORE_TESTS = true; - - private static final String TAG = "StreamingMediaPlayer2Test"; - - private static final String HTTP_H263_AMR_VIDEO_1_KEY = - "streaming_media_player_test_http_h263_amr_video1"; - private static final String HTTP_H263_AMR_VIDEO_2_KEY = - "streaming_media_player_test_http_h263_amr_video2"; - private static final String HTTP_H264_BASE_AAC_VIDEO_1_KEY = - "streaming_media_player_test_http_h264_base_aac_video1"; - private static final String HTTP_H264_BASE_AAC_VIDEO_2_KEY = - "streaming_media_player_test_http_h264_base_aac_video2"; - private static final String HTTP_MPEG4_SP_AAC_VIDEO_1_KEY = - "streaming_media_player_test_http_mpeg4_sp_aac_video1"; - private static final String HTTP_MPEG4_SP_AAC_VIDEO_2_KEY = - "streaming_media_player_test_http_mpeg4_sp_aac_video2"; - private static final String MODULE_NAME = "CtsMediaTestCases"; - private DynamicConfigDeviceSide dynamicConfig; - - private CtsTestServer mServer; - - private String mInputUrl; - - @Override - protected void setUp() throws Exception { - // if launched with InstrumentationTestRunner to pass a command line argument - if (getInstrumentation() instanceof InstrumentationTestRunner) { - InstrumentationTestRunner testRunner = - (InstrumentationTestRunner)getInstrumentation(); - - Bundle arguments = testRunner.getArguments(); - mInputUrl = arguments.getString("url"); - Log.v(TAG, "setUp: arguments: " + arguments); - if (mInputUrl != null) { - Log.v(TAG, "setUp: arguments[url] " + mInputUrl); - } - } - - super.setUp(); - dynamicConfig = new DynamicConfigDeviceSide(MODULE_NAME); - } - -/* RTSP tests are more flaky and vulnerable to network condition. - Disable until better solution is available - // Streaming RTSP video from YouTube - public void testRTSP_H263_AMR_Video1() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0x271de9756065677e" - + "&fmt=13&user=android-device-test", 176, 144); - } - public void testRTSP_H263_AMR_Video2() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0xc80658495af60617" - + "&fmt=13&user=android-device-test", 176, 144); - } - - public void testRTSP_MPEG4SP_AAC_Video1() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0x271de9756065677e" - + "&fmt=17&user=android-device-test", 176, 144); - } - public void testRTSP_MPEG4SP_AAC_Video2() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0xc80658495af60617" - + "&fmt=17&user=android-device-test", 176, 144); - } - - public void testRTSP_H264Base_AAC_Video1() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0x271de9756065677e" - + "&fmt=18&user=android-device-test", 480, 270); - } - public void testRTSP_H264Base_AAC_Video2() throws Exception { - playVideoTest("rtsp://v2.cache7.c.youtube.com/video.3gp?cid=0xc80658495af60617" - + "&fmt=18&user=android-device-test", 480, 270); - } -*/ - // Streaming HTTP video from YouTube - public void testHTTP_H263_AMR_Video1() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_H263, - MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_H263_AMR_VIDEO_1_KEY); - playVideoTest(urlString, 176, 144); - } - - public void testHTTP_H263_AMR_Video2() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_H263, - MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_H263_AMR_VIDEO_2_KEY); - playVideoTest(urlString, 176, 144); - } - - public void testHTTP_MPEG4SP_AAC_Video1() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_MPEG4_SP_AAC_VIDEO_1_KEY); - playVideoTest(urlString, 176, 144); - } - - public void testHTTP_MPEG4SP_AAC_Video2() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_MPEG4_SP_AAC_VIDEO_2_KEY); - playVideoTest(urlString, 176, 144); - } - - public void testHTTP_H264Base_AAC_Video1() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_H264_BASE_AAC_VIDEO_1_KEY); - playVideoTest(urlString, 640, 360); - } - - public void testHTTP_H264Base_AAC_Video2() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - String urlString = dynamicConfig.getValue(HTTP_H264_BASE_AAC_VIDEO_2_KEY); - playVideoTest(urlString, 640, 360); - } - - // Streaming HLS video from YouTube - public void testHLS() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - // Play stream for 60 seconds - playLiveVideoTest("http://www.youtube.com/api/manifest/hls_variant/id/" - + "0168724d02bd9945/itag/5/source/youtube/playlist_type/DVR/ip/" - + "0.0.0.0/ipbits/0/expire/19000000000/sparams/ip,ipbits,expire" - + ",id,itag,source,playlist_type/signature/773AB8ACC68A96E5AA48" - + "1996AD6A1BBCB70DCB87.95733B544ACC5F01A1223A837D2CF04DF85A336" - + "0/key/ik0/file/m3u8", 60 * 1000); - } - - public void testHlsWithHeadersCookies() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - final Uri uri = Uri.parse( - "http://www.youtube.com/api/manifest/hls_variant/id/" - + "0168724d02bd9945/itag/5/source/youtube/playlist_type/DVR/ip/" - + "0.0.0.0/ipbits/0/expire/19000000000/sparams/ip,ipbits,expire" - + ",id,itag,source,playlist_type/signature/773AB8ACC68A96E5AA48" - + "1996AD6A1BBCB70DCB87.95733B544ACC5F01A1223A837D2CF04DF85A336" - + "0/key/ik0/file/m3u8"); - - // TODO: dummy values for headers/cookies till we find a server that actually needs them - HashMap<String, String> headers = new HashMap<>(); - headers.put("header0", "value0"); - headers.put("header1", "value1"); - - String cookieName = "auth_1234567"; - String cookieValue = "0123456789ABCDEF0123456789ABCDEF"; - HttpCookie cookie = new HttpCookie(cookieName, cookieValue); - cookie.setHttpOnly(true); - cookie.setDomain("www.youtube.com"); - cookie.setPath("/"); // all paths - cookie.setSecure(false); - cookie.setDiscard(false); - cookie.setMaxAge(24 * 3600); // 24hrs - - java.util.Vector<HttpCookie> cookies = new java.util.Vector<HttpCookie>(); - cookies.add(cookie); - - // Play stream for 60 seconds - playLiveVideoTest(uri, headers, cookies, 60 * 1000); - } - - public void testHlsSampleAes_bbb_audio_only_overridable() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - String defaultUrl = "http://storage.googleapis.com/wvmedia/cenc/hls/sample_aes/" + - "bbb_1080p_30fps_11min/audio_only/prog_index.m3u8"; - - // if url override provided - String testUrl = (mInputUrl != null) ? mInputUrl : defaultUrl; - - // Play stream for 60 seconds - playLiveAudioOnlyTest( - testUrl, - 60 * 1000); - } - - public void testHlsSampleAes_bbb_unmuxed_1500k() throws Exception { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - - // Play stream for 60 seconds - playLiveVideoTest( - "http://storage.googleapis.com/wvmedia/cenc/hls/sample_aes/" + - "bbb_1080p_30fps_11min/unmuxed_1500k/prog_index.m3u8", - 60 * 1000); - } - - - // Streaming audio from local HTTP server - public void testPlayMp3Stream1() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("ringer.mp3", false, false); - } - public void testPlayMp3Stream2() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("ringer.mp3", false, false); - } - public void testPlayMp3StreamRedirect() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("ringer.mp3", true, false); - } - public void testPlayMp3StreamNoLength() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("noiseandchirps.mp3", false, true); - } - public void testPlayOggStream() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("noiseandchirps.ogg", false, false); - } - public void testPlayOggStreamRedirect() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("noiseandchirps.ogg", true, false); - } - public void testPlayOggStreamNoLength() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpAudioStreamTest("noiseandchirps.ogg", false, true); - } - public void testPlayMp3Stream1Ssl() throws Throwable { - if (IGNORE_TESTS) { - return; - } - localHttpsAudioStreamTest("ringer.mp3", false, false); - } - - private void localHttpAudioStreamTest(final String name, boolean redirect, boolean nolength) - throws Throwable { - mServer = new CtsTestServer(mContext); - try { - String stream_url = null; - if (redirect) { - // Stagefright doesn't have a limit, but we can't test support of infinite redirects - // Up to 4 redirects seems reasonable though. - stream_url = mServer.getRedirectingAssetUrl(name, 4); - } else { - stream_url = mServer.getAssetUrl(name); - } - if (nolength) { - stream_url = stream_url + "?" + CtsTestServer.NOLENGTH_POSTFIX; - } - - if (!MediaUtils.checkCodecsForPath(mContext, stream_url)) { - return; // skip - } - - final Uri uri = Uri.parse(stream_url); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - - mOnBufferingUpdateCalled.reset(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - fail("Media player had error " + what + " playing " + name); - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) { - mOnBufferingUpdateCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - assertFalse(mOnBufferingUpdateCalled.isSignalled()); - - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - if (nolength) { - mPlayer.play(); - Thread.sleep(LONG_SLEEP_TIME); - assertFalse(mPlayer.isPlaying()); - } else { - mOnBufferingUpdateCalled.waitForSignal(); - mPlayer.play(); - Thread.sleep(SLEEP_TIME); - } - mPlayer.stop(); - mPlayer.reset(); - } finally { - mServer.shutdown(); - } - } - private void localHttpsAudioStreamTest(final String name, boolean redirect, boolean nolength) - throws Throwable { - mServer = new CtsTestServer(mContext, true); - try { - String stream_url = null; - if (redirect) { - // Stagefright doesn't have a limit, but we can't test support of infinite redirects - // Up to 4 redirects seems reasonable though. - stream_url = mServer.getRedirectingAssetUrl(name, 4); - } else { - stream_url = mServer.getAssetUrl(name); - } - if (nolength) { - stream_url = stream_url + "?" + CtsTestServer.NOLENGTH_POSTFIX; - } - - final Uri uri = Uri.parse(stream_url); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - - mOnBufferingUpdateCalled.reset(); - - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - mOnErrorCalled.signal(); - } - - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) { - mOnBufferingUpdateCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - assertFalse(mOnBufferingUpdateCalled.isSignalled()); - try { - mPlayer.prepare(); - mOnErrorCalled.waitForSignal(); - } catch (Exception ex) { - return; - } - } finally { - mServer.shutdown(); - } - } - - // TODO: unhide this test when we sort out how to expose buffering control API. - private void doTestBuffering() throws Throwable { - final String name = "ringer.mp3"; - mServer = new CtsTestServer(mContext); - try { - String stream_url = mServer.getAssetUrl(name); - - if (!MediaUtils.checkCodecsForPath(mContext, stream_url)) { - Log.w(TAG, "can not find stream " + stream_url + ", skipping test"); - return; // skip - } - - Monitor onSetBufferingParamsCalled = new Monitor(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - fail("Media player had error " + what + " playing " + name); - } - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) { - mOnBufferingUpdateCalled.signal(); - } - } - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_SET_BUFFERING_PARAMS) { - mCallStatus = status; - onSetBufferingParamsCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - // getBufferingParams should be called after setDataSource. - try { - BufferingParams params = mPlayer.getBufferingParams(); - fail("MediaPlayer2 failed to check state for getBufferingParams"); - } catch (IllegalStateException e) { - // expected - } - - // setBufferingParams should be called after setDataSource. - BufferingParams params = new BufferingParams.Builder() - .setInitialMarkMs(2) - .setResumePlaybackMarkMs(3) - .build(); - mCallStatus = MediaPlayer2.CALL_STATUS_NO_ERROR; - onSetBufferingParamsCalled.reset(); - mPlayer.setBufferingParams(params); - onSetBufferingParamsCalled.waitForSignal(); - assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR); - - final Uri uri = Uri.parse(stream_url); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - - mOnBufferingUpdateCalled.reset(); - - assertFalse(mOnBufferingUpdateCalled.isSignalled()); - - params = mPlayer.getBufferingParams(); - - int newMark = params.getInitialMarkMs() + 2; - BufferingParams newParams = - new BufferingParams.Builder(params).setInitialMarkMs(newMark).build(); - - onSetBufferingParamsCalled.reset(); - mPlayer.setBufferingParams(newParams); - onSetBufferingParamsCalled.waitForSignal(); - - int checkMark = -1; - BufferingParams checkParams = mPlayer.getBufferingParams(); - checkMark = checkParams.getInitialMarkMs(); - assertEquals("marks do not match", newMark, checkMark); - - // TODO: add more dynamic checking, e.g., buffering shall not exceed pre-set mark. - - mPlayer.reset(); - } finally { - mServer.shutdown(); - } - } - - public void testPlayHlsStream() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - localHlsTest("hls.m3u8", false, false); - } - - public void testPlayHlsStreamWithQueryString() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - localHlsTest("hls.m3u8", true, false); - } - - public void testPlayHlsStreamWithRedirect() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - return; // skip - } - localHlsTest("hls.m3u8", false, true); - } - - public void testPlayHlsStreamWithTimedId3() throws Throwable { - if (IGNORE_TESTS) { - return; - } - if (!MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) { - Log.d(TAG, "Device doesn't have video codec, skipping test"); - return; - } - - mServer = new CtsTestServer(mContext); - try { - // counter must be final if we want to access it inside onTimedMetaData; - // use AtomicInteger so we can have a final counter object with mutable integer value. - final AtomicInteger counter = new AtomicInteger(); - String stream_url = mServer.getAssetUrl("prog_index.m3u8"); - final Uri uri = Uri.parse(stream_url); - mPlayer.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - mPlayer.setDisplay(getActivity().getSurfaceHolder()); - mPlayer.setScreenOnWhilePlaying(true); - mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK); - - final Object completion = new Object(); - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - int run; - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - mOnPrepareCalled.signal(); - } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) { - if (run++ == 0) { - mPlayer.seekTo(0, MediaPlayer2.SEEK_PREVIOUS_SYNC); - mPlayer.play(); - } else { - mPlayer.stop(); - synchronized (completion) { - completion.notify(); - } - } - } - } - - @Override - public void onTimedMetaDataAvailable(MediaPlayer2 mp, DataSourceDesc dsd, - TimedMetaData md) { - counter.incrementAndGet(); - long pos = mp.getCurrentPosition(); - long timeUs = md.getTimestamp(); - byte[] rawData = md.getMetaData(); - // Raw data contains an id3 tag holding the decimal string representation of - // the associated time stamp rounded to the closest half second. - - int offset = 0; - offset += 3; // "ID3" - offset += 2; // version - offset += 1; // flags - offset += 4; // size - offset += 4; // "TXXX" - offset += 4; // frame size - offset += 2; // frame flags - offset += 1; // "\x03" : UTF-8 encoded Unicode - offset += 1; // "\x00" : null-terminated empty description - - int length = rawData.length; - length -= offset; - length -= 1; // "\x00" : terminating null - - String data = new String(rawData, offset, length); - int dataTimeUs = Integer.parseInt(data); - assertTrue("Timed ID3 timestamp does not match content", - Math.abs(dataTimeUs - timeUs) < 500000); - assertTrue("Timed ID3 arrives after timestamp", pos * 1000 < timeUs); - } - - @Override - public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, - int what, int status) { - if (what == MediaPlayer2.CALL_COMPLETED_PLAY) { - mOnPlayCalled.signal(); - } - } - }; - mPlayer.setMediaPlayer2EventCallback(mExecutor, ecb); - - mPlayer.prepare(); - mOnPrepareCalled.waitForSignal(); - - mOnPlayCalled.reset(); - mPlayer.play(); - mOnPlayCalled.waitForSignal(); - assertTrue("MediaPlayer2 not playing", mPlayer.isPlaying()); - - int i = -1; - List<TrackInfo> trackInfos = mPlayer.getTrackInfo(); - for (i = 0; i < trackInfos.size(); i++) { - TrackInfo trackInfo = trackInfos.get(i); - if (trackInfo.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_METADATA) { - break; - } - } - assertTrue("Stream has no timed ID3 track", i >= 0); - mPlayer.selectTrack(i); - - synchronized (completion) { - completion.wait(); - } - - // There are a total of 19 metadata access units in the test stream; every one of them - // should be received twice: once before the seek and once after. - assertTrue("Incorrect number of timed ID3s recieved", counter.get() == 38); - } finally { - mServer.shutdown(); - } - } - - private static class WorkerWithPlayer implements Runnable { - private final Object mLock = new Object(); - private Looper mLooper; - private MediaPlayer2 mPlayer; - - /** - * Creates a worker thread with the given name. The thread - * then runs a {@link android.os.Looper}. - * @param name A name for the new thread - */ - WorkerWithPlayer(String name) { - Thread t = new Thread(null, this, name); - t.setPriority(Thread.MIN_PRIORITY); - t.start(); - synchronized (mLock) { - while (mLooper == null) { - try { - mLock.wait(); - } catch (InterruptedException ex) { - } - } - } - } - - public MediaPlayer2 getPlayer() { - return mPlayer; - } - - @Override - public void run() { - synchronized (mLock) { - Looper.prepare(); - mLooper = Looper.myLooper(); - mPlayer = MediaPlayer2.create(); - mLock.notifyAll(); - } - Looper.loop(); - } - - public void quit() { - mLooper.quit(); - mPlayer.close(); - } - } - - public void testBlockingReadRelease() throws Throwable { - if (IGNORE_TESTS) { - return; - } - - mServer = new CtsTestServer(mContext); - - WorkerWithPlayer worker = new WorkerWithPlayer("player"); - final MediaPlayer2 mp = worker.getPlayer(); - - try { - String path = mServer.getDelayedAssetUrl("noiseandchirps.ogg", 15000); - final Uri uri = Uri.parse(path); - mp.setDataSource(new DataSourceDesc.Builder() - .setDataSource(mContext, uri) - .build()); - - MediaPlayer2.MediaPlayer2EventCallback ecb = - new MediaPlayer2.MediaPlayer2EventCallback() { - @Override - public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) { - if (what == MediaPlayer2.MEDIA_INFO_PREPARED) { - fail("prepare should not succeed"); - } - } - }; - mp.setMediaPlayer2EventCallback(mExecutor, ecb); - - mp.prepare(); - Thread.sleep(1000); - long start = SystemClock.elapsedRealtime(); - mp.close(); - long end = SystemClock.elapsedRealtime(); - long releaseDuration = (end - start); - assertTrue("release took too long: " + releaseDuration, releaseDuration < 1000); - } catch (IllegalArgumentException e) { - fail(e.getMessage()); - } catch (SecurityException e) { - fail(e.getMessage()); - } catch (IllegalStateException e) { - fail(e.getMessage()); - } catch (InterruptedException e) { - fail(e.getMessage()); - } finally { - mServer.shutdown(); - } - - // give the worker a bit of time to start processing the message before shutting it down - Thread.sleep(5000); - worker.quit(); - } - - private void localHlsTest(final String name, boolean appendQueryString, boolean redirect) - throws Throwable { - mServer = new CtsTestServer(mContext); - try { - String stream_url = null; - if (redirect) { - stream_url = mServer.getQueryRedirectingAssetUrl(name); - } else { - stream_url = mServer.getAssetUrl(name); - } - if (appendQueryString) { - stream_url += "?foo=bar/baz"; - } - - playLiveVideoTest(stream_url, 10); - } finally { - mServer.shutdown(); - } - } -} diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp index fd0d37beb69..8ba89a2cb04 100644 --- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp +++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp @@ -1087,6 +1087,8 @@ void AHardwareBufferGLTest::SetUpFramebuffer(int width, int height, int layer, glRenderbufferStorage(GL_RENDERBUFFER, default_formats[i], width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_points[i], GL_RENDERBUFFER, renderbuffer); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); break; } default: FAIL() << "Unrecognized binding type"; diff --git a/tests/tests/net/jni/NativeMultinetworkJni.c b/tests/tests/net/jni/NativeMultinetworkJni.c index 2fa529191d2..69238cf9a37 100644 --- a/tests/tests/net/jni/NativeMultinetworkJni.c +++ b/tests/tests/net/jni/NativeMultinetworkJni.c @@ -179,13 +179,17 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); // For reference see: - // https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1 - uint8_t quic_packet[] = { - 0x0c, // public flags: 64bit conn ID, 8bit sequence number + // https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1 + uint8_t quic_packet[1200] = { + 0x0d, // public flags: + // - version present (0x01), + // - 64bit connection ID (0x0c), + // - 1 byte packet number (0x00) 0, 0, 0, 0, 0, 0, 0, 0, // 64bit connection ID - 0x01, // sequence number + 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number + 1, // 1 byte packet number 0x00, // private flags - 0x07, // type: regular frame type "PING" + 0x07, // PING frame (cuz why not) }; arc4random_buf(quic_packet + 1, 8); // random connection ID @@ -213,7 +217,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( i + 1, MAX_RETRIES, rcvd, errnum); } } - if (rcvd < sent) { + if (rcvd < 9) { ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum); if (rcvd <= 0) { ALOGD("Does this network block UDP port %s?", kPort); @@ -229,8 +233,7 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck( return -EPROTO; } - // TODO: log, and compare to the IP address encoded in the - // response, since this should be a public reset packet. + // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code. close(fd); return 0; diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java index d7f0853af2b..cdd2588fca1 100644 --- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java +++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java @@ -27,6 +27,7 @@ import android.os.Looper; import android.os.ProxyFileDescriptorCallback; import android.os.Parcel; import android.os.ParcelFileDescriptor; +import android.os.UserManager; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; @@ -69,15 +70,22 @@ public class StorageManagerTest extends AndroidTestCase { private static final String TEST1_NEW_CONTENTS = "1\n"; private StorageManager mStorageManager; + private UserManager mUserManager; private final Handler mHandler = new Handler(Looper.getMainLooper()); @Override protected void setUp() throws Exception { super.setUp(); mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); } public void testMountAndUnmountObbNormal() throws IOException { + // Mount obb only works for system user. Skip for secondary users. + if (!mUserManager.isSystemUser()) { + return; + } + for (File target : getTargetFiles()) { target = new File(target, "test1_new.obb"); Log.d(TAG, "Testing path " + target); @@ -104,6 +112,11 @@ public class StorageManagerTest extends AndroidTestCase { } public void testAttemptMountNonObb() { + // Mount obb only works for system user. Skip for secondary users. + if (!mUserManager.isSystemUser()) { + return; + } + for (File target : getTargetFiles()) { target = new File(target, "test1_nosig.obb"); Log.d(TAG, "Testing path " + target); @@ -141,6 +154,11 @@ public class StorageManagerTest extends AndroidTestCase { } public void testMountAndUnmountTwoObbs() throws IOException { + // Mount obb only works for system user. Skip for secondary users. + if (!mUserManager.isSystemUser()) { + return; + } + for (File target : getTargetFiles()) { Log.d(TAG, "Testing target " + target); final File test1 = new File(target, "test1.obb"); diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java index 9ed199e850b..9e65d0b90ca 100644 --- a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java +++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java @@ -267,7 +267,8 @@ public class MediaStoreUiTest extends InstrumentationTestCase { private boolean supportsHardware() { final PackageManager pm = getInstrumentation().getContext().getPackageManager(); - return !pm.hasSystemFeature("android.hardware.type.television") + return !pm.hasSystemFeature("android.hardware.type.automotive") + && !pm.hasSystemFeature("android.hardware.type.television") && !pm.hasSystemFeature("android.hardware.type.watch"); } diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk index f4ae8a723d7..3d4498d8d33 100644 --- a/tests/tests/security/Android.mk +++ b/tests/tests/security/Android.mk @@ -27,6 +27,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ctstestserver \ ctstestrunner-axt \ compatibility-device-util-axt \ + compatibility-common-util-devicesidelib \ guava \ platform-test-annotations diff --git a/tests/tests/security/res/raw/bug_73552574_avc.mp4 b/tests/tests/security/res/raw/bug_73552574_avc.mp4 Binary files differnew file mode 100644 index 00000000000..1cca70ced45 --- /dev/null +++ b/tests/tests/security/res/raw/bug_73552574_avc.mp4 diff --git a/tests/tests/security/res/raw/bug_73552574_framelen.mp4 b/tests/tests/security/res/raw/bug_73552574_framelen.mp4 new file mode 100644 index 00000000000..36728cc8ff7 --- /dev/null +++ b/tests/tests/security/res/raw/bug_73552574_framelen.mp4 @@ -0,0 +1,93 @@ +48 +4 +28 +208 +0 +10 +39 +386 +8 +70 +6 +32 +31 +4 +8 +24 +10 +22 +12 +108 +9 +229 +38 +12 +10 +166 +39 +250 +43 +8 +70 +6 +29 +12 +4 +8 +33 +12 +0 +10 +156 +10 +39 +94 +10 +39 +386 +8 +70 +6 +10 +31 +4 +8 +24 +10 +22 +12 +70 +9 +420 +0 +8 +36 +6 +12 +20 +31 +102 +229 +38 +12 +10 +156 +10 +39 +197 +251 +38 +12 +10 +156 +10 +180 +10 +39 +386 +8 +70 +6 +32 +31 +6441 diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java index 07b39de608d..ed6cf5c7196 100644 --- a/tests/tests/security/src/android/security/cts/EncryptionTest.java +++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java @@ -22,6 +22,7 @@ import android.platform.test.annotations.SecurityTest; import android.test.AndroidTestCase; import junit.framework.TestCase; +import android.content.pm.PackageManager; import android.content.Context; import android.util.Log; import java.io.BufferedReader; @@ -46,7 +47,13 @@ public class EncryptionTest extends AndroidTestCase { private boolean isRequired() { // Optional before MIN_API_LEVEL - return PropertyUtil.getFirstApiLevel() >= MIN_API_LEVEL; + return PropertyUtil.getFirstApiLevel() >= MIN_API_LEVEL && !isTelevision(); + } + + private boolean isTelevision() { + PackageManager pm = getContext().getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION) + || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK); } public void testEncryption() throws Exception { diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java index adf8131aff7..627fc27c85a 100644 --- a/tests/tests/security/src/android/security/cts/StagefrightTest.java +++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java @@ -62,6 +62,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Pattern; import org.json.JSONArray; import org.json.JSONException; @@ -731,6 +732,12 @@ public class StagefrightTest extends InstrumentationTestCase { ***********************************************************/ @SecurityTest + public void testBug_73552574() throws Exception { + int[] frameSizes = getFrameSizes(R.raw.bug_73552574_framelen); + doStagefrightTestRawBlob(R.raw.bug_73552574_avc, "video/avc", 320, 240, frameSizes); + } + + @SecurityTest public void testStagefright_cve_2017_0474() throws Exception { doStagefrightTest(R.raw.cve_2017_0474, 120000); } @@ -939,8 +946,23 @@ public class StagefrightTest extends InstrumentationTestCase { MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener { - private final String[] validProcessNames = { - "mediaserver", "mediadrmserver", "media.extractor", "media.codec", "media.metrics" + private final Pattern[] validProcessPatterns = { + Pattern.compile("adsprpcd"), + Pattern.compile("android\\.hardware\\.cas@\\d+?\\.\\d+?-service"), + Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service"), + Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.clearkey"), + Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.widevine"), + Pattern.compile("android\\.process\\.media"), + Pattern.compile("mediadrmserver"), + Pattern.compile("media\\.extractor"), + Pattern.compile("media\\.metrics"), + Pattern.compile("mediaserver"), + Pattern.compile("media\\.codec"), + Pattern.compile("media\\.swcodec"), + Pattern.compile("\\[?sdcard\\]?"), // name:/system/bin/sdcard, user:media_rw + // Match any vendor processes. + // It should only catch crashes that happen during the test. + Pattern.compile("vendor.*"), }; @Override @@ -988,7 +1010,7 @@ public class StagefrightTest extends InstrumentationTestCase { if (crashes == null) { Log.e(TAG, "Crash results not found for test " + getName()); return what; - } else if (CrashUtils.detectCrash(validProcessNames, true, crashes)) { + } else if (CrashUtils.securityCrashDetected(crashes, true, validProcessPatterns)) { return what; } else { Log.i(TAG, "Crash ignored due to no security crash found for test " + diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java index 7628c821102..79b6bd151fa 100644 --- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java +++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java @@ -18,7 +18,7 @@ package android.content.pm.cts.shortcutmanager; import static android.content.pm.cts.shortcutmanager.common.Constants.INLINE_REPLY_REMOTE_INPUT_CAPTION; -import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetThrottling; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAllThrottling; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.runCommandForNoOutput; import android.content.ComponentName; @@ -64,7 +64,7 @@ public class ShortcutManagerThrottlingTest extends ShortcutManagerCtsTestsBase { protected void setUp() throws Exception { super.setUp(); - resetThrottling(getInstrumentation()); + resetAllThrottling(getInstrumentation()); UiDevice.getInstance(getInstrumentation()).pressHome(); diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java index 6a3653631b6..fdf81deaff5 100644 --- a/tests/tests/telephony/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java +++ b/tests/tests/telephony/src/android/telephony/cts/SmsUsageMonitorShortCodeTest.java @@ -502,6 +502,13 @@ public class SmsUsageMonitorShortCodeTest extends InstrumentationTestCase { SmsUsageMonitor monitor = new SmsUsageMonitor(mContext); for (ShortCodeTest test : sShortCodeTests) { + // It is intended that a short code number in country A may be an emergency number + // in country B. It is intended that the destination will be changed because of this + // reason. checkDestination() returns CATEGORY_NOT_SHORT_CODE for emergency numbers. + if (test.category != CATEGORY_NOT_SHORT_CODE + && PhoneNumberUtils.isEmergencyNumber(test.address, test.countryIso)) { + continue; + } assertEquals("country: " + test.countryIso + " number: " + test.address, test.category, monitor.checkDestination(test.address, test.countryIso)); } diff --git a/tests/tests/text/src/android/text/format/cts/TimeTest.java b/tests/tests/text/src/android/text/format/cts/TimeTest.java index 267b705fa6c..6112b73ad62 100644 --- a/tests/tests/text/src/android/text/format/cts/TimeTest.java +++ b/tests/tests/text/src/android/text/format/cts/TimeTest.java @@ -2824,6 +2824,13 @@ public class TimeTest { Fields.verifyTimeEquals(expected, t); } + @Test + public void test_bug118835133() { + Time t = new Time("Asia/Singapore"); + Fields.set(t, 2018, 9, 30, 12, 48, 32, 0 /* isDst */, 0, 0, 0); + // With http://b/118835133 toMillis() returns -1. + assertEquals(1540874912000L, t.toMillis(true /* ignoreDst */)); + } private static void verifyNormalizeResult(boolean normalizeArgument, Time toNormalize, Time expectedTime, long expectedTimeMillis) { long actualTimeMillis = toNormalize.normalize(normalizeArgument /* ignore isDst */); diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java index e19dfe84e73..34ffd767a99 100644 --- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java +++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java @@ -263,8 +263,18 @@ public class ScrollingMovementMethodTest { assertTrue(mTextView.getScrollY() > previousScrollY); assertTrue(mTextView.getScrollX() < bottom); + assertTrue(getActionResult(new ActionRunnerWithResult() { + public void run() { + // move back up for the next test + mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now, + MotionEvent.ACTION_MOVE, 0, -distFar, 0)); + } + })); + previousScrollY = mTextView.getScrollY(); - final int distTooFar = (int) (-bottom * 10); + // further detracting mScaledTouchSlop from (-bottom * 10) so it is guaranteed to be + // greater than the touch slop value. + final int distTooFar = (int) (-bottom * 10) - mScaledTouchSlop; assertTrue(getActionResult(new ActionRunnerWithResult() { public void run() { // move for long distance diff --git a/tests/tests/transition/res/values/styles.xml b/tests/tests/transition/res/values/styles.xml index 00303c93609..be2272eacb8 100644 --- a/tests/tests/transition/res/values/styles.xml +++ b/tests/tests/transition/res/values/styles.xml @@ -14,7 +14,7 @@ limitations under the License. --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="Theme_NoSwipeDismiss"> + <style name="Theme_NoSwipeDismiss" parent="android:Theme.DeviceDefault"> <item name="android:windowSwipeToDismiss">false</item> </style> </resources> diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java index f69e961cab0..acd68495f6b 100644 --- a/tests/tests/view/src/android/view/cts/ViewTest.java +++ b/tests/tests/view/src/android/view/cts/ViewTest.java @@ -119,7 +119,9 @@ import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -2946,6 +2948,92 @@ public class ViewTest { assertFalse(mockView1.hasCalledOnTouchEvent()); } + /** + * Ensure two MotionEvents are equal, for the purposes of this test only. + * Only compare actions, source, and times. + * Do not compare coordinates, because the injected event has coordinates relative to + * the screen, while the event received by view will be adjusted relative to the parent. + * + * Due to event batching, if two or more input events are injected / occur between two + * consecutive vsync's, they might end up getting combined into a single MotionEvent. + * It is caller's responsibility to ensure that the events were injected with a gap that's + * larger than time between two vsyncs, in order for this function to behave predictably. + * + * Recycle both MotionEvents. + */ + private static void compareAndRecycleMotionEvents(MotionEvent event1, MotionEvent event2) { + if (event1 == null && event2 == null) { + return; + } + + if (event1 == null) { + event2.recycle(); + fail("Expected non-null event in first position"); + } + if (event2 == null) { + event1.recycle(); + fail("Expected non-null event in second position"); + } + + assertEquals(event1.getAction(), event2.getAction()); + assertEquals(event1.getPointerCount(), event2.getPointerCount()); + assertEquals(event1.getSource(), event2.getSource()); + assertEquals(event1.getDownTime(), event2.getDownTime()); + // If resampling occurs, the "real" (injected) events will become historical data, + // and resampled events will be inserted into MotionEvent and returned by the standard api. + // Since the injected event should contain no history, but the event received by + // the view might, we could distinguish them. But for simplicity, only require that + // the events are close in time if historical data is present. + if (event1.getHistorySize() == 0 && event2.getHistorySize() == 0) { + assertEquals(event1.getEventTime(), event2.getEventTime()); + } else { + assertEquals(event1.getEventTime(), event2.getEventTime(), 20 /*delta*/); + } + + event1.recycle(); + event2.recycle(); + } + + @Test + public void testOnTouchListener() { + BlockingQueue<MotionEvent> events = new LinkedBlockingQueue<>(); + class TestTouchListener implements View.OnTouchListener { + @Override + public boolean onTouch(View v, MotionEvent event) { + events.add(MotionEvent.obtain(event)); + return true; + } + } + + // Inject some touch events + TestTouchListener listener = new TestTouchListener(); + View view = mActivity.findViewById(R.id.mock_view); + view.setOnTouchListener(listener); + + int[] xy = new int[2]; + view.getLocationOnScreen(xy); + + final int viewWidth = view.getWidth(); + final int viewHeight = view.getHeight(); + final float x = xy[0] + viewWidth / 2.0f; + final float y = xy[1] + viewHeight / 2.0f; + + final long downTime = SystemClock.uptimeMillis(); + MotionEvent downEvent = + MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0); + downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mInstrumentation.getUiAutomation().injectInputEvent(downEvent, true); + final long eventTime = SystemClock.uptimeMillis(); + MotionEvent upEvent = + MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); + upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mInstrumentation.getUiAutomation().injectInputEvent(upEvent, true); + + compareAndRecycleMotionEvents(downEvent, events.poll()); + compareAndRecycleMotionEvents(upEvent, events.poll()); + assertTrue(events.isEmpty()); + } + @Test public void testInvalidate1() throws Throwable { final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java index 4cc5ec6ed26..606bde98168 100644 --- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java +++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; import android.app.Instrumentation; import android.app.UiAutomation; import android.content.res.Configuration; +import android.content.res.Resources; import android.text.TextUtils; import android.view.accessibility.AccessibilityEvent; import android.widget.NumberPicker; @@ -340,11 +341,15 @@ public class NumberPickerTest { final int[] numberPickerLocationOnScreen = new int[2]; mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen); + int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; + int numberPickerMiddleX = numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2; + int numberPickerStartY = numberPickerLocationOnScreen[1] + 1; + CtsTouchUtils.emulateDragGesture(mInstrumentation, - numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2, - numberPickerLocationOnScreen[1] + 1, + numberPickerMiddleX, + numberPickerStartY, 0, - mNumberPicker.getHeight() - 2); + screenHeight - numberPickerStartY); // drag down to the bottom of the screen. // At this point we expect that the drag-down gesture has selected the value // that was "above" the previously selected one, and that our value change listener @@ -389,12 +394,15 @@ public class NumberPickerTest { final int[] numberPickerLocationOnScreen = new int[2]; mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen); + int numberPickerMiddleX = numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2; + int numberPickerEndY = numberPickerLocationOnScreen[1] + mNumberPicker.getHeight() - 1; + mUiAutomation.executeAndWaitForEvent(() -> CtsTouchUtils.emulateDragGesture(mInstrumentation, - numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2, - numberPickerLocationOnScreen[1] + mNumberPicker.getHeight() - 1, + numberPickerMiddleX, + numberPickerEndY, 0, - -(mNumberPicker.getHeight() - 2)), + -(numberPickerEndY)), // drag up to the top of the screen. (AccessibilityEvent event) -> event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED, TIMEOUT_ACCESSIBILITY_EVENT); @@ -434,4 +442,5 @@ public class NumberPickerTest { mNumberPicker.setWrapSelectorWheel(true); assertTrue(mNumberPicker.getWrapSelectorWheel()); } + } diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java index 54d7c2232ca..15bcb3bd6aa 100644 --- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java +++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java @@ -160,7 +160,7 @@ public class ZoomButtonTest { assertTrue("First callback should have happened sooner than " + actualTimeUntilFirstInvocationNs / NANOS_IN_MILLI, (callbackFirstInvocationTime - startTime) - <= (minTimeUntilFirstInvocationMs + 100) * NANOS_IN_MILLI); + <= (minTimeUntilFirstInvocationMs + 200) * NANOS_IN_MILLI); } } |