Merge "Check config in multi-display tests" into oc-dev
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index d20cb4a..b1c8177 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -23,6 +23,9 @@
import its.device
from its.device import ItsSession
+CHART_DELAY = 1 # seconds
+
+
def main():
"""Run all the automated tests, saving intermediate files, and producing
a summary/report of the results.
@@ -227,6 +230,8 @@
cmd = ['python',
os.path.join(os.getcwd(), 'tools/load_scene.py'),
scene_arg, screen_id_arg]
+ else:
+ time.sleep(CHART_DELAY)
else:
# Skip scene validation for scene 5 running in parallel
if not merge_result_switch or scene != 'scene5':
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 3a96709..99a4ee3 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1959,6 +1959,46 @@
android:label="@string/aware_data_path_open_passive_subscribe"
android:configChanges="keyboardHidden|orientation|screenSize" />
+ <activity android:name=".wifiaware.DataPathPassphraseUnsolicitedPublishTestActivity"
+ android:label="@string/aware_data_path_passphrase_unsolicited_publish"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathPassphrasePassiveSubscribeTestActivity"
+ android:label="@string/aware_data_path_passphrase_passive_subscribe"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOpenSolicitedPublishTestActivity"
+ android:label="@string/aware_data_path_open_solicited_publish"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOpenActiveSubscribeTestActivity"
+ android:label="@string/aware_data_path_open_active_subscribe"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathPassphraseSolicitedPublishTestActivity"
+ android:label="@string/aware_data_path_passphrase_solicited_publish"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathPassphraseActiveSubscribeTestActivity"
+ android:label="@string/aware_data_path_passphrase_active_subscribe"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOobOpenResponderTestActivity"
+ android:label="@string/aware_data_path_oob_open_responder"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOobOpenInitiatorTestActivity"
+ android:label="@string/aware_data_path_oob_open_initiator"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOobPassphraseResponderTestActivity"
+ android:label="@string/aware_data_path_oob_passphrase_responder"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
+ <activity android:name=".wifiaware.DataPathOobPassphraseInitiatorTestActivity"
+ android:label="@string/aware_data_path_oob_passphrase_initiator"
+ android:configChanges="keyboardHidden|orientation|screenSize" />
+
<activity-alias android:name=".CtsVerifierActivity" android:label="@string/app_name"
android:targetActivity=".TestListActivity">
<intent-filter>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 2d7c498..02cb70f 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1392,13 +1392,71 @@
Test failed.\n\nUnexpected error. Check logcat.</string>
<string name="aware_dp_ib_open_unsolicited">Data Path: Open: Unsolicited/Passive</string>
+ <string name="aware_dp_ib_passphrase_unsolicited">Data Path: Passphrase: Unsolicited/Passive</string>
+ <string name="aware_dp_ib_open_solicited">Data Path: Open: Solicited/Active</string>
+ <string name="aware_dp_ib_passphrase_solicited">Data Path: Passphrase: Solicited/Active</string>
<string name="aware_publish">Publish</string>
<string name="aware_subscribe">Subscribe</string>
+ <string name="aware_dp_oob_open">Data Path (OOB): Open</string>
+ <string name="aware_dp_oob_passphrase">Data Path (OOB): Passphrase</string>
+ <string name="aware_responder">Responder</string>
+ <string name="aware_initiator">Initiator</string>
+
+ <string name="aware_status_attached">Attached ...</string>
+ <string name="aware_status_attach_fail">Attach failure!</string>
+ <string name="aware_status_attach_timeout">Attach failure - timed out!</string>
+ <string name="aware_status_identity">Discovery (Identity) MAC address: %1$s ...</string>
+ <string name="aware_status_identity_fail">Identity listener failure - timed out!</string>
+ <string name="aware_status_subscribe_started">Subscribe discovery session started ...</string>
+ <string name="aware_status_subscribe_failed">Subscribe failure!</string>
+ <string name="aware_status_subscribe_timeout">Subscribe failure - timed out!</string>
+ <string name="aware_status_subscribe_null_session">Subscribe failure - null session!</string>
+ <string name="aware_status_publish_started">Publish discovery session started ...</string>
+ <string name="aware_status_publish_failed">Publish failure!</string>
+ <string name="aware_status_publish_timeout">Publish failure - timed out!</string>
+ <string name="aware_status_publish_null_session">Publish failure - null session!</string>
+ <string name="aware_status_discovery">Service discovered ...</string>
+ <string name="aware_status_discovery_timeout">Service discovery failure - timed out!</string>
+ <string name="aware_status_discovery_fail">Service discovery failure - parameter mismatch!</string>
+ <string name="aware_status_send_success">Sent message successfully ...</string>
+ <string name="aware_status_send_failed">Send message failure!</string>
+ <string name="aware_status_send_timeout">Send message failure - timed out!</string>
+ <string name="aware_status_send_fail_parameter">Send message failure - mismatched ids!</string>
+ <string name="aware_status_received">Received message ...</string>
+ <string name="aware_status_received_mac">Received peer MAC address: %1$s ...</string>
+ <string name="aware_status_receive_timeout">Receive message failure - timed out!</string>
+ <string name="aware_status_receive_failure">Receive message failure - didn\'t receive expected message!</string>
+ <string name="aware_status_network_requested">Network requested ...</string>
+ <string name="aware_status_network_success">Network formed ...</string>
+ <string name="aware_status_network_failed">Network request failure - timed out!</string>
+ <string name="aware_status_sleeping_wait_for_responder">Pausing to let Responder time to set up ...</string>
+ <string name="aware_status_lifecycle_ok">Discovery lifecycle validated!</string>
+
<string name="aware_data_path_open_unsolicited_publish">Data Path: Open: Unsolicited Publish</string>
<string name="aware_data_path_open_unsolicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Open: Unsolicited/Passive\' / \'Subscribe\' test.</string>
<string name="aware_data_path_open_passive_subscribe">Data Path: Open: Passive Subscribe</string>
+ <string name="aware_data_path_passphrase_unsolicited_publish">Data Path: Passphrase: Unsolicited Publish</string>
+ <string name="aware_data_path_passphrase_unsolicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Passphrase: Unsolicited/Passive\' / \'Subscribe\' test.</string>
+ <string name="aware_data_path_passphrase_passive_subscribe">Data Path: Passphrase: Passive Subscribe</string>
+
+ <string name="aware_data_path_open_solicited_publish">Data Path: Open: Solicited Publish</string>
+ <string name="aware_data_path_open_solicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Open: Solicited/Active\' / \'Subscribe\' test.</string>
+ <string name="aware_data_path_open_active_subscribe">Data Path: Open: Active Subscribe</string>
+
+ <string name="aware_data_path_passphrase_solicited_publish">Data Path: Passphrase: Solicited Publish</string>
+ <string name="aware_data_path_passphrase_solicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Passphrase: Solicited/Active\' / \'Subscribe\' test.</string>
+ <string name="aware_data_path_passphrase_active_subscribe">Data Path: Passphrase: Active Subscribe</string>
+
+ <string name="aware_data_path_oob_open_responder">Data Path (OOB): Open: Responder</string>
+ <string name="aware_data_path_oob_open_responder_info">The responder is now ready.\n\nOn the other device: start the \'Data Path (OOB): Open\' / \'Initiator\' test.</string>
+ <string name="aware_data_path_oob_open_initiator">Data Path (OOB): Open: Initiator</string>
+
+ <string name="aware_data_path_oob_passphrase_responder">Data Path (OOB): Passphrase: Responder</string>
+ <string name="aware_data_path_oob_passphrase_responder_info">The responder is now ready.\n\nOn the other device: start the \'Data Path (OOB): Passphrase\' / \'Initiator\' test.</string>
+ <string name="aware_data_path_oob_passphrase_initiator">Data Path (OOB): Passphrase: Initiator</string>
+
<string name="camera_fov_calibration">Camera FOV Calibration</string>
<string name="camera_fov_calibration_done">Done</string>
<string name="camera_fov_general_settings">General settings</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/BaseTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/BaseTestCase.java
index 523487d..8556b19 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/BaseTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/BaseTestCase.java
@@ -17,6 +17,7 @@
package com.android.cts.verifier.wifiaware;
import android.content.Context;
+import android.content.res.Resources;
import android.net.wifi.aware.WifiAwareManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -28,6 +29,7 @@
*/
public abstract class BaseTestCase {
protected Context mContext;
+ protected Resources mResources;
protected Listener mListener;
private Thread mThread;
@@ -38,6 +40,7 @@
public BaseTestCase(Context context) {
mContext = context;
+ mResources = mContext.getResources();
}
/**
@@ -152,4 +155,27 @@
*/
void onTestFailed(String reason);
}
+
+ /**
+ * Convert byte array to hex string representation utility.
+ */
+ public static String bytesToHex(byte[] bytes, Character separator) {
+ final char[] hexArray = "0123456789ABCDEF".toCharArray();
+ boolean useSeparator = separator != null;
+ char sep = 0;
+ if (useSeparator) {
+ sep = separator;
+ }
+ char[] hexChars = new char[bytes.length * 2 + (useSeparator ? bytes.length - 1 : 0)];
+ int base = 0;
+ for (int j = 0; j < bytes.length; j++) {
+ if (useSeparator && j != 0) {
+ hexChars[base++] = sep;
+ }
+ int v = bytes[j] & 0xFF;
+ hexChars[base++] = hexArray[v >> 4];
+ hexChars[base++] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
new file mode 100644
index 0000000..4593ed4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.wifi.aware.AttachCallback;
+import android.net.wifi.aware.DiscoverySessionCallback;
+import android.net.wifi.aware.IdentityChangedListener;
+import android.net.wifi.aware.PeerHandle;
+import android.net.wifi.aware.PublishDiscoverySession;
+import android.net.wifi.aware.SubscribeDiscoverySession;
+import android.net.wifi.aware.WifiAwareSession;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Blocking callbacks for Wi-Fi Aware and Connectivity Manager.
+ */
+public class CallbackUtils {
+ private static final String TAG = "CallbackUtils";
+
+ public static final int CALLBACK_TIMEOUT_SEC = 15;
+
+ /**
+ * Utility AttachCallback - provides mechanism to block execution with the
+ * waitForAttach method.
+ */
+ public static class AttachCb extends AttachCallback {
+ public static final int TIMEOUT = -1;
+ public static final int ON_ATTACHED = 0;
+ public static final int ON_ATTACH_FAILED = 1;
+
+ private CountDownLatch mBlocker = new CountDownLatch(1);
+ private int mCallback = TIMEOUT;
+ private WifiAwareSession mWifiAwareSession = null;
+
+ @Override
+ public void onAttached(WifiAwareSession session) {
+ mCallback = ON_ATTACHED;
+ mWifiAwareSession = session;
+ mBlocker.countDown();
+ }
+
+ @Override
+ public void onAttachFailed() {
+ mCallback = ON_ATTACH_FAILED;
+ mBlocker.countDown();
+ }
+
+ /**
+ * Wait (blocks) for any AttachCallback callback or timeout.
+ *
+ * @return A pair of values: the callback constant (or TIMEOUT) and the WifiAwareSession
+ * created when attach successful - null otherwise (attach failure or timeout).
+ */
+ public Pair<Integer, WifiAwareSession> waitForAttach() throws InterruptedException {
+ if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ return new Pair<>(mCallback, mWifiAwareSession);
+ }
+
+ return new Pair<>(TIMEOUT, null);
+ }
+ }
+
+ /**
+ * Utility IdentityChangedListener - provides mechanism to block execution with the
+ * waitForIdentity method. Single shot listener - only listens for the first triggered
+ * callback.
+ */
+ public static class IdentityListenerSingleShot extends IdentityChangedListener {
+ private CountDownLatch mBlocker = new CountDownLatch(1);
+ private byte[] mMac = null;
+
+ @Override
+ public void onIdentityChanged(byte[] mac) {
+ if (mMac != null) {
+ return;
+ }
+
+ mMac = mac;
+ mBlocker.countDown();
+ }
+
+ /**
+ * Wait (blocks) for the onIdentityChanged callback or a timeout.
+ *
+ * @return The MAC address returned by the onIdentityChanged() callback, or null on timeout.
+ */
+ public byte[] waitForMac() throws InterruptedException {
+ if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ return mMac;
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Utility NetworkCallback - provides mechanism for blocking/serializing access with the
+ * waitForNetwork method.
+ */
+ public static class NetworkCb extends ConnectivityManager.NetworkCallback {
+ private CountDownLatch mBlocker = new CountDownLatch(1);
+ private boolean mNetworkAvailable = false;
+
+ @Override
+ public void onAvailable(Network network) {
+ mNetworkAvailable = true;
+ mBlocker.countDown();
+ }
+
+ @Override
+ public void onUnavailable() {
+ mNetworkAvailable = false;
+ mBlocker.countDown();
+ }
+
+ /**
+ * Wait (blocks) for Available or Unavailable callbacks - or timesout.
+ *
+ * @return true if Available, false otherwise (Unavailable or timeout).
+ */
+ public boolean waitForNetwork() throws InterruptedException {
+ if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ return mNetworkAvailable;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Utility DiscoverySessionCallback - provides mechanism to block/serialize Aware discovery
+ * operations using the waitForCallbacks() method.
+ */
+ public static class DiscoveryCb extends DiscoverySessionCallback {
+ public static final int TIMEOUT = -1;
+ public static final int ON_PUBLISH_STARTED = 0x1 << 0;
+ public static final int ON_SUBSCRIBE_STARTED = 0x1 << 1;
+ public static final int ON_SESSION_CONFIG_UPDATED = 0x1 << 2;
+ public static final int ON_SESSION_CONFIG_FAILED = 0x1 << 3;
+ public static final int ON_SESSION_TERMINATED = 0x1 << 4;
+ public static final int ON_SERVICE_DISCOVERED = 0x1 << 5;
+ public static final int ON_MESSAGE_SEND_SUCCEEDED = 0x1 << 6;
+ public static final int ON_MESSAGE_SEND_FAILED = 0x1 << 7;
+ public static final int ON_MESSAGE_RECEIVED = 0x1 << 8;
+
+ /**
+ * Data container for all parameters which can be returned by any DiscoverySessionCallback
+ * callback.
+ */
+ public static class CallbackData {
+ public CallbackData(int callback) {
+ this.callback = callback;
+ }
+
+ public int callback;
+
+ public PublishDiscoverySession publishDiscoverySession;
+ public SubscribeDiscoverySession subscribeDiscoverySession;
+ public PeerHandle peerHandle;
+ public byte[] serviceSpecificInfo;
+ public List<byte[]> matchFilter;
+ public int messageId;
+ }
+
+ private CountDownLatch mBlocker = null;
+ private int mWaitForCallbackMask = 0;
+
+ private final Object mLock = new Object();
+ private ArrayDeque<CallbackData> mCallbackQueue = new ArrayDeque<>();
+
+ private void processCallback(CallbackData callbackData) {
+ synchronized (mLock) {
+ mCallbackQueue.addLast(callbackData);
+ if (mBlocker != null && (mWaitForCallbackMask & callbackData.callback)
+ == callbackData.callback) {
+ mBlocker.countDown();
+ }
+ }
+ }
+
+ private CallbackData getAndRemoveFirst(int callbackMask) {
+ synchronized (mLock) {
+ for (CallbackData cbd : mCallbackQueue) {
+ if ((cbd.callback & callbackMask) == cbd.callback) {
+ mCallbackQueue.remove(cbd);
+ return cbd;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private CallbackData waitForCallbacks(int callbackMask, boolean timeout)
+ throws InterruptedException {
+ synchronized (mLock) {
+ CallbackData cbd = getAndRemoveFirst(callbackMask);
+ if (cbd != null) {
+ return cbd;
+ }
+
+ mWaitForCallbackMask = callbackMask;
+ mBlocker = new CountDownLatch(1);
+ }
+
+ boolean finishedNormally = true;
+ if (timeout) {
+ finishedNormally = mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS);
+ } else {
+ mBlocker.await();
+ }
+ if (finishedNormally) {
+ CallbackData cbd = getAndRemoveFirst(callbackMask);
+ if (cbd != null) {
+ return cbd;
+ }
+
+ Log.wtf(TAG, "DiscoveryCb.waitForCallback: callbackMask=" + callbackMask
+ + ": did not time-out but doesn't have any of the requested callbacks in "
+ + "the stack!?");
+ // falling-through to TIMEOUT
+ }
+
+ return new CallbackData(TIMEOUT);
+ }
+
+ /**
+ * Wait for the specified callbacks - a bitmask of any of the ON_* constants. Returns the
+ * CallbackData structure whose CallbackData.callback specifies the callback which was
+ * triggered. The callback may be TIMEOUT.
+ *
+ * Note: other callbacks happening while while waiting for the specified callback(s) will
+ * be queued.
+ */
+ public CallbackData waitForCallbacks(int callbackMask) throws InterruptedException {
+ return waitForCallbacks(callbackMask, true);
+ }
+
+ /**
+ * Wait for the specified callbacks - a bitmask of any of the ON_* constants. Returns the
+ * CallbackData structure whose CallbackData.callback specifies the callback which was
+ * triggered.
+ *
+ * This call will not timeout - it can be interrupted though (which results in a thrown
+ * exception).
+ *
+ * Note: other callbacks happening while while waiting for the specified callback(s) will
+ * be queued.
+ */
+ public CallbackData waitForCallbacksNoTimeout(int callbackMask)
+ throws InterruptedException {
+ return waitForCallbacks(callbackMask, false);
+ }
+
+ @Override
+ public void onPublishStarted(PublishDiscoverySession session) {
+ CallbackData callbackData = new CallbackData(ON_PUBLISH_STARTED);
+ callbackData.publishDiscoverySession = session;
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onSubscribeStarted(SubscribeDiscoverySession session) {
+ CallbackData callbackData = new CallbackData(ON_SUBSCRIBE_STARTED);
+ callbackData.subscribeDiscoverySession = session;
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onSessionConfigUpdated() {
+ CallbackData callbackData = new CallbackData(ON_SESSION_CONFIG_UPDATED);
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onSessionConfigFailed() {
+ CallbackData callbackData = new CallbackData(ON_SESSION_CONFIG_FAILED);
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onSessionTerminated() {
+ CallbackData callbackData = new CallbackData(ON_SESSION_TERMINATED);
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onServiceDiscovered(PeerHandle peerHandle, byte[] serviceSpecificInfo,
+ List<byte[]> matchFilter) {
+ CallbackData callbackData = new CallbackData(ON_SERVICE_DISCOVERED);
+ callbackData.peerHandle = peerHandle;
+ callbackData.serviceSpecificInfo = serviceSpecificInfo;
+ callbackData.matchFilter = matchFilter;
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onMessageSendSucceeded(int messageId) {
+ CallbackData callbackData = new CallbackData(ON_MESSAGE_SEND_SUCCEEDED);
+ callbackData.messageId = messageId;
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onMessageSendFailed(int messageId) {
+ CallbackData callbackData = new CallbackData(ON_MESSAGE_SEND_FAILED);
+ callbackData.messageId = messageId;
+ processCallback(callbackData);
+ }
+
+ @Override
+ public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
+ CallbackData callbackData = new CallbackData(ON_MESSAGE_RECEIVED);
+ callbackData.peerHandle = peerHandle;
+ callbackData.serviceSpecificInfo = message;
+ processCallback(callbackData);
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenInitiatorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenInitiatorTestActivity.java
new file mode 100644
index 0000000..107b945
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenInitiatorTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+
+import com.android.cts.verifier.wifiaware.testcase.DataPathOutOfBandTestCase;
+
+/**
+ * Test activity for data-path, open, passive subscribe
+ */
+public class DataPathOobOpenInitiatorTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathOutOfBandTestCase(context, true, false);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenResponderTestActivity.java
new file mode 100644
index 0000000..4080bd7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobOpenResponderTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.testcase.DataPathOutOfBandTestCase;
+
+/**
+ * Test activity for data-path, open, unsolicited publish
+ */
+public class DataPathOobOpenResponderTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathOutOfBandTestCase(context, true, true);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setInfoResources(R.string.aware_data_path_oob_open_responder,
+ R.string.aware_data_path_oob_open_responder_info, 0);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseInitiatorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseInitiatorTestActivity.java
new file mode 100644
index 0000000..cfdec55
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseInitiatorTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+
+import com.android.cts.verifier.wifiaware.testcase.DataPathOutOfBandTestCase;
+
+/**
+ * Test activity for data-path, open, passive subscribe
+ */
+public class DataPathOobPassphraseInitiatorTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathOutOfBandTestCase(context, false, false);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseResponderTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseResponderTestActivity.java
new file mode 100644
index 0000000..b97e74e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOobPassphraseResponderTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.testcase.DataPathOutOfBandTestCase;
+
+/**
+ * Test activity for data-path, open, unsolicited publish
+ */
+public class DataPathOobPassphraseResponderTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathOutOfBandTestCase(context, false, true);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setInfoResources(R.string.aware_data_path_oob_passphrase_responder,
+ R.string.aware_data_path_oob_passphrase_responder_info, 0);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenActiveSubscribeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenActiveSubscribeTestActivity.java
new file mode 100644
index 0000000..f6afecc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenActiveSubscribeTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, passive subscribe
+ */
+public class DataPathOpenActiveSubscribeTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, true, false, false);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenSolicitedPublishTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenSolicitedPublishTestActivity.java
new file mode 100644
index 0000000..154dcfe
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathOpenSolicitedPublishTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, unsolicited publish
+ */
+public class DataPathOpenSolicitedPublishTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, true, true, false);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setInfoResources(R.string.aware_data_path_open_solicited_publish,
+ R.string.aware_data_path_open_solicited_publish_info, 0);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseActiveSubscribeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseActiveSubscribeTestActivity.java
new file mode 100644
index 0000000..c8ef3ea
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseActiveSubscribeTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, passive subscribe
+ */
+public class DataPathPassphraseActiveSubscribeTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, false, false, false);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphrasePassiveSubscribeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphrasePassiveSubscribeTestActivity.java
new file mode 100644
index 0000000..ff40e03
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphrasePassiveSubscribeTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, passive subscribe
+ */
+public class DataPathPassphrasePassiveSubscribeTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, false, false, true);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseSolicitedPublishTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseSolicitedPublishTestActivity.java
new file mode 100644
index 0000000..dcde6ff
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseSolicitedPublishTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, unsolicited publish
+ */
+public class DataPathPassphraseSolicitedPublishTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, false, true, false);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setInfoResources(R.string.aware_data_path_passphrase_solicited_publish,
+ R.string.aware_data_path_passphrase_solicited_publish_info, 0);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseUnsolicitedPublishTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseUnsolicitedPublishTestActivity.java
new file mode 100644
index 0000000..7a25bb4
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/DataPathPassphraseUnsolicitedPublishTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.testcase.DataPathInBandTestCase;
+
+/**
+ * Test activity for data-path, open, unsolicited publish
+ */
+public class DataPathPassphraseUnsolicitedPublishTestActivity extends BaseTestActivity {
+ @Override
+ protected BaseTestCase getTestCase(Context context) {
+ return new DataPathInBandTestCase(context, false, true, true);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setInfoResources(R.string.aware_data_path_passphrase_unsolicited_publish,
+ R.string.aware_data_path_passphrase_unsolicited_publish_info, 0);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/TestListActivity.java
index f591ff4..c2c7636 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/TestListActivity.java
@@ -70,6 +70,56 @@
R.string.aware_subscribe,
DataPathOpenPassiveSubscribeTestActivity.class.getName(),
new Intent(this, DataPathOpenPassiveSubscribeTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newCategory(this,
+ R.string.aware_dp_ib_passphrase_unsolicited));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_publish,
+ DataPathPassphraseUnsolicitedPublishTestActivity.class.getName(),
+ new Intent(this, DataPathPassphraseUnsolicitedPublishTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_subscribe,
+ DataPathPassphrasePassiveSubscribeTestActivity.class.getName(),
+ new Intent(this, DataPathPassphrasePassiveSubscribeTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newCategory(this,
+ R.string.aware_dp_ib_open_solicited));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_publish,
+ DataPathOpenSolicitedPublishTestActivity.class.getName(),
+ new Intent(this, DataPathOpenSolicitedPublishTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_subscribe,
+ DataPathOpenActiveSubscribeTestActivity.class.getName(),
+ new Intent(this, DataPathOpenActiveSubscribeTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newCategory(this,
+ R.string.aware_dp_ib_passphrase_solicited));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_publish,
+ DataPathPassphraseSolicitedPublishTestActivity.class.getName(),
+ new Intent(this, DataPathPassphraseSolicitedPublishTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_subscribe,
+ DataPathPassphraseActiveSubscribeTestActivity.class.getName(),
+ new Intent(this, DataPathPassphraseActiveSubscribeTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newCategory(this,
+ R.string.aware_dp_oob_open));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_responder,
+ DataPathOobOpenResponderTestActivity.class.getName(),
+ new Intent(this, DataPathOobOpenResponderTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_initiator,
+ DataPathOobOpenInitiatorTestActivity.class.getName(),
+ new Intent(this, DataPathOobOpenInitiatorTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newCategory(this,
+ R.string.aware_dp_oob_passphrase));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_responder,
+ DataPathOobPassphraseResponderTestActivity.class.getName(),
+ new Intent(this, DataPathOobPassphraseResponderTestActivity.class), null));
+ adapter.add(TestListAdapter.TestListItem.newTest(this,
+ R.string.aware_initiator,
+ DataPathOobPassphraseInitiatorTestActivity.class.getName(),
+ new Intent(this, DataPathOobPassphraseInitiatorTestActivity.class), null));
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
index 9d58bc2..7ecdc30 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
@@ -16,18 +16,71 @@
package com.android.cts.verifier.wifiaware.testcase;
-import android.content.Context;
+import static com.android.cts.verifier.wifiaware.CallbackUtils.CALLBACK_TIMEOUT_SEC;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.aware.PeerHandle;
+import android.net.wifi.aware.PublishConfig;
+import android.net.wifi.aware.PublishDiscoverySession;
+import android.net.wifi.aware.SubscribeConfig;
+import android.net.wifi.aware.SubscribeDiscoverySession;
+import android.net.wifi.aware.WifiAwareSession;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.cts.verifier.R;
import com.android.cts.verifier.wifiaware.BaseTestCase;
+import com.android.cts.verifier.wifiaware.CallbackUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Test case for data-path, in-band test cases:
* open/passphrase * solicited/unsolicited * publish/subscribe.
+ *
+ * Subscribe test sequence:
+ * 1. Attach
+ * wait for results (session)
+ * 2. Subscribe
+ * wait for results (subscribe session)
+ * 3. Wait for discovery
+ * 4. Send message
+ * Wait for success
+ * 5. Wait for rx message
+ * 6. Request network
+ * Wait for network
+ * 7. Destroy session
+ *
+ * Publish test sequence:
+ * 1. Attach
+ * wait for results (session)
+ * 2. Publish
+ * wait for results (publish session)
+ * 3. Wait for rx message
+ * 4. Request network
+ * 5. Send message
+ * Wait for success
+ * 6. Wait for network
+ * 7. Destroy session
*/
public class DataPathInBandTestCase extends BaseTestCase {
private static final String TAG = "DataPathInBandTestCase";
private static final boolean DBG = true;
+ private static final String SERVICE_NAME = "CtsVerifierTestService";
+ private static final byte[] MATCH_FILTER_BYTES = "bytes used for matching".getBytes();
+ private static final byte[] PUB_SSI = "Extra bytes in the publisher discovery".getBytes();
+ private static final byte[] SUB_SSI = "Arbitrary bytes for the subscribe discovery".getBytes();
+ private static final byte[] MSG_SUB_TO_PUB = "Let's talk".getBytes();
+ private static final byte[] MSG_PUB_TO_SUB = "Ready".getBytes();
+ private static final String PASSPHRASE = "Some super secret password";
+ private static final int MESSAGE_ID = 1234;
+
private boolean mIsSecurityOpen;
private boolean mIsPublish;
private boolean mIsUnsolicited;
@@ -35,6 +88,7 @@
private final Object mLock = new Object();
private String mFailureReason;
+ private WifiAwareSession mWifiAwareSession;
public DataPathInBandTestCase(Context context, boolean isSecurityOpen, boolean isPublish,
boolean isUnsolicited) {
@@ -46,7 +100,42 @@
@Override
protected boolean executeTest() throws InterruptedException {
- return false;
+ if (DBG) {
+ Log.d(TAG,
+ "executeTest: mIsSecurityOpen=" + mIsSecurityOpen + ", mIsPublish=" + mIsPublish
+ + ", mIsUnsolicited=" + mIsUnsolicited);
+ }
+
+ // 1. attach
+ CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb();
+ mWifiAwareManager.attach(attachCb, mHandler);
+ Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach();
+ switch (results.first) {
+ case CallbackUtils.AttachCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_attach_timeout));
+ Log.e(TAG, "executeTest: attach TIMEOUT");
+ return false;
+ case CallbackUtils.AttachCb.ON_ATTACH_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
+ Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED");
+ return false;
+ }
+ mWifiAwareSession = results.second;
+ if (mWifiAwareSession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
+ Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached));
+ if (DBG) {
+ Log.d(TAG, "executeTest: attach succeeded");
+ }
+
+ if (mIsPublish) {
+ return executeTestPublisher();
+ } else {
+ return executeTestSubscriber();
+ }
}
private void setFailureReason(String reason) {
@@ -61,4 +150,282 @@
return mFailureReason;
}
}
-}
\ No newline at end of file
+
+ @Override
+ protected void tearDown() {
+ if (mWifiAwareSession != null) {
+ mWifiAwareSession.destroy();
+ mWifiAwareSession = null;
+ }
+ super.tearDown();
+ }
+
+ private boolean executeTestSubscriber() throws InterruptedException {
+ if (DBG) Log.d(TAG, "executeTestSubscriber");
+ CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
+
+ // 2. subscribe
+ List<byte[]> matchFilter = new ArrayList<>();
+ matchFilter.add(MATCH_FILTER_BYTES);
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
+ SERVICE_NAME).setServiceSpecificInfo(SUB_SSI).setMatchFilter(
+ matchFilter).setSubscribeType(
+ mIsUnsolicited ? SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE
+ : SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE).setMatchStyle(
+ SubscribeConfig.MATCH_STYLE_FIRST_ONLY).setTerminateNotificationEnabled(
+ true).build();
+ if (DBG) Log.d(TAG, "executeTestSubscriber: subscribeConfig=" + subscribeConfig);
+ mWifiAwareSession.subscribe(subscribeConfig, discoveryCb, mHandler);
+
+ // wait for results - subscribe session
+ CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED
+ | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout));
+ Log.e(TAG, "executeTestSubscriber: subscribe TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed));
+ Log.e(TAG, "executeTestSubscriber: subscribe ON_SESSION_CONFIG_FAILED");
+ return false;
+ }
+ SubscribeDiscoverySession discoverySession = callbackData.subscribeDiscoverySession;
+ if (discoverySession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session));
+ Log.e(TAG, "executeTestSubscriber: subscribe succeeded but null session returned");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: subscribe succeeded");
+
+ // 3. wait for discovery
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout));
+ Log.e(TAG, "executeTestSubscriber: waiting for discovery TIMEOUT");
+ return false;
+ }
+ PeerHandle peerHandle = callbackData.peerHandle;
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: discovery");
+
+ // validate discovery parameters match
+ if (!Arrays.equals(PUB_SSI, callbackData.serviceSpecificInfo)) {
+ setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
+ Log.e(TAG, "executeTestSubscriber: discovery but SSI mismatch: rx='" + new String(
+ callbackData.serviceSpecificInfo) + "'");
+ return false;
+ }
+ if (callbackData.matchFilter.size() != 1 || !Arrays.equals(MATCH_FILTER_BYTES,
+ callbackData.matchFilter.get(0))) {
+ setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
+ StringBuffer sb = new StringBuffer();
+ sb.append("size=").append(callbackData.matchFilter.size());
+ for (byte[] mf: callbackData.matchFilter) {
+ sb.append(", e='").append(new String(mf)).append("'");
+ }
+ Log.e(TAG, "executeTestSubscriber: discovery but matchFilter mismatch: "
+ + sb.toString());
+ return false;
+ }
+ if (peerHandle == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_discovery_fail));
+ Log.e(TAG, "executeTestSubscriber: discovery but null peerHandle");
+ return false;
+ }
+
+ // 4. send message & wait for send status
+ discoverySession.sendMessage(peerHandle, MESSAGE_ID, MSG_SUB_TO_PUB);
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
+ | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
+ Log.e(TAG, "executeTestSubscriber: send message TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_send_failed));
+ Log.e(TAG, "executeTestSubscriber: send message ON_MESSAGE_SEND_FAILED");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: send message succeeded");
+
+ if (callbackData.messageId != MESSAGE_ID) {
+ setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
+ Log.e(TAG, "executeTestSubscriber: send message message ID mismatch: "
+ + callbackData.messageId);
+ return false;
+ }
+
+ // 5. wait to receive message
+ callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
+ Log.e(TAG, "executeTestSubscriber: receive message TIMEOUT");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_received));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: received message");
+
+ // validate that received the expected message
+ if (!Arrays.equals(MSG_PUB_TO_SUB, callbackData.serviceSpecificInfo)) {
+ setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
+ Log.e(TAG, "executeTestSubscriber: receive message message content mismatch: rx='"
+ + new String(callbackData.serviceSpecificInfo) + "'");
+ return false;
+ }
+
+ // 6. request network
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ String networkSpecifier = mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(
+ peerHandle) : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
+ PASSPHRASE);
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
+ networkSpecifier).build();
+ CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
+ cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: requested network");
+ boolean networkAvailable = networkCb.waitForNetwork();
+ cm.unregisterNetworkCallback(networkCb);
+ if (!networkAvailable) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestSubscriber: network request rejected - ON_UNAVAILABLE");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
+ if (DBG) Log.d(TAG, "executeTestSubscriber: network request granted - AVAILABLE");
+
+ // 7. destroy session
+ discoverySession.destroy();
+
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
+ return true;
+ }
+
+ private boolean executeTestPublisher() throws InterruptedException {
+ if (DBG) Log.d(TAG, "executeTestPublisher");
+ CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
+
+ // 2. publish
+ List<byte[]> matchFilter = new ArrayList<>();
+ matchFilter.add(MATCH_FILTER_BYTES);
+ PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
+ SERVICE_NAME).setServiceSpecificInfo(PUB_SSI).setMatchFilter(
+ matchFilter).setPublishType(mIsUnsolicited ? PublishConfig.PUBLISH_TYPE_UNSOLICITED
+ : PublishConfig.PUBLISH_TYPE_SOLICITED).setTerminateNotificationEnabled(
+ true).build();
+ if (DBG) Log.d(TAG, "executeTestPublisher: publishConfig=" + publishConfig);
+ mWifiAwareSession.publish(publishConfig, discoveryCb, mHandler);
+
+ // wait for results - publish session
+ CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED
+ | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_publish_timeout));
+ Log.e(TAG, "executeTestPublisher: publish TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_publish_failed));
+ Log.e(TAG, "executeTestPublisher: publish ON_SESSION_CONFIG_FAILED");
+ return false;
+ }
+ PublishDiscoverySession discoverySession = callbackData.publishDiscoverySession;
+ if (discoverySession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_publish_null_session));
+ Log.e(TAG, "executeTestPublisher: publish succeeded but null session returned");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started));
+ if (DBG) Log.d(TAG, "executeTestPublisher: publish succeeded");
+
+ // 3. wait to receive message: no timeout since this depends on (human) operator starting
+ // the test on the subscriber device.
+ callbackData = discoveryCb.waitForCallbacksNoTimeout(
+ CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
+ PeerHandle peerHandle = callbackData.peerHandle;
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_received));
+ if (DBG) Log.d(TAG, "executeTestPublisher: received message");
+
+ // validate that received the expected message
+ if (!Arrays.equals(MSG_SUB_TO_PUB, callbackData.serviceSpecificInfo)) {
+ setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
+ Log.e(TAG, "executeTestPublisher: receive message message content mismatch: rx='"
+ + new String(callbackData.serviceSpecificInfo) + "'");
+ return false;
+ }
+ if (peerHandle == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
+ Log.e(TAG, "executeTestPublisher: received message but peerHandle is null!?");
+ return false;
+ }
+
+ // 4. Request network
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ String networkSpecifier = mIsSecurityOpen ? discoverySession.createNetworkSpecifierOpen(
+ peerHandle) : discoverySession.createNetworkSpecifierPassphrase(peerHandle,
+ PASSPHRASE);
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
+ networkSpecifier).build();
+ CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
+ cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
+ if (DBG) Log.d(TAG, "executeTestPublisher: requested network");
+
+ // 5. send message & wait for send status
+ discoverySession.sendMessage(peerHandle, MESSAGE_ID, MSG_PUB_TO_SUB);
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
+ | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
+ Log.e(TAG, "executeTestPublisher: send message TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_send_failed));
+ Log.e(TAG, "executeTestPublisher: send message ON_MESSAGE_SEND_FAILED");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
+ if (DBG) Log.d(TAG, "executeTestPublisher: send message succeeded");
+
+ if (callbackData.messageId != MESSAGE_ID) {
+ setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
+ Log.e(TAG, "executeTestPublisher: send message succeeded but message ID mismatch : "
+ + callbackData.messageId);
+ return false;
+ }
+
+ // 6. wait for network
+ boolean networkAvailable = networkCb.waitForNetwork();
+ cm.unregisterNetworkCallback(networkCb);
+ if (!networkAvailable) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestPublisher: request network rejected - ON_UNAVAILABLE");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
+ if (DBG) Log.d(TAG, "executeTestPublisher: network request granted - AVAILABLE");
+
+ // 7. destroy session
+ discoverySession.destroy();
+
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
+ return true;
+
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
new file mode 100644
index 0000000..a2e0de5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.wifiaware.testcase;
+
+import static com.android.cts.verifier.wifiaware.CallbackUtils.CALLBACK_TIMEOUT_SEC;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.aware.PeerHandle;
+import android.net.wifi.aware.PublishConfig;
+import android.net.wifi.aware.PublishDiscoverySession;
+import android.net.wifi.aware.SubscribeConfig;
+import android.net.wifi.aware.SubscribeDiscoverySession;
+import android.net.wifi.aware.WifiAwareManager;
+import android.net.wifi.aware.WifiAwareSession;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.wifiaware.BaseTestCase;
+import com.android.cts.verifier.wifiaware.CallbackUtils;
+
+/**
+ *Test case for data-path, out-of-band (OOB) test cases:
+ * open/passphrase * responder/initiator.
+ *
+ * OOB assumes that there's an alternative channel over which to communicate the discovery MAC
+ * address of the Aware interface. That channel (e.g. bluetooth or a host test device) is not
+ * readily available (don't want to have Aware tests dependent on BLE). Instead will fake the OOB
+ * channel using Aware itself: will do normal discovery during which the devices will exchange their
+ * MAC addresses, then destroy the discovery sessions and use the MAC addresses to perform OOB data-
+ * path requests.
+ *
+ * Responder test sequence:
+ * 1. Attach (with identity listener)
+ * wait for results (session)
+ * wait for identity
+ * 2. Publish
+ * wait for results (publish session)
+ * 3. Wait for rx message (with MAC)
+ * 4. Send message with MAC
+ * wait for success
+ * 5. Destroy discovery session
+ * 6. Request network (as Responder)
+ * wait for network
+ *
+ * Initiator test sequence:
+ * 1. Attach (with identity listener)
+ * wait for results (session)
+ * wait for identity
+ * 2. Subscribe
+ * wait for results (subscribe session)
+ * 3. Wait for discovery
+ * 4. Send message with MAC
+ * wait for success
+ * 5. Wait for rx message (with MAC)
+ * 6. Destroy discovery session
+ * 7. Sleep for 5 seconds to let Responder time to set up
+ * 8. Request network (as Initiator)
+ * wait for network
+ */
+public class DataPathOutOfBandTestCase extends BaseTestCase {
+ private static final String TAG = "DataPathOutOfBandTestCase";
+ private static final boolean DBG = true;
+
+ private static final int MAC_BYTES_LEN = 6;
+
+ private static final String SERVICE_NAME = "CtsVerifierTestService";
+ private static final String PASSPHRASE = "Some super secret password";
+ private static final int MESSAGE_ID = 1234;
+
+ private boolean mIsSecurityOpen;
+ private boolean mIsResponder;
+
+ private final Object mLock = new Object();
+
+ private String mFailureReason;
+ private WifiAwareSession mWifiAwareSession;
+ private byte[] mDiscoveryMac;
+
+ public DataPathOutOfBandTestCase(Context context, boolean isSecurityOpen,
+ boolean isResponder) {
+ super(context);
+ mIsSecurityOpen = isSecurityOpen;
+ mIsResponder = isResponder;
+ }
+
+ @Override
+ protected boolean executeTest() throws InterruptedException {
+ if (DBG) {
+ Log.d(TAG, "executeTest: mIsSecurityOpen=" + mIsSecurityOpen + ", mIsResponder="
+ + mIsResponder);
+ }
+
+ // 1. attach (with identity listener)
+ CallbackUtils.AttachCb attachCb = new CallbackUtils.AttachCb();
+ CallbackUtils.IdentityListenerSingleShot identityL = new CallbackUtils
+ .IdentityListenerSingleShot();
+ mWifiAwareManager.attach(attachCb, identityL, mHandler);
+ Pair<Integer, WifiAwareSession> results = attachCb.waitForAttach();
+ switch (results.first) {
+ case CallbackUtils.AttachCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_attach_timeout));
+ Log.e(TAG, "executeTest: attach TIMEOUT");
+ return false;
+ case CallbackUtils.AttachCb.ON_ATTACH_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
+ Log.e(TAG, "executeTest: attach ON_ATTACH_FAILED");
+ return false;
+ }
+ mWifiAwareSession = results.second;
+ if (mWifiAwareSession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_attach_fail));
+ Log.e(TAG, "executeTest: attach callback succeeded but null session returned!?");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_attached));
+ if (DBG) {
+ Log.d(TAG, "executeTest: attach succeeded");
+ }
+ mDiscoveryMac = identityL.waitForMac();
+ if (mDiscoveryMac == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_identity_fail));
+ Log.e(TAG, "executeTest: identity callback not triggered");
+ return false;
+ }
+ mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_identity,
+ bytesToHex(mDiscoveryMac, ':')));
+ if (DBG) {
+ Log.d(TAG, "executeTest: identity received: " + bytesToHex(mDiscoveryMac, ':'));
+ }
+
+ if (mIsResponder) {
+ return executeTestResponder();
+ } else {
+ return executeTestInitiator();
+ }
+ }
+
+ private void setFailureReason(String reason) {
+ synchronized (mLock) {
+ mFailureReason = reason;
+ }
+ }
+
+ @Override
+ protected String getFailureReason() {
+ synchronized (mLock) {
+ return mFailureReason;
+ }
+ }
+
+ @Override
+ protected void tearDown() {
+ if (mWifiAwareSession != null) {
+ mWifiAwareSession.destroy();
+ mWifiAwareSession = null;
+ }
+ super.tearDown();
+ }
+
+ private boolean executeTestResponder() throws InterruptedException {
+ if (DBG) Log.d(TAG, "executeTestResponder");
+ CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
+
+ // 2. publish
+ PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
+ SERVICE_NAME).build();
+ if (DBG) Log.d(TAG, "executeTestResponder: publishConfig=" + publishConfig);
+ mWifiAwareSession.publish(publishConfig, discoveryCb, mHandler);
+
+ // wait for results - publish session
+ CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_PUBLISH_STARTED
+ | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_publish_timeout));
+ Log.e(TAG, "executeTestResponder: publish TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_publish_failed));
+ Log.e(TAG, "executeTestResponder: publish ON_SESSION_CONFIG_FAILED");
+ return false;
+ }
+ PublishDiscoverySession discoverySession = callbackData.publishDiscoverySession;
+ if (discoverySession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_publish_null_session));
+ Log.e(TAG, "executeTestResponder: publish succeeded but null session returned");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_publish_started));
+ if (DBG) Log.d(TAG, "executeTestResponder: publish succeeded");
+
+ // 3. Wait for rx message (with MAC)
+ callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
+ Log.e(TAG, "executeTestResponder: receive message TIMEOUT");
+ return false;
+ }
+
+ if (callbackData.serviceSpecificInfo == null
+ || callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
+ setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
+ Log.e(TAG, "executeTestResponder: receive message message content mismatch: "
+ + bytesToHex(callbackData.serviceSpecificInfo, ':'));
+ return false;
+ }
+
+ PeerHandle peerHandle = callbackData.peerHandle;
+ byte[] peerMac = callbackData.serviceSpecificInfo;
+
+ mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
+ bytesToHex(peerMac, ':')));
+ if (DBG) {
+ Log.d(TAG, "executeTestResponder: received MAC address: " + bytesToHex(peerMac, ':'));
+ }
+
+ // 4. Send message with MAC and wait for success
+ discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
+ | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
+ Log.e(TAG, "executeTestResponder: send message TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_send_failed));
+ Log.e(TAG, "executeTestResponder: send message ON_MESSAGE_SEND_FAILED");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
+ if (DBG) Log.d(TAG, "executeTestResponder: send message succeeded");
+
+ if (callbackData.messageId != MESSAGE_ID) {
+ setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
+ Log.e(TAG, "executeTestResponder: send message message ID mismatch: "
+ + callbackData.messageId);
+ return false;
+ }
+
+ // 5. Destroy discovery session
+ discoverySession.destroy();
+
+ // 6. Request network (as Responder) and wait for network
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ String networkSpecifier = mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac)
+ : mWifiAwareSession.createNetworkSpecifierPassphrase(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, peerMac, PASSPHRASE);
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
+ networkSpecifier).build();
+ CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
+ cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
+ if (DBG) Log.d(TAG, "executeTestResponder: requested network");
+ boolean networkAvailable = networkCb.waitForNetwork();
+ cm.unregisterNetworkCallback(networkCb);
+ if (!networkAvailable) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
+ if (DBG) Log.d(TAG, "executeTestResponder: network request granted - AVAILABLE");
+
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
+ return true;
+ }
+
+ private boolean executeTestInitiator() throws InterruptedException {
+ if (DBG) Log.d(TAG, "executeTestInitiator");
+ CallbackUtils.DiscoveryCb discoveryCb = new CallbackUtils.DiscoveryCb();
+
+ // 2. Subscribe
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
+ SERVICE_NAME).build();
+ if (DBG) Log.d(TAG, "executeTestInitiator: subscribeConfig=" + subscribeConfig);
+ mWifiAwareSession.subscribe(subscribeConfig, discoveryCb, mHandler);
+
+ // wait for results - subscribe session
+ CallbackUtils.DiscoveryCb.CallbackData callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_SUBSCRIBE_STARTED
+ | CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_timeout));
+ Log.e(TAG, "executeTestInitiator: subscribe TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_SESSION_CONFIG_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_failed));
+ Log.e(TAG, "executeTestInitiator: subscribe ON_SESSION_CONFIG_FAILED");
+ return false;
+ }
+ SubscribeDiscoverySession discoverySession = callbackData.subscribeDiscoverySession;
+ if (discoverySession == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_subscribe_null_session));
+ Log.e(TAG, "executeTestInitiator: subscribe succeeded but null session returned");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_subscribe_started));
+ if (DBG) Log.d(TAG, "executeTestInitiator: subscribe succeeded");
+
+ // 3. Wait for discovery
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_SERVICE_DISCOVERED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_discovery_timeout));
+ Log.e(TAG, "executeTestInitiator: waiting for discovery TIMEOUT");
+ return false;
+ }
+ PeerHandle peerHandle = callbackData.peerHandle;
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_discovery));
+ if (DBG) Log.d(TAG, "executeTestInitiator: discovery");
+
+ // 4. Send message with MAC and wait for success
+ discoverySession.sendMessage(peerHandle, MESSAGE_ID, mDiscoveryMac);
+ callbackData = discoveryCb.waitForCallbacks(
+ CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
+ | CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_send_timeout));
+ Log.e(TAG, "executeTestInitiator: send message TIMEOUT");
+ return false;
+ case CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_FAILED:
+ setFailureReason(mContext.getString(R.string.aware_status_send_failed));
+ Log.e(TAG, "executeTestInitiator: send message ON_MESSAGE_SEND_FAILED");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_send_success));
+ if (DBG) Log.d(TAG, "executeTestInitiator: send message succeeded");
+
+ if (callbackData.messageId != MESSAGE_ID) {
+ setFailureReason(mContext.getString(R.string.aware_status_send_fail_parameter));
+ Log.e(TAG, "executeTestInitiator: send message message ID mismatch: "
+ + callbackData.messageId);
+ return false;
+ }
+
+ // 5. Wait for rx message (with MAC)
+ callbackData = discoveryCb.waitForCallbacks(CallbackUtils.DiscoveryCb.ON_MESSAGE_RECEIVED);
+ switch (callbackData.callback) {
+ case CallbackUtils.DiscoveryCb.TIMEOUT:
+ setFailureReason(mContext.getString(R.string.aware_status_receive_timeout));
+ Log.e(TAG, "executeTestInitiator: receive message TIMEOUT");
+ return false;
+ }
+
+ if (callbackData.serviceSpecificInfo == null
+ || callbackData.serviceSpecificInfo.length != MAC_BYTES_LEN) {
+ setFailureReason(mContext.getString(R.string.aware_status_receive_failure));
+ Log.e(TAG, "executeTestInitiator: receive message message content mismatch: "
+ + bytesToHex(callbackData.serviceSpecificInfo, ':'));
+ return false;
+ }
+
+ byte[] peerMac = callbackData.serviceSpecificInfo;
+
+ mListener.onTestMsgReceived(mResources.getString(R.string.aware_status_received_mac,
+ bytesToHex(peerMac, ':')));
+ if (DBG) {
+ Log.d(TAG, "executeTestInitiator: received MAC address: " + bytesToHex(peerMac, ':'));
+ }
+
+ // 6. Destroy discovery session
+ discoverySession.destroy();
+
+ // 7. Sleep for 5 seconds to let Responder time to set up
+ mListener.onTestMsgReceived(
+ mContext.getString(R.string.aware_status_sleeping_wait_for_responder));
+ Thread.sleep(5000);
+
+ // 8. Request network (as Initiator) and wait for network
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ String networkSpecifier = mIsSecurityOpen ? mWifiAwareSession.createNetworkSpecifierOpen(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac)
+ : mWifiAwareSession.createNetworkSpecifierPassphrase(
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, peerMac, PASSPHRASE);
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
+ networkSpecifier).build();
+ CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
+ cm.requestNetwork(nr, CALLBACK_TIMEOUT_SEC * 1000, networkCb);
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
+ if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
+ boolean networkAvailable = networkCb.waitForNetwork();
+ cm.unregisterNetworkCallback(networkCb);
+ if (!networkAvailable) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
+ return false;
+ }
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
+ if (DBG) Log.d(TAG, "executeTestInitiator: network request granted - AVAILABLE");
+
+ mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_lifecycle_ok));
+ return true;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index a2dad7e..30d5f95 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -366,6 +366,8 @@
// Get the tests to run in this shard
modules = mModuleRepo.getModules(getDevice().getSerialNumber(), mShardIndex);
}
+ mExcludeFilters.clear();
+ mIncludeFilters.clear();
// Update BuildInfo in each shard to store the original command-line arguments from
// the session to be retried. These arguments will be serialized in the report later.
if (mRetrySessionId != null) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index ad12490..794e45e 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -286,6 +286,7 @@
configFile.getName()), e);
}
}
+ mExcludeFilters.clear();
TestRunHandler.setTestRuns(new CompatibilityBuildHelper(buildInfo), shardedTestCounts);
}
diff --git a/hostsidetests/incident/apps/errorsapp/src/com/android/server/cts/errors/ErrorsTests.java b/hostsidetests/incident/apps/errorsapp/src/com/android/server/cts/errors/ErrorsTests.java
index 9243dcc..630df5c 100644
--- a/hostsidetests/incident/apps/errorsapp/src/com/android/server/cts/errors/ErrorsTests.java
+++ b/hostsidetests/incident/apps/errorsapp/src/com/android/server/cts/errors/ErrorsTests.java
@@ -15,7 +15,6 @@
*/
package com.android.server.cts.errors;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.BroadcastReceiver;
@@ -41,6 +40,12 @@
public class ErrorsTests {
private static final String TAG = "ErrorsTests";
+ private static final String CRASH_TAG = "data_app_crash";
+ private static final String ANR_TAG = "data_app_anr";
+ private static final String NATIVE_CRASH_TAG = "SYSTEM_TOMBSTONE";
+
+ private static final int TIMEOUT_SECS = 60 * 3;
+
private CountDownLatch mResultsReceivedSignal;
private DropBoxManager mDropbox;
private long mStartMs;
@@ -51,7 +56,6 @@
mContext = InstrumentationRegistry.getTargetContext();
mDropbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
mResultsReceivedSignal = new CountDownLatch(1);
- registerReceiver(mContext, mResultsReceivedSignal);
mStartMs = System.currentTimeMillis();
}
@@ -59,60 +63,63 @@
public void testException() throws Exception {
Log.i(TAG, "testException");
+ registerReceiver(mContext, mResultsReceivedSignal, CRASH_TAG,
+ mContext.getPackageName() + ":TestProcess",
+ "java.lang.RuntimeException: This is a test exception");
Intent intent = new Intent();
intent.setClass(mContext, ExceptionActivity.class);
mContext.startActivity(intent);
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- assertDropboxContains("data_app_crash", mContext.getPackageName() + ":TestProcess",
- "java.lang.RuntimeException: This is a test exception");
+ assertTrue(mResultsReceivedSignal.await(TIMEOUT_SECS, TimeUnit.SECONDS));
}
@Test
public void testANR() throws Exception {
Log.i(TAG, "testANR");
+ registerReceiver(mContext, mResultsReceivedSignal, ANR_TAG,
+ mContext.getPackageName() + ":TestProcess",
+ "Subject: Broadcast of Intent { act=android.intent.action.SCREEN_ON");
Intent intent = new Intent();
intent.setClass(mContext, ANRActivity.class);
mContext.startActivity(intent);
- mResultsReceivedSignal.await(60, TimeUnit.SECONDS);
- assertDropboxContains("data_app_anr", mContext.getPackageName() + ":TestProcess",
- "Subject: Broadcast of Intent { act=android.intent.action.SCREEN_ON");
+ assertTrue(mResultsReceivedSignal.await(TIMEOUT_SECS, TimeUnit.SECONDS));
}
@Test
public void testNativeCrash() throws Exception {
Log.i(TAG, "testNativeCrash");
+ registerReceiver(mContext, mResultsReceivedSignal, NATIVE_CRASH_TAG,
+ mContext.getPackageName() + ":TestProcess", "backtrace:");
Intent intent = new Intent();
intent.setClass(mContext, NativeActivity.class);
mContext.startActivity(intent);
- mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
- assertDropboxContains("SYSTEM_TOMBSTONE", mContext.getPackageName() + ":TestProcess",
- "backtrace:");
+ assertTrue(mResultsReceivedSignal.await(TIMEOUT_SECS, TimeUnit.SECONDS));
}
- static void registerReceiver(Context ctx, CountDownLatch onReceiveLatch) {
+ void registerReceiver(Context ctx, CountDownLatch onReceiveLatch, String wantTag,
+ String... wantInStackTrace) {
ctx.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- onReceiveLatch.countDown();
+ // DropBox might receive other entries while we're waiting for the error
+ // entry, so we need to check the tag and stack trace before continuing.
+ DropBoxManager.Entry entry = mDropbox.getNextEntry(wantTag, mStartMs);
+ if (entry != null) {
+ String stackTrace = entry.getText(10000); // Only need to check a few lines.
+ boolean allMatches = true;
+ for (String line : wantInStackTrace) {
+ allMatches &= stackTrace.contains(line);
+ }
+ entry.close();
+ if (allMatches) {
+ onReceiveLatch.countDown();
+ }
+ }
}
}, new IntentFilter(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED));
}
-
- private void assertDropboxContains(String tag, String... wantInStackTrace) throws Exception {
- DropBoxManager.Entry entry = mDropbox.getNextEntry(tag, mStartMs);
- assertTrue("No entry found with tag: " + tag, entry != null);
-
- assertEquals("Tag", tag, entry.getTag());
-
- String stackTrace = entry.getText(10000); // Only need to check a few lines.
- for (String line : wantInStackTrace) {
- assertTrue(tag + ": Stack trace did not contain: " + line, stackTrace.contains(line));
- }
- entry.close();
- }
}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
index 8cb377d..46c9b03 100755
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/AndroidManifest.xml
@@ -22,7 +22,7 @@
<activity android:name=".DialogTestActivity"
android:exported="true"
/>
- <activity android:name=".MovingPopupTestActivity"
+ <activity android:name=".MovingChildTestActivity"
android:exported="true"
/>
</application>
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingPopupTestActivity.java b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingChildTestActivity.java
similarity index 67%
rename from hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingPopupTestActivity.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingChildTestActivity.java
index 91b9788..de6f597 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingPopupTestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/frametestapp/src/android/server/frametestapp/MovingChildTestActivity.java
@@ -18,23 +18,23 @@
import android.app.Activity;
import android.content.Intent;
+import android.content.Context;
import android.os.Bundle;
import android.view.WindowManager;
import android.view.Window;
import android.view.Gravity;
import android.view.View;
import android.widget.Space;
-import android.widget.PopupWindow;
import android.widget.Button;
import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
import android.widget.FrameLayout;
-// This activity will parent a Popup to the main window, and then move
-// the main window around. We can use this to verify the Popup
+// This activity will parent a Child to the main window, and then move
+// the main window around. We can use this to verify the Child
// is properly updated.
-public class MovingPopupTestActivity extends Activity {
+public class MovingChildTestActivity extends Activity {
Space mView;
- PopupWindow mPopupWindow;
int mX = 0;
int mY = 0;
@@ -43,6 +43,7 @@
public void run() {
final Window w = getWindow();
final WindowManager.LayoutParams attribs = w.getAttributes();
+ attribs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
attribs.x = mX % 1000;
attribs.y = mY % 1000;
w.setAttributes(attribs);
@@ -52,16 +53,19 @@
}
};
- final Runnable makePopup = new Runnable() {
+ final Runnable makeChild = new Runnable() {
@Override
public void run() {
- Button b = new Button(MovingPopupTestActivity.this);
+ Button b = new Button(MovingChildTestActivity.this);
+ WindowManager.LayoutParams p = new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
+ p.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ p.x = 0;
+ p.y = 0;
+ p.token = mView.getWindowToken();
+ p.setTitle("ChildWindow");
- mPopupWindow = new PopupWindow(MovingPopupTestActivity.this);
- mPopupWindow.setContentView(b);
- mPopupWindow.setWidth(50);
- mPopupWindow.setHeight(50);
- mPopupWindow.showAtLocation(mView, 0, 0, 0);
+ ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).addView(b, p);
mView.postDelayed(moveWindow, 50);
}
@@ -76,6 +80,6 @@
mView = new Space(this);
setContentView(mView, p);
- mView.post(makePopup);
+ mView.post(makeChild);
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/PopupMovementTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/ChildMovementTests.java
similarity index 89%
rename from hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/PopupMovementTests.java
rename to hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/ChildMovementTests.java
index 6c7cad0..218fcfe 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/PopupMovementTests.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/ChildMovementTests.java
@@ -32,17 +32,17 @@
import android.server.cts.ActivityManagerTestBase;
import android.server.cts.WindowManagerState.WindowState;
-public class PopupMovementTests extends ParentChildTestBase {
+public class ChildMovementTests extends ParentChildTestBase {
private List<WindowState> mWindowList = new ArrayList();
@Override
String intentKey() {
- return "android.server.FrameTestApp.PopupTestCase";
+ return "android.server.FrameTestApp.ChildTestCase";
}
@Override
String activityName() {
- return "MovingPopupTestActivity";
+ return "MovingChildTestActivity";
}
WindowState getSingleWindow(String fullWindowName) {
@@ -66,7 +66,7 @@
}
void doSingleTest(ParentChildTest t) throws Exception {
- String popupName = "PopupWindow";
+ String popupName = "ChildWindow";
final String[] waitForVisible = new String[] { popupName };
mAmWmState.setUseActivityNamesForWindowNames(false);
@@ -85,7 +85,7 @@
SurfaceTraceReceiver.SurfaceObserver observer = new SurfaceTraceReceiver.SurfaceObserver() {
int transactionCount = 0;
- boolean sawPopupMove = false;
+ boolean sawChildMove = false;
boolean sawMainMove = false;
int timesSeen = 0;
@@ -93,7 +93,7 @@
public void openTransaction() {
transactionCount++;
if (transactionCount == 1) {
- sawPopupMove = false;
+ sawChildMove = false;
sawMainMove = false;
}
}
@@ -105,7 +105,7 @@
return;
}
synchronized (monitor) {
- if (sawPopupMove ^ sawMainMove ) {
+ if (sawChildMove ^ sawMainMove ) {
monitor.notifyAll();
return;
}
@@ -119,7 +119,7 @@
@Override
public void setPosition(String windowName, float x, float y) {
if (windowName.equals(popupName)) {
- sawPopupMove = true;
+ sawChildMove = true;
timesSeen++;
} else if (windowName.equals(mainName)) {
sawMainMove = true;
@@ -128,10 +128,10 @@
};
/**
- * Here we test that a Popup moves in the same transaction
- * as its parent. We launch an activity with a Popup which will
+ * Here we test that a Child moves in the same transaction
+ * as its parent. We launch an activity with a Child which will
* move around its own main window. Then we listen to WindowManager transactions.
- * Since the Popup is static within the window, if we ever see one of
+ * Since the Child is static within the window, if we ever see one of
* them move xor the other one we have a problem!
*/
public void testSurfaceMovesWithParent() throws Exception {
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
index 56b1b40..6fb5fbd 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/DialogFrameTests.java
@@ -135,7 +135,9 @@
// With FLAG_LAYOUT_NO_LIMITS we should get the size we request, even if its much
// larger than the screen.
public void testOversizedDimensionsNoLimits() throws Exception {
- doParentChildTest("OversizedDimensionsNoLimits",
+ // TODO(b/36890978): We only run this in fullscreen because of the
+ // unclear status of NO_LIMITS for non-child surfaces in MW modes
+ doFullscreenTest("OversizedDimensionsNoLimits",
(WindowState parent, WindowState dialog) -> {
Rectangle contentFrame = parent.getContentFrame();
Rectangle expectedFrame = new Rectangle(contentFrame.x, contentFrame.y,
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
index 8291633..b67fc28 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityVolumeTest.java
@@ -14,6 +14,7 @@
package android.accessibilityservice.cts;
import android.app.Instrumentation;
+import android.content.pm.PackageManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.media.AudioManager;
@@ -31,16 +32,25 @@
public class AccessibilityVolumeTest {
Instrumentation mInstrumentation;
AudioManager mAudioManager;
+ // If a platform collects all volumes into one, these tests aren't relevant
+ boolean mSingleVolume;
@Before
public void setUp() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mAudioManager =
(AudioManager) mInstrumentation.getContext().getSystemService(AUDIO_SERVICE);
+ // TVs have a single volume
+ PackageManager pm = mInstrumentation.getContext().getPackageManager();
+ mSingleVolume = (pm != null) && (pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION));
}
@Test
public void testChangeAccessibilityVolume_outsideValidAccessibilityService_shouldFail() {
+ if (mSingleVolume) {
+ return;
+ }
int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
mAudioManager.setStreamVolume(AudioManager.STREAM_ACCESSIBILITY, otherVolume, 0);
@@ -50,6 +60,9 @@
@Test
public void testChangeAccessibilityVolume_inAccessibilityService_shouldWork() {
+ if (mSingleVolume) {
+ return;
+ }
int startingVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ACCESSIBILITY);
int otherVolume = (startingVolume == 0) ? 1 : startingVolume - 1;
InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index ca10e56..c7f6c20 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -48,6 +48,7 @@
private static final NotificationChannel CHANNEL = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_HIGH);
private static final String SHORTCUT_ID = "shortcutId";
+ private static final String SETTING_TEXT = "work chats";
@Override
protected void setUp() throws Exception {
@@ -91,6 +92,7 @@
.setBadgeIconType(Notification.BADGE_ICON_SMALL)
.setShortcutId(SHORTCUT_ID)
.setTimeout(TIMEOUT)
+ .setSettingsText(SETTING_TEXT)
.build();
mNotification.icon = 0;
mNotification.number = 1;
@@ -145,6 +147,7 @@
assertEquals(mNotification.getBadgeIconType(), result.getBadgeIconType());
assertEquals(mNotification.getTimeout(), result.getTimeout());
assertEquals(mNotification.getChannel(), result.getChannel());
+ assertEquals(mNotification.getSettingsText(), result.getSettingsText());
mNotification.contentIntent = null;
parcel = Parcel.obtain();
@@ -203,6 +206,7 @@
.setBadgeIconType(Notification.BADGE_ICON_SMALL)
.setShortcutId(SHORTCUT_ID)
.setTimeout(TIMEOUT)
+ .setSettingsText(SETTING_TEXT)
.build();
assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT));
assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE));
@@ -212,6 +216,7 @@
assertEquals(Notification.BADGE_ICON_SMALL, mNotification.getBadgeIconType());
assertEquals(SHORTCUT_ID, mNotification.getShortcutId());
assertEquals(TIMEOUT, mNotification.getTimeout());
+ assertEquals(SETTING_TEXT, mNotification.getSettingsText());
}
public void testActionBuilder() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
index f925a7b..6df6f10 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
@@ -70,11 +70,11 @@
mClearButton.setOnClickListener((v) -> resetFields());
}
- private void save() {
+ void save() {
getSystemService(AutofillManager.class).commit();
}
- private void resetFields() {
+ void resetFields() {
for (int i = 0; i < N_ROWS; i++) {
for (int j = 0; j < N_COLS; j++) {
mCells[i][j].setText("");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index 39e4741..c78a6e1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -158,7 +158,6 @@
this.callback = callback;
this.flags = flags;
}
-
}
/**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 2d5a33c..f6ddb13 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -61,6 +61,9 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.uiautomator.UiObject2;
import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
import android.view.autofill.AutofillManager;
import org.junit.After;
@@ -90,11 +93,8 @@
*/
public class LoginActivityTest extends AutoFillServiceTestCase {
- // TODO(b/33197203 , b/36855717): remove when bug 36855717 is fixed
- private static final boolean BUG_36855717_FIXED = false;
-
// TODO(b/33197203 , b/35707731): remove when fixed
- private static final boolean SUPPORTS_PARTIOTINED_AUTH = false;
+ private static final boolean SUPPORTS_PARTITIONED_AUTH = false;
@Rule
public final ActivityTestRule<LoginActivity> mActivityRule =
@@ -174,6 +174,25 @@
}
@Test
+ public void testAutoFillWhenViewHasChildAccessibilityNodes() throws Exception {
+ mActivity.onUsername((v) -> v.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
+ return new AccessibilityNodeProvider() {
+ @Override
+ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
+ final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ info.addChild(v, virtualViewId);
+ return info;
+ }
+ };
+ }
+ }));
+
+ testAutoFillOneDataset();
+ }
+
+ @Test
public void testAutoFillOneDatasetAndMoveFocusAround() throws Exception {
// Set service.
enableService();
@@ -975,13 +994,9 @@
sUiBot.assertNotShownByText("Tap to auth response");
// ...and select it this time
- if (BUG_36855717_FIXED) {
- callback.assertUiShownEvent(username);
- }
+ callback.assertUiShownEvent(username);
sUiBot.selectDataset("Dataset");
- if (BUG_36855717_FIXED) {
- callback.assertUiHiddenEvent(username);
- }
+ callback.assertUiHiddenEvent(username);
sUiBot.assertNoDatasets();
sUiBot.assertNotShownByText("Tap to auth response");
@@ -1036,7 +1051,7 @@
callback.assertUiShownEvent(username);
sUiBot.assertShownByText("Tap to auth response");
- if (SUPPORTS_PARTIOTINED_AUTH) {
+ if (SUPPORTS_PARTITIONED_AUTH) {
// Make sure UI is not show on 2nd field
final View password = mActivity.getPassword();
mActivity.onPassword(View::requestFocus);
@@ -1065,13 +1080,9 @@
callback.assertUiHiddenEvent(username);
sUiBot.assertNotShownByText("Tap to auth response");
- if (BUG_36855717_FIXED) {
- callback.assertUiShownEvent(username);
- }
+ callback.assertUiShownEvent(username);
sUiBot.selectDataset("Dataset");
- if (BUG_36855717_FIXED) {
- callback.assertUiHiddenEvent(username);
- }
+ callback.assertUiHiddenEvent(username);
sUiBot.assertNoDatasets();
sUiBot.assertNotShownByText("Tap to auth response");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index d82ce48..8c350aa 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -19,8 +19,13 @@
import static android.autofillservice.cts.GridActivity.ID_L1C2;
import static android.autofillservice.cts.GridActivity.ID_L2C1;
import static android.autofillservice.cts.GridActivity.ID_L2C2;
+import static android.autofillservice.cts.GridActivity.ID_L3C1;
+import static android.autofillservice.cts.GridActivity.ID_L3C2;
+import static android.autofillservice.cts.GridActivity.ID_L4C1;
+import static android.autofillservice.cts.GridActivity.ID_L4C2;
import static android.autofillservice.cts.Helper.assertTextIsSanitized;
import static android.autofillservice.cts.Helper.assertValue;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -29,6 +34,8 @@
import android.autofillservice.cts.CannedFillResponse.CannedDataset;
import android.autofillservice.cts.GridActivity.FillExpectation;
import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.os.Bundle;
import android.support.test.rule.ActivityTestRule;
import org.junit.Before;
@@ -189,6 +196,103 @@
expectation2.assertAutoFilled();
}
+ @Test
+ public void testAutofillBundleDataIsPassedAlong() throws Exception {
+ // Set service.
+ enableService();
+
+ final Bundle extras = new Bundle();
+ extras.putString("numbers", "4");
+
+ // Prepare 1st partition.
+ final CannedFillResponse response1 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+ .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+ .build())
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_L1C1)
+ .setExtras(extras)
+ .build();
+ sReplier.addResponse(response1);
+
+ // Trigger auto-fill on 1st partition.
+ mActivity.focusCell(1, 1);
+ final FillRequest fillRequest1 = sReplier.getNextFillRequest();
+ assertThat(fillRequest1.data).isNull();
+ sUiBot.assertDatasets("l1c1");
+
+ // Prepare 2nd partition; it replaces 'number' and adds 'numbers2'
+ extras.clear();
+ extras.putString("numbers", "48");
+ extras.putString("numbers2", "1516");
+
+ final CannedFillResponse response2 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L2C1, "l2c1", createPresentation("l2c1"))
+ .setField(ID_L2C2, "l2c2", createPresentation("l2c2"))
+ .build())
+ .setExtras(extras)
+ .build();
+ sReplier.addResponse(response2);
+
+ // Trigger auto-fill on 2nd partition
+ mActivity.focusCell(2, 1);
+ final FillRequest fillRequest2 = sReplier.getNextFillRequest();
+ assertWithMessage("null bundle on request 2").that(fillRequest2.data).isNotNull();
+ assertWithMessage("wrong number of extras on request 2 bundle")
+ .that(fillRequest2.data.size()).isEqualTo(1);
+ assertThat(fillRequest2.data.getString("numbers")).isEqualTo("4");
+
+ // Prepare 3nd partition; it has no extras
+ final CannedFillResponse response3 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L3C1, "l3c1", createPresentation("l3c1"))
+ .setField(ID_L3C2, "l3c2", createPresentation("l3c2"))
+ .build())
+ .setExtras(null)
+ .build();
+ sReplier.addResponse(response3);
+
+ // Trigger auto-fill on 3rd partition
+ mActivity.focusCell(3, 1);
+ final FillRequest fillRequest3 = sReplier.getNextFillRequest();
+ assertWithMessage("null bundle on request 3").that(fillRequest2.data).isNotNull();
+ assertWithMessage("wrong number of extras on request 3 bundle")
+ .that(fillRequest3.data.size()).isEqualTo(2);
+ assertThat(fillRequest3.data.getString("numbers")).isEqualTo("48");
+ assertThat(fillRequest3.data.getString("numbers2")).isEqualTo("1516");
+
+
+ // Prepare 4th partition; it contains just 'numbers4'
+ extras.clear();
+ extras.putString("numbers4", "2342");
+
+ final CannedFillResponse response4 = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_L4C1, "l4c1", createPresentation("l4c1"))
+ .setField(ID_L4C2, "l4c2", createPresentation("l4c2"))
+ .build())
+ .setExtras(extras)
+ .build();
+ sReplier.addResponse(response4);
+
+ // Trigger auto-fill on 4th partition
+ mActivity.focusCell(4, 1);
+ final FillRequest fillRequest4 = sReplier.getNextFillRequest();
+ assertWithMessage("non-null bundle on request 4").that(fillRequest4.data).isNull();
+
+ // Trigger save
+ mActivity.setText(1, 1, "L1C1");
+ mActivity.save();
+
+ sUiBot.saveForAutofill(SAVE_DATA_TYPE_PASSWORD, true);
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+
+ assertWithMessage("wrong number of extras on save request bundle")
+ .that(saveRequest.data.size()).isEqualTo(1);
+ assertThat(saveRequest.data.getString("numbers4")).isEqualTo("2342");
+ }
+
// TODO(b/33197203, b/35707731): test force autofill after autofilled
// TODO(b/33197203, b/35707731): add test for saving (1, 2, 3, or more unique save types)
}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentManagerNonConfigTest.java b/tests/fragment/src/android/fragment/cts/FragmentManagerNonConfigTest.java
index 0ce4aa3..1b28290 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentManagerNonConfigTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentManagerNonConfigTest.java
@@ -35,23 +35,16 @@
public ActivityTestRule<NonConfigOnStopActivity> mActivityRule =
new ActivityTestRule<>(NonConfigOnStopActivity.class);
- @After
- public void resetActivity() {
- FragmentTestUtil.resetOrientation();
- }
-
/**
* When a fragment is added during onStop(), it shouldn't show up in non-config
* state when restored.
*/
@Test
public void nonConfigStop() throws Throwable {
- if (!FragmentTestUtil.switchOrientation()) {
- return; // nothing to do -- we can't change the orientation
- }
+ NonConfigOnStopActivity activity = FragmentTestUtil.recreateActivity(mActivityRule,
+ mActivityRule.getActivity());
// A fragment was added in onStop(), but we shouldn't see it here...
- Activity activity = OrientationChangeActivity.sActivity;
assertTrue(activity.getFragmentManager().getFragments().isEmpty());
}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
index 4b2ae16..c175164 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -24,8 +24,6 @@
import android.app.FragmentManager;
import android.app.FragmentManagerNonConfig;
import android.app.Instrumentation;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
import android.os.Looper;
import android.os.Parcelable;
import android.support.test.InstrumentationRegistry;
@@ -35,8 +33,6 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -218,57 +214,28 @@
}
/**
- * Switches the orientation of the OrientationChangeActivity.
+ * Restarts the RecreatedActivity and waits for the new activity to be resumed.
*
- * @return {@code true} if the orientation changed or {@code false} if the screen is square
- * or some other error happens
+ * @return The newly-restarted Activity
*/
- public static boolean switchOrientation() throws InterruptedException {
- OrientationChangeActivity activity = OrientationChangeActivity.sActivity;
-
- int currentOrientation = activity.getResources().getConfiguration().orientation;
-
- int nextOrientation;
- int expectedOrientation;
- if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
- nextOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- expectedOrientation = Configuration.ORIENTATION_PORTRAIT;
- } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
- nextOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- expectedOrientation = Configuration.ORIENTATION_LANDSCAPE;
- } else {
- return false; // Don't know what to do with square or unknown orientations
- }
-
+ public static <T extends RecreatedActivity> T recreateActivity(
+ ActivityTestRule<? extends Activity> rule, T activity) throws InterruptedException {
// Now switch the orientation
- LoaderActivity.sResumed = new CountDownLatch(1);
- LoaderActivity.sDestroyed = new CountDownLatch(1);
+ RecreatedActivity.sResumed = new CountDownLatch(1);
+ RecreatedActivity.sDestroyed = new CountDownLatch(1);
- activity.setRequestedOrientation(nextOrientation);
- assertTrue(LoaderActivity.sResumed.await(1, TimeUnit.SECONDS));
- assertTrue(LoaderActivity.sDestroyed.await(1, TimeUnit.SECONDS));
+ runOnUiThreadRethrow(rule, () -> {
+ activity.recreate();
+ });
+ assertTrue(RecreatedActivity.sResumed.await(1, TimeUnit.SECONDS));
+ assertTrue(RecreatedActivity.sDestroyed.await(1, TimeUnit.SECONDS));
+ T newActivity = (T) RecreatedActivity.sActivity;
- int switchedOrientation =
- LoaderActivity.sActivity.getResources().getConfiguration().orientation;
- assertEquals(expectedOrientation, switchedOrientation);
- return true;
+ waitForExecution(rule);
+
+ RecreatedActivity.clearState();
+ return newActivity;
}
+}
- /**
- * After calling {@link #switchOrientation()}, this must be called in an After.
- */
- public static void resetOrientation() {
- final OrientationChangeActivity activity = OrientationChangeActivity.sActivity;
- final int unspecifiedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- if (activity != null && activity.getRequestedOrientation() != unspecifiedOrientation) {
- OrientationChangeActivity.sResumed = new CountDownLatch(1);
- activity.setRequestedOrientation(unspecifiedOrientation);
- // Wait for the orientation change to settle, if there was a change
- try {
- OrientationChangeActivity.sResumed.await(1, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- // I guess there wasn't a change in orientation after all
- }
- }
- OrientationChangeActivity.clearState();
- }}
+
diff --git a/tests/fragment/src/android/fragment/cts/LoaderActivity.java b/tests/fragment/src/android/fragment/cts/LoaderActivity.java
index 5654b42..9c69f75 100644
--- a/tests/fragment/src/android/fragment/cts/LoaderActivity.java
+++ b/tests/fragment/src/android/fragment/cts/LoaderActivity.java
@@ -15,7 +15,6 @@
*/
package android.fragment.cts;
-import android.app.Activity;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Context;
@@ -24,13 +23,11 @@
import android.view.ViewGroup;
import android.widget.TextView;
-import java.util.concurrent.CountDownLatch;
-
/**
* This Activity sets the text when loading completes. It also tracks the Activity in
* a static variable, so it must be cleared in test tear down.
*/
-public class LoaderActivity extends OrientationChangeActivity {
+public class LoaderActivity extends RecreatedActivity {
public TextView textView;
public TextView textViewB;
diff --git a/tests/fragment/src/android/fragment/cts/LoaderTest.java b/tests/fragment/src/android/fragment/cts/LoaderTest.java
index 880d13e..2eb897e 100755
--- a/tests/fragment/src/android/fragment/cts/LoaderTest.java
+++ b/tests/fragment/src/android/fragment/cts/LoaderTest.java
@@ -22,14 +22,10 @@
import android.app.Fragment;
import android.app.FragmentManager;
-import android.app.Instrumentation;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Context;
-import android.content.Intent;
import android.content.Loader;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
@@ -37,7 +33,6 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,25 +50,17 @@
public ActivityTestRule<LoaderActivity> mActivityRule =
new ActivityTestRule<>(LoaderActivity.class);
- @After
- public void resetActivity() {
- FragmentTestUtil.resetOrientation();
- }
-
/**
* Test to ensure that there is no Activity leak due to Loader
*/
@Test
public void testLeak() throws Throwable {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Intent intent = new Intent(mActivityRule.getActivity(), LoaderActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- LoaderActivity.sResumed = new CountDownLatch(1);
- instrumentation.startActivitySync(intent);
- assertTrue(LoaderActivity.sResumed.await(1, TimeUnit.SECONDS));
-
+ // Restart the activity because mActivityRule keeps a strong reference to the
+ // old activity.
+ LoaderActivity activity = FragmentTestUtil.recreateActivity(mActivityRule,
+ mActivityRule.getActivity());
LoaderFragment fragment = new LoaderFragment();
- FragmentManager fm = LoaderActivity.sActivity.getFragmentManager();
+ FragmentManager fm = activity.getFragmentManager();
fm.beginTransaction()
.add(fragment, "1")
@@ -87,12 +74,11 @@
.commit();
FragmentTestUtil.executePendingTransactions(mActivityRule, fm);
+ fm = null; // clear it so that it can be released
WeakReference<LoaderActivity> weakActivity = new WeakReference(LoaderActivity.sActivity);
- if (!FragmentTestUtil.switchOrientation()) {
- return; // can't switch orientation for square screens
- }
+ activity = FragmentTestUtil.recreateActivity(mActivityRule, activity);
// Wait for everything to settle. We have to make sure that the old Activity
// is ready to be collected.
@@ -113,12 +99,9 @@
assertEquals("Loaded!", activity.textView.getText().toString());
- if (!FragmentTestUtil.switchOrientation()) {
- return; // can't switch orientation for square screens
- }
+ activity = FragmentTestUtil.recreateActivity(mActivityRule, activity);
// After orientation change, the text should still be loaded properly
- activity = (LoaderActivity) LoaderActivity.sActivity;
assertEquals("Loaded!", activity.textView.getText().toString());
}
diff --git a/tests/fragment/src/android/fragment/cts/NonConfigOnStopActivity.java b/tests/fragment/src/android/fragment/cts/NonConfigOnStopActivity.java
index e61bd50..a93b616 100644
--- a/tests/fragment/src/android/fragment/cts/NonConfigOnStopActivity.java
+++ b/tests/fragment/src/android/fragment/cts/NonConfigOnStopActivity.java
@@ -17,7 +17,7 @@
import android.app.Fragment;
-public class NonConfigOnStopActivity extends OrientationChangeActivity {
+public class NonConfigOnStopActivity extends RecreatedActivity {
@Override
protected void onStop() {
super.onStop();
diff --git a/tests/fragment/src/android/fragment/cts/OrientationChangeActivity.java b/tests/fragment/src/android/fragment/cts/RecreatedActivity.java
similarity index 92%
rename from tests/fragment/src/android/fragment/cts/OrientationChangeActivity.java
rename to tests/fragment/src/android/fragment/cts/RecreatedActivity.java
index d8aeb31..82b32a9 100644
--- a/tests/fragment/src/android/fragment/cts/OrientationChangeActivity.java
+++ b/tests/fragment/src/android/fragment/cts/RecreatedActivity.java
@@ -20,9 +20,9 @@
import java.util.concurrent.CountDownLatch;
-public class OrientationChangeActivity extends Activity {
+public class RecreatedActivity extends Activity {
// These must be cleared after each test using clearState()
- public static OrientationChangeActivity sActivity;
+ public static RecreatedActivity sActivity;
public static CountDownLatch sResumed;
public static CountDownLatch sDestroyed;
diff --git a/tests/tests/graphics/assets/almost-red-adobe.png b/tests/tests/graphics/assets/almost-red-adobe.png
new file mode 100644
index 0000000..531b5a4
--- /dev/null
+++ b/tests/tests/graphics/assets/almost-red-adobe.png
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index 64dba77..05f74f8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -51,12 +51,15 @@
import android.text.SpannedString;
import android.util.DisplayMetrics;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Vector;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class CanvasTest {
@@ -2114,4 +2117,24 @@
assertEquals(matrices.elementAt(i), mCanvas.getMatrix());
}
}
+
+ @Test
+ public void testDrawBitmapColorBehavior() {
+ try {
+ // Create a wide gamut bitmap where the pixel value is slightly less than max red.
+ Resources resources = InstrumentationRegistry.getTargetContext().getResources();
+ InputStream in = resources.getAssets().open("almost-red-adobe.png");
+ Bitmap bitmap = BitmapFactory.decodeStream(in);
+
+ // Draw the bitmap to an sRGB canvas.
+ Bitmap canvasBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(canvasBitmap);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+
+ // Verify that the pixel is now max red.
+ Assert.assertEquals(0xFFFF0000, canvasBitmap.getPixel(0, 0));
+ } catch (IOException e) {
+ Assert.fail();
+ }
+ }
}
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index b2ae259..1fb5460 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -45,23 +45,26 @@
LOCAL_MULTILIB := both
LOCAL_STATIC_JAVA_LIBRARIES := \
- ctsmediautil \
compatibility-device-util \
- ctstestserver \
+ ctsdeviceutillegacy \
+ ctsmediautil \
ctstestrunner \
- ndkaudio \
+ ctstestserver \
junit \
- legacy-android-test
+ legacy-android-test \
+ ndkaudio
LOCAL_JNI_SHARED_LIBRARIES := \
- libctsimagereader_jni \
- libctsmediacodec_jni \
libaudio_jni \
+ libctsimagereader_jni \
+ libctsmediadrm_jni \
+ libctsmediacodec_jni \
libnativehelper_compat_libc++ \
libndkaudioLib
# do not compress VP9 video files
LOCAL_AAPT_FLAGS := -0 .vp9
+LOCAL_AAPT_FLAGS += -0 .ts
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/media/libmediandkjni/AMediaObjects.h b/tests/tests/media/libmediandkjni/AMediaObjects.h
new file mode 100644
index 0000000..c4d5397
--- /dev/null
+++ b/tests/tests/media/libmediandkjni/AMediaObjects.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AMEDIAOBJECTS_H_
+#define AMEDIAOBJECTS_H_
+
+#include <utils/Log.h>
+
+#include "media/NdkMediaCrypto.h"
+#include "media/NdkMediaDrm.h"
+#include "media/NdkMediaExtractor.h"
+
+namespace {
+
+// Simple class to manage deletion of AMedia objects
+class AMediaObjects {
+ public:
+ AMediaObjects();
+ virtual ~AMediaObjects();
+
+ void setCrypto(AMediaCrypto* const theCrypto) {
+ mCrypto = theCrypto;
+ }
+ void setDrm(AMediaDrm* const theDrm) {
+ mDrm = theDrm;
+ }
+ void setVideoExtractor(AMediaExtractor* const theExtractor) {
+ mVideoExtractor = theExtractor;
+ }
+ void setAudioExtractor(AMediaExtractor* const theExtractor) {
+ mAudioExtractor = theExtractor;
+ }
+
+ AMediaCrypto* getCrypto() const { return mCrypto; }
+ AMediaDrm* getDrm() const { return mDrm; }
+ AMediaExtractor* getAudioExtractor() const { return mAudioExtractor; }
+ AMediaExtractor* getVideoExtractor() const { return mVideoExtractor; }
+
+ private:
+ AMediaCrypto *mCrypto;
+ AMediaDrm* mDrm;
+ AMediaExtractor* mAudioExtractor;
+ AMediaExtractor* mVideoExtractor;
+
+ // Disallow copy and assignment
+ AMediaObjects(const AMediaObjects&);
+ void operator=(const AMediaObjects&);
+};
+
+AMediaObjects::AMediaObjects(void) : mCrypto(NULL), mDrm(NULL),
+ mAudioExtractor(NULL), mVideoExtractor(NULL) {
+}
+
+AMediaObjects::~AMediaObjects() {
+ if (mCrypto) {
+ AMediaCrypto_delete(mCrypto);
+ }
+ if (mAudioExtractor) {
+ AMediaExtractor_delete(mAudioExtractor);
+ }
+ if (mVideoExtractor) {
+ AMediaExtractor_delete(mVideoExtractor);
+ }
+ if (mDrm) {
+ AMediaDrm_release(mDrm);
+ }
+}
+
+} // anonymous namespace
+#endif // AMEDIAOBJECTS_H_
+
diff --git a/tests/tests/media/libmediandkjni/Android.mk b/tests/tests/media/libmediandkjni/Android.mk
index 39dbea3..e42d388 100644
--- a/tests/tests/media/libmediandkjni/Android.mk
+++ b/tests/tests/media/libmediandkjni/Android.mk
@@ -14,27 +14,67 @@
#
LOCAL_PATH := $(call my-dir)
+#------------------------------------------------------------------------------
+# Builds libctsmediacodec_jni.so
+#
include $(CLEAR_VARS)
-LOCAL_MODULE := libctsmediacodec_jni
+LOCAL_MODULE := libctsmediacodec_jni
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- native-media-jni.cpp \
- codec-utils-jni.cpp \
- md5_utils.cpp
+ native-media-jni.cpp \
+ codec-utils-jni.cpp \
+ md5_utils.cpp
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
- system/core/include
+ $(JNI_H_INCLUDE) \
+ system/core/include
LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
-LOCAL_SHARED_LIBRARIES := libandroid libnativehelper_compat_libc++ liblog libmediandk libEGL
+LOCAL_SHARED_LIBRARIES := \
+ libandroid libnativehelper_compat_libc++ \
+ liblog libmediandk libEGL
LOCAL_SDK_VERSION := current
LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
include $(BUILD_SHARED_LIBRARY)
+
+#------------------------------------------------------------------------------
+# Builds libctsmediadrm_jni.so
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libctsmediadrm_jni
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ CtsMediaDrmJniOnLoad.cpp \
+ codec-utils-jni.cpp \
+ md5_utils.cpp \
+ native-mediadrm-jni.cpp \
+
+LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE) \
+ system/core/include
+
+
+LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid libnativehelper_compat_libc++ \
+ liblog libmediandk libdl libEGL
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_CFLAGS := -Werror -Wall -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/media/libmediandkjni/CtsMediaDrmJniOnLoad.cpp b/tests/tests/media/libmediandkjni/CtsMediaDrmJniOnLoad.cpp
new file mode 100644
index 0000000..24714a3
--- /dev/null
+++ b/tests/tests/media/libmediandkjni/CtsMediaDrmJniOnLoad.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <stdio.h>
+
+extern int register_android_media_cts_NativeClearKeySystemTest(JNIEnv*);
+
+jint JNI_OnLoad(JavaVM *vm, void */*reserved*/) {
+ JNIEnv *env = NULL;
+
+ if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
+ return JNI_ERR;
+ }
+
+ if (register_android_media_cts_NativeClearKeySystemTest(env)) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_4;
+}
diff --git a/tests/tests/media/libmediandkjni/md5_utils.cpp b/tests/tests/media/libmediandkjni/md5_utils.cpp
index f4f893a..8e520e1 100644
--- a/tests/tests/media/libmediandkjni/md5_utils.cpp
+++ b/tests/tests/media/libmediandkjni/md5_utils.cpp
@@ -157,7 +157,7 @@
*/
void
MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
- register UWORD32 a, b, c, d;
+ UWORD32 a, b, c, d;
a = buf[0];
b = buf[1];
diff --git a/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
new file mode 100644
index 0000000..b98a6af
--- /dev/null
+++ b/tests/tests/media/libmediandkjni/native-mediadrm-jni.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TAG "NativeMediaDrm"
+
+#include <utils/Log.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include <assert.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include <android/native_window_jni.h>
+
+#include "AMediaObjects.h"
+
+#include "media/NdkMediaCodec.h"
+#include "media/NdkMediaCrypto.h"
+#include "media/NdkMediaDrm.h"
+#include "media/NdkMediaExtractor.h"
+#include "media/NdkMediaFormat.h"
+#include "media/NdkMediaMuxer.h"
+
+typedef std::vector<uint8_t> Uuid;
+
+struct fields_t {
+ jfieldID surface;
+ jfieldID mimeType;
+ jfieldID audioUrl;
+ jfieldID videoUrl;
+};
+
+struct PlaybackParams {
+ jobject surface;
+ jstring mimeType;
+ jstring audioUrl;
+ jstring videoUrl;
+};
+
+static fields_t gFieldIds;
+static bool gGotVendorDefinedEvent = false;
+
+static const size_t kPlayTimeSeconds = 30;
+static const size_t kUuidSize = 16;
+
+static const uint8_t kWidevineUuid[kUuidSize] = {
+ 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce,
+ 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed
+};
+
+// The test content is not packaged with clearkey UUID,
+// we have to use a canned clearkey pssh for the test.
+static const uint8_t kClearkeyPssh[] = {
+ // BMFF box header (4 bytes size + 'pssh')
+ 0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
+ // full box header (version = 1 flags = 0)
+ 0x01, 0x00, 0x00, 0x00,
+ // system id
+ 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
+ 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+ // number of key ids
+ 0x00, 0x00, 0x00, 0x01,
+ // key id
+ 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87,
+ 0x7e, 0x57, 0xd0, 0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
+ // size of data, must be zero
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t kKeyRequestData[] = {
+ 0x7b, 0x22, 0x6b, 0x69, 0x64,
+ 0x73, 0x22, 0x3a, 0x5b, 0x22,
+ 0x59, 0x41, 0x59, 0x65, 0x41,
+ 0x58, 0x35, 0x48, 0x66, 0x6f,
+ 0x64, 0x2b, 0x56, 0x39, 0x41,
+ 0x4e, 0x48, 0x74, 0x41, 0x4e,
+ 0x48, 0x67, 0x22, 0x5d, 0x2c,
+ 0x22, 0x74, 0x79, 0x70, 0x65,
+ 0x22, 0x3a, 0x22, 0x74, 0x65,
+ 0x6d, 0x70, 0x6f, 0x72, 0x61,
+ 0x72, 0x79, 0x22, 0x7d,
+};
+
+static const size_t kKeyRequestSize = sizeof(kKeyRequestData);
+
+// base 64 encoded JSON response string, must not contain padding character '='
+static const char kResponse[] = "{\"keys\":[{\"kty\":\"oct\"," \
+ "\"kid\":\"YAYeAX5Hfod+V9ANHtANHg\",\"k\":" \
+ "\"GoogleTestKeyBase64ggg\"}]}";
+
+static bool isUuidSizeValid(Uuid uuid) {
+ return (uuid.size() == kUuidSize);
+}
+
+static std::vector<uint8_t> jbyteArrayToVector(
+ JNIEnv* env, jbyteArray const &byteArray) {
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(
+ env->GetByteArrayElements(byteArray, /*is_copy*/NULL));
+ std::vector<uint8_t> vector;
+ for (jsize i = 0; i < env->GetArrayLength(byteArray); ++i) {
+ vector.push_back(buffer[i]);
+ }
+ return vector;
+}
+
+static Uuid jbyteArrayToUuid(JNIEnv* env, jbyteArray const &uuid) {
+ Uuid juuid;
+ juuid.resize(0);
+ if (uuid != NULL) {
+ juuid = jbyteArrayToVector(env, uuid);
+ }
+ return juuid;
+}
+
+extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest_isCryptoSchemeSupportedNative(
+ JNIEnv* env, jclass /*clazz*/, jbyteArray uuid) {
+
+ if (NULL == uuid) {
+ jniThrowException(env, "java/lang/NullPointerException", "null uuid");
+ return JNI_FALSE;
+ }
+
+ Uuid juuid = jbyteArrayToUuid(env, uuid);
+ if (isUuidSizeValid(juuid)) {
+ return AMediaDrm_isCryptoSchemeSupported(&juuid[0], NULL);
+ } else {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "invalid UUID size, expected %u bytes", kUuidSize);
+ }
+ return JNI_FALSE;
+}
+
+void initPlaybackParams(JNIEnv* env, const jobject &playbackParams, PlaybackParams ¶ms) {
+ params.surface = env->GetObjectField(
+ playbackParams, gFieldIds.surface);
+
+ params.mimeType = static_cast<jstring>(env->GetObjectField(
+ playbackParams, gFieldIds.mimeType));
+
+ params.audioUrl = static_cast<jstring>(env->GetObjectField(
+ playbackParams, gFieldIds.audioUrl));
+
+ params.videoUrl = static_cast<jstring>(env->GetObjectField(
+ playbackParams, gFieldIds.videoUrl));
+}
+
+extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest_testGetPropertyStringNative(
+ JNIEnv* env, jclass clazz, jbyteArray uuid,
+ jstring name, jobject outValue) {
+
+ if (NULL == uuid || NULL == name || NULL == outValue) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "One or more null input parameters");
+ return JNI_FALSE;
+ }
+
+ Uuid juuid = jbyteArrayToUuid(env, uuid);
+ if (!isUuidSizeValid(juuid)) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "invalid UUID size, expected %u bytes", kUuidSize);
+ return JNI_FALSE;
+ }
+
+ AMediaObjects aMediaObjects;
+ aMediaObjects.setDrm(AMediaDrm_createByUUID(&juuid[0]));
+ if (NULL == aMediaObjects.getDrm()) {
+ jniThrowException(env, "java/lang/RuntimeException", "null MediaDrm");
+ return JNI_FALSE;
+ }
+
+ const char *utf8_name = env->GetStringUTFChars(name, NULL);
+ const char *utf8_outValue = NULL;
+ media_status_t status = AMediaDrm_getPropertyString(aMediaObjects.getDrm(),
+ utf8_name, &utf8_outValue);
+ env->ReleaseStringUTFChars(name, utf8_name);
+
+ if (NULL != utf8_outValue) {
+ clazz = env->GetObjectClass(outValue);
+ jmethodID mId = env->GetMethodID (clazz, "append",
+ "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+ jstring outString = env->NewStringUTF(
+ static_cast<const char *>(utf8_outValue));
+ env->CallObjectMethod(outValue, mId, outString);
+ } else {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "get property string returns %d", status);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest__testPsshNative(
+ JNIEnv* env, jclass /*clazz*/, jbyteArray uuid, jstring videoUrl) {
+
+ if (NULL == uuid || NULL == videoUrl) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "null uuid or null videoUrl");
+ return JNI_FALSE;
+ }
+
+ Uuid juuid = jbyteArrayToUuid(env, uuid);
+ if (!isUuidSizeValid(juuid)) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "invalid UUID size, expected %u bytes", kUuidSize);
+ return JNI_FALSE;
+ }
+
+ AMediaObjects aMediaObjects;
+ aMediaObjects.setVideoExtractor(AMediaExtractor_new());
+ const char* url = env->GetStringUTFChars(videoUrl, 0);
+ if (url) {
+ media_status_t status = AMediaExtractor_setDataSource(
+ aMediaObjects.getVideoExtractor(), url);
+ env->ReleaseStringUTFChars(videoUrl, url);
+
+ if (status != AMEDIA_OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "set video data source error=%d", status);
+ return JNI_FALSE;
+ }
+ }
+
+ PsshInfo* psshInfo = AMediaExtractor_getPsshInfo(aMediaObjects.getVideoExtractor());
+ if (psshInfo == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "null psshInfo");
+ return JNI_FALSE;
+ }
+
+ jboolean testResult = JNI_FALSE;
+ for (size_t i = 0; i < psshInfo->numentries; i++) {
+ PsshEntry *entry = &psshInfo->entries[i];
+
+ // We do not have clearkey content that contains ClearKey UUID in the
+ // pssh box. So we have to test if it has Widevine UUID instead.
+ // TODO: Replace kWidevineUuid with uuid when test content contains
+ // ClearKey UUID.
+ if (0 == memcmp(entry->uuid, kWidevineUuid, sizeof(entry->uuid))) {
+ aMediaObjects.setCrypto(
+ AMediaCrypto_new(entry->uuid, entry->data, entry->datalen));
+ if (aMediaObjects.getCrypto()) {
+ testResult = JNI_TRUE;
+ } else {
+ ALOGE("Failed to create media crypto=%zd", i);
+ testResult = JNI_FALSE;
+ }
+ break;
+ }
+ }
+ return testResult;
+}
+
+static bool isVideo(const char* mime) {
+ return !strncmp(mime, "video/", 6) ? true : false;
+}
+
+static bool isAudio(const char* mime) {
+ return !strncmp(mime, "audio/", 6) ? true : false;
+}
+
+static void addTrack(const AMediaFormat* format,
+ const char* mime, const AMediaCrypto* crypto,
+ const ANativeWindow* window, AMediaCodec** codec) {
+
+ *codec = AMediaCodec_createDecoderByType(mime);
+ if (codec == NULL) {
+ ALOGE("cannot create codec for %s", mime);
+ return;
+ }
+
+ AMediaCodec_configure(*codec, format,
+ const_cast<ANativeWindow*>(window),
+ const_cast<AMediaCrypto*>(crypto), 0);
+}
+
+static void addTracks(const AMediaExtractor* extractor,
+ const AMediaCrypto* crypto, const ANativeWindow* window,
+ AMediaCodec** codec) {
+ size_t numTracks = AMediaExtractor_getTrackCount(
+ const_cast<AMediaExtractor*>(extractor));
+ AMediaFormat* trackFormat = NULL;
+ for (size_t i = 0; i < numTracks; ++i) {
+ trackFormat = AMediaExtractor_getTrackFormat(
+ const_cast<AMediaExtractor*>(extractor), i);
+ if (trackFormat) {
+ ALOGV("track %zd format: %s", i,
+ AMediaFormat_toString(trackFormat));
+
+ const char* mime = "";
+ if (!AMediaFormat_getString(
+ trackFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
+ ALOGE("no mime type");
+ AMediaFormat_delete(trackFormat);
+ return;
+ } else if (isAudio(mime) || isVideo(mime)) {
+ AMediaExtractor_selectTrack(
+ const_cast<AMediaExtractor*>(extractor), i);
+ ALOGV("track %zd codec format: %s", i,
+ AMediaFormat_toString(trackFormat));
+
+ addTrack(trackFormat, mime, crypto, window, codec);
+ AMediaCodec_start(*codec);
+ AMediaCodec_flush(*codec);
+ AMediaExtractor_seekTo(
+ const_cast<AMediaExtractor*>(extractor), 0,
+ AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC);
+ }
+ AMediaFormat_delete(trackFormat);
+ }
+ }
+}
+
+static int64_t getSystemNanoTime() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec * 1000000000LL + now.tv_nsec;
+}
+
+static void fillDecoder(AMediaCodec* codec, AMediaExtractor* extractor,
+ int64_t* presentationTimeUs, bool* eosReached) {
+ media_status_t status = AMEDIA_OK;
+
+ ssize_t bufferIndex = AMediaCodec_dequeueInputBuffer(codec, 2000);
+ if (bufferIndex >= 0) {
+ size_t bufsize;
+ uint8_t* buf = AMediaCodec_getInputBuffer(codec, bufferIndex, &bufsize);
+
+ int sampleSize = AMediaExtractor_readSampleData(extractor, buf, bufsize);
+ if (sampleSize < 0) {
+ sampleSize = 0;
+ *eosReached = true;
+ }
+
+ *presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
+
+ AMediaCodecCryptoInfo *cryptoInfo =
+ AMediaExtractor_getSampleCryptoInfo(extractor);
+ if (cryptoInfo) {
+ status = AMediaCodec_queueSecureInputBuffer(
+ codec, bufferIndex, 0, cryptoInfo,
+ *presentationTimeUs,
+ *eosReached ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
+ AMediaCodecCryptoInfo_delete(cryptoInfo);
+ } else {
+ status = AMediaCodec_queueInputBuffer(
+ codec, bufferIndex, 0, sampleSize,
+ *presentationTimeUs,
+ *eosReached ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
+ }
+ AMediaExtractor_advance(extractor);
+ }
+}
+
+static bool drainDecoder(AMediaCodec* codec, int64_t presentationTimeUs,
+ int64_t* startTimeNano) {
+
+ AMediaCodecBufferInfo info;
+ ssize_t bufferIndex = AMediaCodec_dequeueOutputBuffer(codec, &info, 0);
+ if (bufferIndex >= 0) {
+ if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
+ return true; // eos reached
+ }
+
+ if (*startTimeNano < 0) {
+ *startTimeNano = getSystemNanoTime() - (presentationTimeUs * 1000);
+ }
+ int64_t delay = (*startTimeNano + presentationTimeUs * 1000) -
+ getSystemNanoTime();
+ if (delay > 0) {
+ usleep(delay / 1000);
+ }
+
+ AMediaCodec_releaseOutputBuffer(codec, bufferIndex, info.size != 0);
+ } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
+ ALOGV("output buffers changed");
+ } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+ AMediaFormat* format = AMediaCodec_getOutputFormat(codec);
+ ALOGV("format changed to: %s", AMediaFormat_toString(format));
+ AMediaFormat_delete(format);
+ } else if (bufferIndex == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+ ALOGV("no output buffer right now");
+ usleep(20000);
+ } else {
+ ALOGV("unexpected info code: %zd", bufferIndex);
+ }
+ return false;
+}
+
+static jboolean playContent(JNIEnv* env, const AMediaObjects& aMediaObjects,
+ PlaybackParams& params, const AMediaDrmSessionId& sessionId, Uuid uuid) {
+
+ ANativeWindow *window = ANativeWindow_fromSurface(env, params.surface);
+ AMediaExtractor* audioExtractor = aMediaObjects.getAudioExtractor();
+ AMediaExtractor* videoExtractor = aMediaObjects.getVideoExtractor();
+
+ AMediaCodec* audioCodec = NULL;
+ AMediaCodec* videoCodec = NULL;
+ AMediaCrypto* crypto = NULL;
+
+ crypto = AMediaCrypto_new(&uuid[0], sessionId.ptr, sessionId.length);
+ if (crypto == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "failed to create crypto object");
+ return JNI_FALSE;
+ }
+
+ addTracks(audioExtractor, NULL, NULL, &audioCodec);
+ addTracks(videoExtractor, crypto, window, &videoCodec);
+
+ bool sawAudioInputEos = false;
+ bool sawAudioOutputEos = false;
+ bool sawVideoInputEos = false;
+ bool sawVideoOutputEos = false;
+ int64_t videoPresentationTimeUs = 0;
+ int64_t videoStartTimeNano = -1;
+ struct timespec timeSpec;
+ clock_gettime(CLOCK_MONOTONIC, &timeSpec);
+ time_t startTimeSec = timeSpec.tv_sec;
+
+ while (!sawAudioOutputEos && !sawVideoOutputEos) {
+ if (!sawVideoInputEos) {
+ fillDecoder(videoCodec, videoExtractor,
+ &videoPresentationTimeUs, &sawVideoInputEos);
+ }
+
+ if (!sawAudioInputEos) {
+ // skip audio, still need to advance the audio extractor
+ AMediaExtractor_advance(audioExtractor);
+ }
+
+ if (!sawVideoOutputEos) {
+ sawVideoOutputEos = drainDecoder(videoCodec, videoPresentationTimeUs,
+ &videoStartTimeNano);
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &timeSpec);
+ if (timeSpec.tv_sec >= static_cast<time_t>(
+ (startTimeSec + kPlayTimeSeconds))) {
+ // stop reading samples and drain the output buffers
+ sawAudioInputEos = sawVideoInputEos = true;
+ sawAudioOutputEos = true; // ignore audio
+ }
+ }
+
+ if (audioCodec) {
+ AMediaCodec_stop(audioCodec);
+ AMediaCodec_delete(audioCodec);
+ }
+ if (videoCodec) {
+ AMediaCodec_stop(videoCodec);
+ AMediaCodec_delete(videoCodec);
+ }
+
+ AMediaCrypto_delete(crypto);
+ ANativeWindow_release(window);
+ return JNI_TRUE;
+}
+
+static void listener(
+ AMediaDrm* /*drm*/, const AMediaDrmSessionId* /*sessionId*/,
+ AMediaDrmEventType eventType,
+ int /*extra*/, const uint8_t* /*data*/, size_t /*dataSize*/) {
+
+ switch (eventType) {
+ case EVENT_PROVISION_REQUIRED:
+ ALOGD("EVENT_PROVISION_REQUIRED received");
+ break;
+ case EVENT_KEY_REQUIRED:
+ ALOGD("EVENT_KEY_REQUIRED received");
+ break;
+ case EVENT_KEY_EXPIRED:
+ ALOGD("EVENT_KEY_EXPIRED received");
+ break;
+ case EVENT_VENDOR_DEFINED:
+ gGotVendorDefinedEvent = true;
+ ALOGD("EVENT_VENDOR_DEFINED received");
+ break;
+ default:
+ ALOGD("Unknown event received");
+ break;
+ }
+}
+
+extern "C" jboolean Java_android_media_cts_NativeClearKeySystemTest_testClearKeyPlaybackNative(
+ JNIEnv* env, jclass /*clazz*/, jbyteArray uuid, jobject playbackParams) {
+ if (NULL == uuid || NULL == playbackParams) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "null uuid or null playback parameters");
+ return JNI_FALSE;
+ }
+
+ Uuid juuid = jbyteArrayToUuid(env, uuid);
+ if (!isUuidSizeValid(juuid)) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "invalid UUID size, expected %u bytes", kUuidSize);
+ return JNI_FALSE;
+ }
+
+ PlaybackParams params;
+ initPlaybackParams(env, playbackParams, params);
+
+ AMediaObjects aMediaObjects;
+ media_status_t status = AMEDIA_OK;
+ aMediaObjects.setDrm(AMediaDrm_createByUUID(&juuid[0]));
+ if (NULL == aMediaObjects.getDrm()) {
+ jniThrowException(env, "java/lang/RuntimeException", "null MediaDrm");
+ return JNI_FALSE;
+ }
+
+ status = AMediaDrm_setOnEventListener(aMediaObjects.getDrm(), listener);
+ if (status != AMEDIA_OK) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "setOnEventListener failed");
+ return JNI_FALSE;
+ }
+
+ aMediaObjects.setAudioExtractor(AMediaExtractor_new());
+ const char* url = env->GetStringUTFChars(params.audioUrl, 0);
+ if (url) {
+ status = AMediaExtractor_setDataSource(
+ aMediaObjects.getAudioExtractor(), url);
+ env->ReleaseStringUTFChars(params.audioUrl, url);
+
+ if (status != AMEDIA_OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "set audio data source error=%d", status);
+ return JNI_FALSE;
+ }
+ }
+
+ aMediaObjects.setVideoExtractor(AMediaExtractor_new());
+ url = env->GetStringUTFChars(params.videoUrl, 0);
+ if (url) {
+ status = AMediaExtractor_setDataSource(
+ aMediaObjects.getVideoExtractor(), url);
+ env->ReleaseStringUTFChars(params.videoUrl, url);
+
+ if (status != AMEDIA_OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "set video data source error=%d", status);
+ return JNI_FALSE;
+ }
+ }
+
+ AMediaDrmSessionId sessionId;
+ status = AMediaDrm_openSession(aMediaObjects.getDrm(), &sessionId);
+ if (status != AMEDIA_OK) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "openSession failed");
+ return JNI_FALSE;
+ }
+
+ // Pointer to keyRequest memory, which remains until the next
+ // AMediaDrm_getKeyRequest call or until the drm object is released.
+ const uint8_t* keyRequest;
+ size_t keyRequestSize = 0;
+
+ // The server recognizes "video/mp4" but not "video/avc".
+ status = AMediaDrm_getKeyRequest(aMediaObjects.getDrm(), &sessionId,
+ kClearkeyPssh, sizeof(kClearkeyPssh),
+ "video/mp4" /*mimeType*/, KEY_TYPE_STREAMING,
+ NULL, 0, &keyRequest, &keyRequestSize);
+ if (status != AMEDIA_OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "getKeyRequest failed, error = %d", status);
+ AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+ return JNI_FALSE;
+ }
+
+ if (kKeyRequestSize != keyRequestSize) {
+ ALOGE("Invalid keyRequestSize %zd", keyRequestSize);
+ return JNI_FALSE;
+ }
+
+ if (memcmp(kKeyRequestData, keyRequest, kKeyRequestSize) != 0) {
+ ALOGE("Invalid keyRequest data is returned");
+ return JNI_FALSE;
+ }
+
+ AMediaDrmKeySetId keySetId;
+ gGotVendorDefinedEvent = false;
+ status = AMediaDrm_provideKeyResponse(aMediaObjects.getDrm(), &sessionId,
+ reinterpret_cast<const uint8_t*>(kResponse),
+ sizeof(kResponse), &keySetId);
+ if (status != AMEDIA_OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "provideKeyResponse failed, error = %d", status);
+ AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+ return JNI_FALSE;
+ }
+
+ // Check if the event listener has received the expected event sent by
+ // provideKeyResponse. This is for testing AMediaDrm_setOnEventListener().
+ const char *utf8_outValue = NULL;
+ status = AMediaDrm_getPropertyString(aMediaObjects.getDrm(),
+ "listenerTestSupport", &utf8_outValue);
+ if (status == AMEDIA_OK && NULL != utf8_outValue) {
+ std::string eventType(utf8_outValue);
+ if (eventType.compare("true") == 0) {
+ int count = 0;
+ while (!gGotVendorDefinedEvent && count++ < 5) {
+ // Prevents race condition when the event arrives late
+ usleep(1000);
+ }
+ if (!gGotVendorDefinedEvent) {
+ ALOGE("Event listener did not receive the expected event.");
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "Event listener did not receive the expected event.");
+ AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ playContent(env, aMediaObjects, params, sessionId, juuid);
+
+ status = AMediaDrm_closeSession(aMediaObjects.getDrm(), &sessionId);
+ if (status != AMEDIA_OK) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "closeSession failed");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "isCryptoSchemeSupportedNative", "([B)Z",
+ (void *)Java_android_media_cts_NativeClearKeySystemTest_isCryptoSchemeSupportedNative },
+
+ { "testClearKeyPlaybackNative",
+ "([BLandroid/media/cts/NativeClearKeySystemTest$PlaybackParams;)Z",
+ (void *)Java_android_media_cts_NativeClearKeySystemTest_testClearKeyPlaybackNative },
+
+ { "testGetPropertyStringNative",
+ "([BLjava/lang/String;Ljava/lang/StringBuffer;)Z",
+ (void *)Java_android_media_cts_NativeClearKeySystemTest_testGetPropertyStringNative },
+
+ { "testPsshNative", "([BLjava/lang/String;)Z",
+ (void *)Java_android_media_cts_NativeClearKeySystemTest__testPsshNative },
+};
+
+int register_android_media_cts_NativeClearKeySystemTest(JNIEnv* env) {
+ jint result = JNI_ERR;
+ jclass testClass =
+ env->FindClass("android/media/cts/NativeClearKeySystemTest");
+ if (testClass) {
+ jclass playbackParamsClass = env->FindClass(
+ "android/media/cts/NativeClearKeySystemTest$PlaybackParams");
+ if (playbackParamsClass) {
+ jclass surfaceClass =
+ env->FindClass("android/view/Surface");
+ if (surfaceClass) {
+ gFieldIds.surface = env->GetFieldID(playbackParamsClass,
+ "surface", "Landroid/view/Surface;");
+ } else {
+ gFieldIds.surface = NULL;
+ }
+ gFieldIds.mimeType = env->GetFieldID(playbackParamsClass,
+ "mimeType", "Ljava/lang/String;");
+ gFieldIds.audioUrl = env->GetFieldID(playbackParamsClass,
+ "audioUrl", "Ljava/lang/String;");
+ gFieldIds.videoUrl = env->GetFieldID(playbackParamsClass,
+ "videoUrl", "Ljava/lang/String;");
+ } else {
+ ALOGE("PlaybackParams class not found");
+ }
+
+ } else {
+ ALOGE("NativeClearKeySystemTest class not found");
+ }
+
+ result = env->RegisterNatives(testClass, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+ return result;
+}
diff --git a/tests/tests/media/res/raw/segment000001.ts b/tests/tests/media/res/raw/segment000001.ts
new file mode 100644
index 0000000..fb112ec
--- /dev/null
+++ b/tests/tests/media/res/raw/segment000001.ts
Binary files differ
diff --git a/tests/tests/media/res/raw/segment000001_scrambled.ts b/tests/tests/media/res/raw/segment000001_scrambled.ts
new file mode 100644
index 0000000..4c7d368
--- /dev/null
+++ b/tests/tests/media/res/raw/segment000001_scrambled.ts
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index b48db78..ba657bf 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -471,8 +471,7 @@
int[] streams = {AudioManager.STREAM_ALARM,
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_VOICE_CALL,
- AudioManager.STREAM_RING,
- AudioManager.STREAM_ACCESSIBILITY};
+ AudioManager.STREAM_RING};
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
// adjusting volume is aynchronous, wait before other volume checks
@@ -482,12 +481,12 @@
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
- for (int i = 0; i < streams.length; i++) {
+ for (int stream : streams) {
// set ringer mode to back normal to not interfere with volume tests
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- int maxVolume = mAudioManager.getStreamMaxVolume(streams[i]);
- int minVolume = mAudioManager.getStreamMinVolume(streams[i]);
+ int maxVolume = mAudioManager.getStreamMaxVolume(stream);
+ int minVolume = mAudioManager.getStreamMinVolume(stream);
// validate min
assertTrue(String.format("minVolume(%d) must be >= 0", minVolume), minVolume >= 0);
@@ -495,14 +494,15 @@
maxVolume),
minVolume < maxVolume);
- mAudioManager.setStreamVolume(streams[i], 1, 0);
+ mAudioManager.setStreamVolume(stream, 1, 0);
if (mUseFixedVolume) {
- assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+ assertEquals(maxVolume, mAudioManager.getStreamVolume(stream));
continue;
}
- assertEquals(1, mAudioManager.getStreamVolume(streams[i]));
+ assertEquals(String.format("stream=%d", stream),
+ 1, mAudioManager.getStreamVolume(stream));
- if (streams[i] == AudioManager.STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) {
+ if (stream == AudioManager.STREAM_MUSIC && mAudioManager.isWiredHeadsetOn()) {
// due to new regulations, music sent over a wired headset may be volume limited
// until the user explicitly increases the limit, so we can't rely on being able
// to set the volume to getStreamMaxVolume(). Instead, determine the current limit
@@ -512,52 +512,52 @@
int prevvol = 0;
do {
prevvol = curvol;
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- curvol = mAudioManager.getStreamVolume(streams[i]);
+ mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
+ curvol = mAudioManager.getStreamVolume(stream);
} while (curvol != prevvol);
maxVolume = maxMusicVolume = curvol;
}
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.setStreamVolume(stream, maxVolume, 0);
+ mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
+ assertEquals(maxVolume, mAudioManager.getStreamVolume(stream));
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
- mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, streams[i], 0);
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
+ mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, stream, 0);
Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
- assertEquals(maxVolume - volumeDelta, mAudioManager.getStreamVolume(streams[i]));
+ assertEquals(maxVolume - volumeDelta, mAudioManager.getStreamVolume(stream));
// volume lower
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
+ mAudioManager.setStreamVolume(stream, maxVolume, 0);
+ volume = mAudioManager.getStreamVolume(stream);
while (volume > minVolume) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_LOWER, 0);
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
+ mAudioManager.adjustStreamVolume(stream, ADJUST_LOWER, 0);
assertEquals(Math.max(0, volume - volumeDelta),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
+ mAudioManager.getStreamVolume(stream));
+ volume = mAudioManager.getStreamVolume(stream);
}
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
+ mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0);
// volume raise
- mAudioManager.setStreamVolume(streams[i], 1, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
+ mAudioManager.setStreamVolume(stream, 1, 0);
+ volume = mAudioManager.getStreamVolume(stream);
while (volume < maxVolume) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
+ volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(stream));
+ mAudioManager.adjustStreamVolume(stream, ADJUST_RAISE, 0);
assertEquals(Math.min(volume + volumeDelta, maxVolume),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
+ mAudioManager.getStreamVolume(stream));
+ volume = mAudioManager.getStreamVolume(stream);
}
// volume same
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
+ mAudioManager.setStreamVolume(stream, maxVolume, 0);
for (int k = 0; k < maxVolume; k++) {
- mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
- assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
+ mAudioManager.adjustStreamVolume(stream, ADJUST_SAME, 0);
+ assertEquals(maxVolume, mAudioManager.getStreamVolume(stream));
}
- mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
+ mAudioManager.setStreamVolume(stream, maxVolume, 0);
}
if (mUseFixedVolume) {
@@ -660,18 +660,18 @@
AudioManager.STREAM_NOTIFICATION,
AudioManager.STREAM_SYSTEM};
if (mUseFixedVolume) {
- for (int i = 0; i < streams.length; i++) {
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+ for (int stream : streams) {
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertFalse("Muting should not affect a fixed volume device.",
- mAudioManager.isStreamMute(streams[i]));
+ mAudioManager.isStreamMute(stream));
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertFalse("Toggling mute should not affect a fixed volume device.",
- mAudioManager.isStreamMute(streams[i]));
+ mAudioManager.isStreamMute(stream));
- mAudioManager.setStreamMute(streams[i], true);
+ mAudioManager.setStreamMute(stream, true);
assertFalse("Muting should not affect a fixed volume device.",
- mAudioManager.isStreamMute(streams[i]));
+ mAudioManager.isStreamMute(stream));
}
}
}
@@ -689,16 +689,16 @@
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
// Verify streams cannot be unmuted without policy access.
- for (int i = 0; i < streams.length; i++) {
+ for (int stream : streams) {
try {
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE,
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE,
0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
@@ -706,7 +706,7 @@
}
try {
- mAudioManager.setStreamMute(streams[i], false);
+ mAudioManager.setStreamMute(stream, false);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_SILENT, mAudioManager.getRingerMode());
} catch (SecurityException e) {
@@ -717,37 +717,37 @@
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- for (int i = 0; i < streams.length; i++) {
+ for (int stream : streams) {
// ensure each stream is on and turned up.
- mAudioManager.setStreamVolume(streams[i],
- mAudioManager.getStreamMaxVolume(streams[i]),
+ mAudioManager.setStreamVolume(stream,
+ mAudioManager.getStreamMaxVolume(stream),
0);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
try {
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
mAudioManager.adjustStreamVolume(
- streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
try {
- mAudioManager.setStreamMute(streams[i], true);
+ mAudioManager.setStreamMute(stream, true);
assertEquals("Apps without Notification policy access can't change ringer mode",
RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
} catch (SecurityException e) {
}
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), true);
- testStreamMuting(streams[i]);
+ testStreamMuting(stream);
}
} finally {
Utils.toggleNotificationPolicyAccess(
@@ -780,25 +780,25 @@
mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
- for (int i = 0; i < streams.length; i++) {
+ for (int stream : streams) {
// ensure each stream is on and turned up.
- mAudioManager.setStreamVolume(streams[i],
- mAudioManager.getStreamMaxVolume(streams[i]),
+ mAudioManager.setStreamVolume(stream,
+ mAudioManager.getStreamMaxVolume(stream),
0);
- if (((1 << streams[i]) & muteAffectedStreams) == 0) {
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
- mAudioManager.isStreamMute(streams[i]));
- mAudioManager.setStreamMute(streams[i], true);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
- mAudioManager.isStreamMute(streams[i]));
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE,
+ if (((1 << stream) & muteAffectedStreams) == 0) {
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
+ assertFalse("Stream " + stream + " should not be affected by mute.",
+ mAudioManager.isStreamMute(stream));
+ mAudioManager.setStreamMute(stream, true);
+ assertFalse("Stream " + stream + " should not be affected by mute.",
+ mAudioManager.isStreamMute(stream));
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE,
0);
- assertFalse("Stream " + streams[i] + " should not be affected by mute.",
- mAudioManager.isStreamMute(streams[i]));
+ assertFalse("Stream " + stream + " should not be affected by mute.",
+ mAudioManager.isStreamMute(stream));
continue;
}
- testStreamMuting(streams[i]);
+ testStreamMuting(stream);
}
} finally {
Utils.toggleNotificationPolicyAccess(
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index 69f3ee8..5ea33ba 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -66,8 +66,10 @@
private static final int SLEEP_TIME_MS = 1000;
private static final int VIDEO_WIDTH_CENC = 1280;
private static final int VIDEO_HEIGHT_CENC = 720;
- private static final int VIDEO_WIDTH_WEBM = 320;
- private static final int VIDEO_HEIGHT_WEBM = 180;
+ private static final int VIDEO_WIDTH_WEBM = 352;
+ private static final int VIDEO_HEIGHT_WEBM = 288;
+ private static final int VIDEO_WIDTH_MPEG2TS = 320;
+ private static final int VIDEO_HEIGHT_MPEG2TS = 240;
private static final long PLAY_TIME_MS = TimeUnit.MILLISECONDS.convert(25, TimeUnit.SECONDS);
private static final String MIME_VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
private static final String MIME_VIDEO_VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
@@ -78,6 +80,10 @@
"http://yt-dash-mse-test.commondatastorage.googleapis.com/media/car_cenc-20120827-88.mp4");
private static final Uri WEBM_URL = Uri.parse(
"android.resource://android.media.cts/" + R.raw.video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz_crypt);
+ private static final Uri MPEG2TS_SCRAMBLED_URL = Uri.parse(
+ "android.resource://android.media.cts/" + R.raw.segment000001_scrambled);
+ private static final Uri MPEG2TS_CLEAR_URL = Uri.parse(
+ "android.resource://android.media.cts/" + R.raw.segment000001);
private static final UUID CLEARKEY_SCHEME_UUID =
new UUID(0x1077efecc0b24d02L, 0xace33c1e52e2fb4bL);
@@ -327,15 +333,20 @@
String initDataType, byte[][] clearKeys,
Uri audioUrl, boolean audioEncrypted,
Uri videoUrl, boolean videoEncrypted,
- int videoWidth, int videoHeight) throws Exception {
- MediaDrm drm = startDrm(clearKeys, initDataType);
- if (null == drm) {
- throw new Error("Failed to create drm.");
- }
+ int videoWidth, int videoHeight, boolean scrambled) throws Exception {
+ MediaDrm drm = null;
+ mSessionId = null;
+ if (!scrambled) {
+ drm = startDrm(clearKeys, initDataType);
+ if (null == drm) {
+ throw new Error("Failed to create drm.");
+ }
- if (!drm.isCryptoSchemeSupported(CLEARKEY_SCHEME_UUID)) {
- stopDrm(drm);
- throw new Error("Crypto scheme is not supported.");
+ if (!drm.isCryptoSchemeSupported(CLEARKEY_SCHEME_UUID)) {
+ stopDrm(drm);
+ throw new Error("Crypto scheme is not supported.");
+ }
+ mSessionId = openSession(drm);
}
if (!isResolutionSupported(videoMime, videoFeatures, videoWidth, videoHeight)) {
@@ -364,19 +375,19 @@
}
connectionStatus.testConnection(videoUrl);
- mSessionId = openSession(drm);
mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
getActivity().getSurfaceHolder(),
- mSessionId,
+ mSessionId, scrambled,
mContext.getResources());
mMediaCodecPlayer.setAudioDataSource(audioUrl, null, audioEncrypted);
mMediaCodecPlayer.setVideoDataSource(videoUrl, null, videoEncrypted);
mMediaCodecPlayer.start();
mMediaCodecPlayer.prepare();
- mDrmInitData = mMediaCodecPlayer.getDrmInitData();
-
- getKeys(mDrm, initDataType, mSessionId, mDrmInitData, clearKeys);
+ if (!scrambled) {
+ mDrmInitData = mMediaCodecPlayer.getDrmInitData();
+ getKeys(mDrm, initDataType, mSessionId, mDrmInitData, clearKeys);
+ }
// starts video playback
mMediaCodecPlayer.startThread();
@@ -392,8 +403,10 @@
Log.d(TAG, "playVideo player.reset()");
mMediaCodecPlayer.reset();
- closeSession(drm, mSessionId);
- stopDrm(drm);
+ if (!scrambled) {
+ closeSession(drm, mSessionId);
+ stopDrm(drm);
+ }
}
public void testClearKeyPlaybackCenc() throws Exception {
@@ -403,7 +416,7 @@
"cenc", new byte[][] { CLEAR_KEY_CENC },
CENC_AUDIO_URL, false,
CENC_VIDEO_URL, true,
- VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
+ VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false);
}
public void testClearKeyPlaybackWebm() throws Exception {
@@ -412,6 +425,24 @@
"webm", new byte[][] { CLEAR_KEY_WEBM },
WEBM_URL, true,
WEBM_URL, true,
- VIDEO_WIDTH_WEBM, VIDEO_WIDTH_WEBM);
+ VIDEO_WIDTH_WEBM, VIDEO_HEIGHT_WEBM, false);
+ }
+
+ public void testClearKeyPlaybackMpeg2ts() throws Exception {
+ testClearKeyPlayback(
+ MIME_VIDEO_AVC, new String[0],
+ "mpeg2ts", null,
+ MPEG2TS_SCRAMBLED_URL, false,
+ MPEG2TS_SCRAMBLED_URL, false,
+ VIDEO_WIDTH_MPEG2TS, VIDEO_HEIGHT_MPEG2TS, true);
+ }
+
+ public void testPlaybackMpeg2ts() throws Exception {
+ testClearKeyPlayback(
+ MIME_VIDEO_AVC, new String[0],
+ "mpeg2ts", null,
+ MPEG2TS_CLEAR_URL, false,
+ MPEG2TS_CLEAR_URL, false,
+ VIDEO_WIDTH_MPEG2TS, VIDEO_HEIGHT_MPEG2TS, false);
}
}
diff --git a/tests/tests/media/src/android/media/cts/CodecState.java b/tests/tests/media/src/android/media/cts/CodecState.java
index 51be918..12ebeae 100644
--- a/tests/tests/media/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/src/android/media/cts/CodecState.java
@@ -322,12 +322,10 @@
mSawOutputEOS = true;
- // We need to stop the audio track so that all audio frames are played
- // and the video codec can consume all of its data.
- // After audio track stop, getAudioTimeUs will return 0.
- if (mAudioTrack != null) {
- mAudioTrack.stop();
- }
+ // Do not stop audio track here. Video presentation may not finish
+ // yet, stopping the auido track now would result in getAudioTimeUs
+ // returning 0 and prevent video samples from being presented.
+ // We stop the audio track before the playback thread exits.
return false;
}
@@ -390,4 +388,10 @@
mAudioTrack.process();
}
}
+
+ public void stop() {
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 1d95463..253a5ab 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -19,11 +19,15 @@
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.DrmInitData;
+import android.media.MediaCas;
+import android.media.MediaCasException;
+import android.media.MediaCasException.UnsupportedCasException;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaCrypto;
import android.media.MediaCryptoException;
+import android.media.MediaDescrambler;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.net.Uri;
@@ -60,6 +64,7 @@
private boolean mEncryptedVideo;
private volatile boolean mThreadStarted = false;
private byte[] mSessionId;
+ private boolean mScrambled;
private CodecState mAudioTrackState;
private int mMediaFormatHeight;
private int mMediaFormatWidth;
@@ -72,6 +77,8 @@
private Map<String, String> mVideoHeaders;
private Map<UUID, byte[]> mPsshInitData;
private MediaCrypto mCrypto;
+ private MediaCas mMediaCas;
+ private MediaDescrambler mDescrambler;
private MediaExtractor mAudioExtractor;
private MediaExtractor mVideoExtractor;
private SurfaceHolder mSurfaceHolder;
@@ -91,6 +98,19 @@
"00000000" // Size of Data, must be zero
);
+ // ClearKey CAS/Descrambler test provision string
+ private static final String sProvisionStr =
+ "{ " +
+ " \"id\": 21140844, " +
+ " \"name\": \"Test Title\", " +
+ " \"lowercase_organization_name\": \"Android\", " +
+ " \"asset_key\": { " +
+ " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " +
+ " }, " +
+ " \"cas_type\": 1, " +
+ " \"track_types\": [ ] " +
+ "} " ;
+
/**
* Convert a hex string into byte array.
*/
@@ -108,8 +128,9 @@
* Media player class to stream CENC content using MediaCodec class.
*/
public MediaCodecClearKeyPlayer(
- SurfaceHolder holder, byte[] sessionId, Resources resources) {
+ SurfaceHolder holder, byte[] sessionId, boolean scrambled, Resources resources) {
mSessionId = sessionId;
+ mScrambled = scrambled;
mSurfaceHolder = holder;
mResources = resources;
mState = STATE_IDLE;
@@ -127,6 +148,9 @@
Log.d(TAG, "Thread interrupted");
}
}
+ if (mAudioTrackState != null) {
+ mAudioTrackState.stop();
+ }
}
});
}
@@ -206,6 +230,8 @@
private void prepareVideo() throws IOException {
boolean hasVideo = false;
+ android.media.DrmInitData drmInitData = mVideoExtractor.getDrmInitData();
+
for (int i = mVideoExtractor.getTrackCount(); i-- > 0;) {
MediaFormat format = mVideoExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
@@ -218,6 +244,14 @@
Log.d(TAG, "video track #" + i + " " + format + " " + mime +
" Width:" + mMediaFormatWidth + ", Height:" + mMediaFormatHeight);
+ if (mScrambled && drmInitData != null && mime.startsWith("video/")) {
+ android.media.DrmInitData.SchemeInitData schemeInitData =
+ drmInitData.get(new UUID(0, i));
+ if (schemeInitData != null) {
+ mDescrambler.setMediaCasSession(schemeInitData.data);
+ }
+ }
+
if (!hasVideo) {
mVideoExtractor.selectTrack(i);
addTrack(i, format, mEncryptedVideo);
@@ -239,11 +273,10 @@
}
}
}
- return;
}
private void setDataSource(MediaExtractor extractor, Uri uri, Map<String, String> headers)
- throws IOException {
+ throws IOException, MediaCasException {
String scheme = uri.getScheme();
if (scheme.startsWith("http")) {
extractor.setDataSource(uri.toString(), headers);
@@ -256,26 +289,30 @@
}
}
- public void prepare() throws IOException, MediaCryptoException {
- if (null == mAudioExtractor) {
- mAudioExtractor = new MediaExtractor();
- if (null == mAudioExtractor) {
- Log.e(TAG, "Cannot create Audio extractor.");
- return;
+ private void initCasAndDescrambler(MediaExtractor extractor) throws MediaCasException {
+ int trackCount = extractor.getTrackCount();
+ android.media.DrmInitData drmInitData = extractor.getDrmInitData();
+ for (int trackId = 0; trackId < trackCount; trackId++) {
+ android.media.MediaFormat format = extractor.getTrackFormat(trackId);
+ String mime = format.getString(android.media.MediaFormat.KEY_MIME);
+ Log.d(TAG, "track "+ trackId + ": " + mime);
+ if ("video/scrambled".equals(mime) || "audio/scrambled".equals(mime)) {
+ if (drmInitData == null) {
+ throw new IllegalArgumentException("found scrambled track without drmInitData!");
+ }
+ android.media.DrmInitData.SchemeInitData schemeInitData =
+ drmInitData.get(new UUID(0, trackId));
+ int CA_system_id = (schemeInitData.data[0] & 0xff)
+ | ((schemeInitData.data[1] & 0xff) << 8);
+ mMediaCas = new MediaCas(CA_system_id);
+ mDescrambler = new MediaDescrambler(CA_system_id);
+ mMediaCas.provision(sProvisionStr);
+ extractor.setMediaCas(mMediaCas);
}
}
+ }
- if (null == mVideoExtractor){
- mVideoExtractor = new MediaExtractor();
- if (null == mVideoExtractor) {
- Log.e(TAG, "Cannot create Video extractor.");
- return;
- }
- }
-
- setDataSource(mAudioExtractor, mAudioUri, mAudioHeaders);
- setDataSource(mVideoExtractor, mVideoUri, mVideoHeaders);
-
+ public void prepare() throws IOException, MediaCryptoException, MediaCasException {
if (null == mCrypto && (mEncryptedVideo || mEncryptedAudio)) {
try {
byte[] initData = new byte[0];
@@ -288,8 +325,29 @@
mCrypto.setMediaDrmSession(mSessionId);
} else {
reset();
- mCrypto.release();
- mCrypto = null;
+ }
+
+ if (null == mAudioExtractor) {
+ mAudioExtractor = new MediaExtractor();
+ if (null == mAudioExtractor) {
+ Log.e(TAG, "Cannot create Audio extractor.");
+ return;
+ }
+ }
+ setDataSource(mAudioExtractor, mAudioUri, mAudioHeaders);
+
+ if (mScrambled) {
+ initCasAndDescrambler(mAudioExtractor);
+ mVideoExtractor = mAudioExtractor;
+ } else {
+ if (null == mVideoExtractor){
+ mVideoExtractor = new MediaExtractor();
+ if (null == mVideoExtractor) {
+ Log.e(TAG, "Cannot create Video extractor.");
+ return;
+ }
+ }
+ setDataSource(mVideoExtractor, mVideoUri, mVideoHeaders);
}
if (null == mVideoCodecStates) {
@@ -325,11 +383,19 @@
codec = MediaCodec.createDecoderByType(mime);
}
- codec.configure(
- format,
- isVideo ? mSurfaceHolder.getSurface() : null,
- mCrypto,
- 0);
+ if (!mScrambled) {
+ codec.configure(
+ format,
+ isVideo ? mSurfaceHolder.getSurface() : null,
+ mCrypto,
+ 0);
+ } else {
+ codec.configure(
+ format,
+ isVideo ? mSurfaceHolder.getSurface() : null,
+ 0,
+ isVideo ? mDescrambler : null);
+ }
CodecState state;
if (isVideo) {
@@ -483,6 +549,16 @@
mCrypto = null;
}
+ if (mMediaCas != null) {
+ mMediaCas.release();
+ mMediaCas = null;
+ }
+
+ if (mDescrambler != null) {
+ mDescrambler.release();
+ mDescrambler = null;
+ }
+
mDurationUs = -1;
mState = STATE_IDLE;
}
diff --git a/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
new file mode 100644
index 0000000..59c2e8e
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/NativeClearKeySystemTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import android.net.Uri;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import com.android.compatibility.common.util.MediaUtils;
+import com.google.android.collect.Lists;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.UUID;
+
+/**
+ * Tests MediaDrm NDK APIs. ClearKey system uses a subset of NDK APIs,
+ * this test only tests the APIs that are supported by ClearKey system.
+ */
+public class NativeClearKeySystemTest extends MediaPlayerTestBase {
+ private static final String TAG = NativeClearKeySystemTest.class.getSimpleName();
+
+ private static final int CONNECTION_RETRIES = 10;
+ private static final int VIDEO_WIDTH_CENC = 1280;
+ private static final int VIDEO_HEIGHT_CENC = 720;
+ private static final String ISO_BMFF_VIDEO_MIME_TYPE = "video/avc";
+ private static final String ISO_BMFF_AUDIO_MIME_TYPE = "audio/avc";
+ private static final Uri CENC_AUDIO_URL = Uri.parse(
+ "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
+ "car_cenc-20120827-8c.mp4");
+ private static final Uri CENC_CLEARKEY_VIDEO_URL = Uri.parse(
+ "http://yt-dash-mse-test.commondatastorage.googleapis.com/media/" +
+ "car_cenc-20120827-88.mp4");
+
+ private static final int UUID_BYTE_SIZE = 16;
+ private static final UUID CLEARKEY_SCHEME_UUID =
+ new UUID(0x1077efecc0b24d02L, 0xace33c1e52e2fb4bL);
+ private static final UUID BAD_SCHEME_UUID =
+ new UUID(0xffffffffffffffffL, 0xffffffffffffffffL);
+ private MediaCodecClearKeyPlayer mMediaCodecPlayer;
+
+ static {
+ try {
+ System.loadLibrary("ctsmediadrm_jni");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "NativeClearKeySystemTest: Error loading JNI library");
+ e.printStackTrace();
+ }
+ try {
+ System.loadLibrary("mediandk");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "NativeClearKeySystemTest: Error loading JNI library");
+ e.printStackTrace();
+ }
+ }
+
+ public static class PlaybackParams {
+ public Surface surface;
+ public String mimeType;
+ public String audioUrl;
+ public String videoUrl;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (false == deviceHasMediaDrm()) {
+ tearDown();
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private boolean deviceHasMediaDrm() {
+ // ClearKey is introduced after KitKat.
+ if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT) {
+ Log.i(TAG, "This test is designed to work after Android KitKat.");
+ return false;
+ }
+ return true;
+ }
+
+ private static final byte[] uuidByteArray(UUID uuid) {
+ ByteBuffer buffer = ByteBuffer.wrap(new byte[UUID_BYTE_SIZE]);
+ buffer.putLong(uuid.getMostSignificantBits());
+ buffer.putLong(uuid.getLeastSignificantBits());
+ return buffer.array();
+ }
+
+ public void testIsCryptoSchemeSupported() throws Exception {
+ assertTrue(isCryptoSchemeSupportedNative(uuidByteArray(CLEARKEY_SCHEME_UUID)));
+ }
+
+ public void testIsCryptoSchemeNotSupported() throws Exception {
+ assertFalse(isCryptoSchemeSupportedNative(uuidByteArray(BAD_SCHEME_UUID)));
+ }
+
+ public void testPssh() throws Exception {
+ assertTrue(testPsshNative(uuidByteArray(CLEARKEY_SCHEME_UUID),
+ CENC_CLEARKEY_VIDEO_URL.toString()));
+ }
+
+ public void testGetPropertyString() throws Exception {
+ StringBuffer value = new StringBuffer();
+ testGetPropertyStringNative(uuidByteArray(CLEARKEY_SCHEME_UUID), "description", value);
+ assertEquals("ClearKey CDM", value.toString());
+ }
+
+ public void testUnknownPropertyString() throws Exception {
+ try {
+ StringBuffer value = new StringBuffer();
+ testGetPropertyStringNative(uuidByteArray(CLEARKEY_SCHEME_UUID),
+ "unknown-property", value);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "testUnknownPropertyString error = '" + e.getMessage() + "'");
+ assertThat(e.getMessage(), containsString("get property string returns"));
+ }
+ }
+
+ /**
+ * Tests native clear key system playback.
+ */
+ private void testClearKeyPlayback(
+ String mimeType, /*String initDataType,*/ Uri audioUrl, Uri videoUrl,
+ int videoWidth, int videoHeight) throws Exception {
+
+ if (!isCryptoSchemeSupportedNative(uuidByteArray(CLEARKEY_SCHEME_UUID))) {
+ throw new Error("Crypto scheme is not supported.");
+ }
+
+ IConnectionStatus connectionStatus = new ConnectionStatus(mContext);
+ if (!connectionStatus.isAvailable()) {
+ throw new Error("Network is not available, reason: " +
+ connectionStatus.getNotConnectedReason());
+ }
+
+ // If device is not online, recheck the status a few times.
+ int retries = 0;
+ while (!connectionStatus.isConnected()) {
+ if (retries++ >= CONNECTION_RETRIES) {
+ throw new Error("Device is not online, reason: " +
+ connectionStatus.getNotConnectedReason());
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ connectionStatus.testConnection(videoUrl);
+
+ if (!MediaUtils.checkCodecsForPath(mContext, videoUrl.getPath())) {
+ Log.i(TAG, "Device does not support " +
+ videoWidth + "x" + videoHeight + " resolution for " + mimeType);
+ return; // skip
+ }
+
+ PlaybackParams params = new PlaybackParams();
+ params.surface = mActivity.getSurfaceHolder().getSurface();
+ params.mimeType = mimeType;
+ params.audioUrl = audioUrl.toString();
+ params.videoUrl = videoUrl.toString();
+
+ if (!testClearKeyPlaybackNative(
+ uuidByteArray(CLEARKEY_SCHEME_UUID), params)) {
+ Log.e(TAG, "Fails play back using native media drm APIs.");
+ }
+ params.surface.release();
+ }
+
+ private ArrayList<Integer> intVersion(String version) {
+ String versions[] = version.split("\\.");
+
+ ArrayList<Integer> versionNumbers = Lists.newArrayList();
+ for (String subVersion : versions) {
+ versionNumbers.add(Integer.parseInt(subVersion));
+ }
+ return versionNumbers;
+ }
+
+ private static native boolean isCryptoSchemeSupportedNative(final byte[] uuid);
+
+ private static native boolean testClearKeyPlaybackNative(final byte[] uuid,
+ PlaybackParams params);
+
+ private static native boolean testGetPropertyStringNative(final byte[] uuid,
+ final String name, StringBuffer value);
+
+ private static native boolean testPsshNative(final byte[] uuid, final String videoUrl);
+
+ public void testClearKeyPlaybackCenc() throws Exception {
+ testClearKeyPlayback(
+ ISO_BMFF_VIDEO_MIME_TYPE,
+ CENC_AUDIO_URL,
+ CENC_CLEARKEY_VIDEO_URL,
+ VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
+ }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index f226e12..4e6b9ea 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -913,7 +913,7 @@
android:permissionGroup="android.permission-group.PHONE"
android:label="@string/permlab_answerPhoneCalls"
android:description="@string/permdesc_answerPhoneCalls"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="dangerous|runtime" />
<!-- ====================================================================== -->
@@ -3464,7 +3464,7 @@
android:theme="@style/Theme.NoDisplay"
android:excludeFromRecents="true">
<intent-filter>
- <action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
+ <action android:name="com.android.internal.intent.action.REQUEST_SHUTDOWN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 58611a3..577bb92 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -106,7 +106,7 @@
// OEMs cannot define permissions in the platform namespace
for (String permission : declaredPermissionsMap.keySet()) {
- assertFalse("Cannot define permission in android namespace",
+ assertFalse("Cannot define permission in android namespace:" + permission,
permission.startsWith(PLATFORM_ROOT_NAMESPACE));
}
@@ -207,6 +207,9 @@
case "ephemeral": {
protectionLevel |= PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
} break;
+ case "runtime": {
+ protectionLevel |= PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY;
+ } break;
}
}
return protectionLevel;
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index 9d00124..4b915da 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -38,6 +38,6 @@
LOCAL_PACKAGE_NAME := CtsUiRenderingTestCases
# uncomment when dalvik.annotation.Test* are removed or part of SDK
-#LOCAL_SDK_VERSION := current
+#LOCAL_SDK_VERSION := test_current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/uirendering/res/layout/simple_white_layout.xml b/tests/tests/uirendering/res/layout/simple_white_layout.xml
new file mode 100644
index 0000000..43a10f5
--- /dev/null
+++ b/tests/tests/uirendering/res/layout/simple_white_layout.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/test_width"
+ android:layout_height="@dimen/test_height"
+ android:background="@android:color/white"/>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
new file mode 100644
index 0000000..e3d56ba
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.support.test.filters.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+
+import org.junit.Test;
+
+@MediumTest
+public class AutofillHighlightTests extends ActivityTestBase {
+ @Test
+ public void testHighlightedFrameLayout() {
+ Bitmap goldenBitmap = Bitmap.createBitmap(ActivityTestBase.TEST_WIDTH,
+ ActivityTestBase.TEST_HEIGHT, Bitmap.Config.ARGB_8888);
+ goldenBitmap.eraseColor(Color.WHITE);
+ Canvas canvas = new Canvas(goldenBitmap);
+
+ Drawable autofilledDrawable = getActivity().getDrawable(
+ android.R.drawable.autofilled_highlight);
+ autofilledDrawable.setBounds(0, 0, ActivityTestBase.TEST_WIDTH,
+ ActivityTestBase.TEST_HEIGHT);
+ autofilledDrawable.draw(canvas);
+
+ createTest().addLayout(R.layout.simple_white_layout, view -> view.setAutofilled(true))
+ .runWithVerifier(new GoldenImageVerifier(goldenBitmap, new MSSIMComparer(0.99)));
+ }
+}
+
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
index f66f5f4..c5aa1b3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
@@ -81,7 +81,7 @@
new Point[] {
point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
},
- new int[] { 0xff75fb4c, 0xff75fb4c, 0xff75fb4c, 0xffffffff, 0xffba7d26 }
+ new int[] { 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xffffffff, 0xff7f7f00 }
));
}
@@ -114,7 +114,7 @@
new Point[] {
point(0, 0), point(48, 0), point(32, 40), point(0, 40), point(0, 56)
},
- new int[] { 0xffc07f2c, 0xffc07f2c, 0xffc07f2c, 0xffffffff, 0xffe03f16 }
+ new int[] { 0xffff7f00, 0xffff7f00, 0xffff7f00, 0xffffffff, 0xffff3f00 }
));
}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 03b8994..ca39aab 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -73,7 +73,6 @@
import android.util.Xml;
import android.view.ActionMode;
import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
@@ -1089,7 +1088,7 @@
assertTrue(view.hasCalledOnCreateContextMenu());
assertTrue(mMockParent.hasCreateContextMenu());
verify(listener, times(1)).onCreateContextMenu(
- eq(contextMenu), eq(view), any(ContextMenuInfo.class));
+ eq(contextMenu), eq(view), any());
}
@Test(expected=NullPointerException.class)
diff --git a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index f7fc033..4e33156 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -270,7 +270,7 @@
verifyZeroInteractions(mockClickListener);
assertTrue(mAdapterView.performItemClick(null, 0, 0));
- verify(mockClickListener, times(1)).onItemClick(eq(mAdapterView), any(View.class),
+ verify(mockClickListener, times(1)).onItemClick(eq(mAdapterView), any(),
eq(0), eq(0L));
setArrayAdapter(mAdapterView);
diff --git a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
index 84c60c8..7595c98 100644
--- a/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ArrayAdapterTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.database.DataSetObserver;
import android.support.test.annotation.UiThreadTest;
@@ -411,7 +412,7 @@
ArrayAdapter.createFromResource(null, R.array.string, R.layout.simple_spinner_item);
}
- @Test(expected=NullPointerException.class)
+ @Test(expected=Resources.NotFoundException.class)
public void testCreateFromResourceWithInvalidId() {
ArrayAdapter.createFromResource(mContext, INVALID_ID, R.layout.simple_spinner_item);
}
diff --git a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
index 796073f..1482cae 100644
--- a/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ExpandableListViewTest.java
@@ -164,7 +164,7 @@
mExpandableListView.setOnItemClickListener(mockOnItemClickListener);
assertTrue(mExpandableListView.performItemClick(null, 100, 99));
verify(mockOnItemClickListener, times(1)).onItemClick(eq(mExpandableListView),
- any(View.class), eq(100), eq(99L));
+ any(), eq(100), eq(99L));
}
@Test
@@ -309,7 +309,7 @@
mExpandableListView.performItemClick(null, 0, 0);
verify(mockOnGroupClickListener, times(1)).onGroupClick(eq(mExpandableListView),
- any(View.class), eq(0), eq(0L));
+ any(), eq(0), eq(0L));
}
@UiThreadTest
@@ -328,7 +328,7 @@
// click on the child list of the first group
mExpandableListView.performItemClick(null, 1, 0);
verify(mockOnChildClickListener, times(1)).onChildClick(eq(mExpandableListView),
- any(View.class), eq(0), eq(0), eq(0L));
+ any(), eq(0), eq(0), eq(0L));
}
@UiThreadTest
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 86f2fe3..15249c3 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -121,5 +121,5 @@
JAR_PATH=${JAR_PATH}:$j
done
-java $RDBG_FLAG -XX:+HeapDumpOnOutOfMemoryError -cp ${JAR_PATH} -DCTS_ROOT=${CTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
+java $RDBG_FLAG -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -cp ${JAR_PATH} -DCTS_ROOT=${CTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
diff --git a/tools/cts-tradefed/res/config/cts-vendor-interface.xml b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
index 5f38264..582cebf 100644
--- a/tools/cts-tradefed/res/config/cts-vendor-interface.xml
+++ b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
@@ -48,6 +48,7 @@
<option name="compatibility:include-filter" value="CtsPrintTestCases" />
<option name="compatibility:include-filter" value="CtsProviderTestCases" />
<option name="compatibility:include-filter" value="CtsRsBlasTestCases" />
+ <option name="compatibility:include-filter" value="CtsSecurityHostTestCases" />
<option name="compatibility:include-filter" value="CtsSecurityTestCases" />
<option name="compatibility:include-filter" value="CtsSensorTestCases" />
<option name="compatibility:include-filter" value="CtsShortcutHostTestCases" />
diff --git a/tools/selinux/SELinuxNeverallowTestGen.py b/tools/selinux/SELinuxNeverallowTestGen.py
index bc775d6..6194e2d 100755
--- a/tools/selinux/SELinuxNeverallowTestGen.py
+++ b/tools/selinux/SELinuxNeverallowTestGen.py
@@ -16,7 +16,7 @@
# remove comments
no_comments = re.sub(r'#.+?$', r'', policy_str, flags = re.M)
# match neverallow rules
- return re.findall(r'(^neverallow\s.+?;)', no_comments, flags = re.M |re.S);
+ return re.findall(r'^\s*(neverallow\s.+?;)', no_comments, flags = re.M |re.S);
# neverallow_rule_to_test - takes a neverallow statement and transforms it into
# the output necessary to form a cts unit test in a java source file.