Merge "Relax timeouts to deflake"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4ee6926..b20e8a6 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1724,6 +1724,11 @@
<string name="aware_status_lifecycle_failed">Discovery lifecycle FAILURE!</string>
<string name="aware_status_lifecycle_ok">Discovery lifecycle validated!</string>
+ <string name="aware_status_socket_failure">Failure on socket connection setup!</string>
+ <string name="aware_status_socket_server_socket_started">ServerSocket started on port %1$d!</string>
+ <string name="aware_status_socket_server_info_rx">Peer server info: IPv6=%1$s @ port=%2$d!</string>
+ <string name="aware_status_socket_server_message_from_peer">Message from peer: \'%1$s\'</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>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
index b1bd228..68c741e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
@@ -124,6 +124,7 @@
*/
public static class NetworkCb extends ConnectivityManager.NetworkCallback {
private CountDownLatch mBlocker = new CountDownLatch(1);
+ private Network mNetwork = null;
private NetworkCapabilities mNetworkCapabilities = null;
@Override
@@ -135,18 +136,20 @@
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {
+ mNetwork = network;
mNetworkCapabilities = networkCapabilities;
mBlocker.countDown();
}
/**
- * Wait (blocks) for Available or Unavailable callbacks - or timesout.
+ * Wait (blocks) for Capabilities Changed callback - or timesout.
*
- * @return true if Available, false otherwise (Unavailable or timeout).
+ * @return Network + NetworkCapabilities (pair) if occurred, null otherwise.
*/
- public NetworkCapabilities waitForNetwork() throws InterruptedException {
+ public Pair<Network, NetworkCapabilities> waitForNetworkCapabilities()
+ throws InterruptedException {
if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
- return mNetworkCapabilities;
+ return Pair.create(mNetwork, mNetworkCapabilities);
}
return null;
}
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 2f9bf4c..c5175c4 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
@@ -20,13 +20,23 @@
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.wifi.aware.WifiAwareManager;
+import android.net.wifi.aware.WifiAwareNetworkInfo;
import android.util.Log;
+import android.util.Pair;
import com.android.cts.verifier.R;
import com.android.cts.verifier.wifiaware.CallbackUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Inet6Address;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.util.Arrays;
/**
@@ -44,7 +54,9 @@
* 5. Wait for rx message
* 6. Request network
* Wait for network
- * 7. Destroy session
+ * 7. Create socket and bind to server
+ * 8. Send/receive data to validate connection
+ * 9. Destroy session
*
* Publish test sequence:
* 1. Attach
@@ -52,11 +64,13 @@
* 2. Publish
* wait for results (publish session)
* 3. Wait for rx message
- * 4. Request network
- * 5. Send message
+ * 4. Start a ServerSocket
+ * 5. Request network
+ * 6. Send message
* Wait for success
- * 6. Wait for network
- * 7. Destroy session
+ * 7. Wait for network
+ * 8. Receive/Send data to validate connection
+ * 9. Destroy session
*/
public class DataPathInBandTestCase extends DiscoveryBaseTestCase {
private static final String TAG = "DataPathInBandTestCase";
@@ -65,8 +79,14 @@
private static final byte[] MSG_PUB_TO_SUB = "Ready".getBytes();
private static final String PASSPHRASE = "Some super secret password";
+ private static final byte[] MSG_CLIENT_TO_SERVER = "GET SOME BYTES".getBytes();
+ private static final byte[] MSG_SERVER_TO_CLIENT = "PUT SOME OTHER BYTES".getBytes();
+
private boolean mIsSecurityOpen;
private boolean mIsPublish;
+ private Thread mClientServerThread;
+ private ConnectivityManager mCm;
+ private CallbackUtils.NetworkCb mNetworkCb;
public DataPathInBandTestCase(Context context, boolean isSecurityOpen, boolean isPublish,
boolean isUnsolicited) {
@@ -84,6 +104,10 @@
+ ", mIsUnsolicited=" + mIsUnsolicited);
}
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mClientServerThread = null;
+ mNetworkCb = null;
+
boolean success;
if (mIsPublish) {
success = executeTestPublisher();
@@ -102,6 +126,18 @@
return true;
}
+ @Override
+ protected void tearDown() {
+ if (mClientServerThread != null) {
+ mClientServerThread.interrupt();
+ }
+ if (mNetworkCb != null) {
+ mCm.unregisterNetworkCallback(mNetworkCb);
+ }
+ super.tearDown();
+ }
+
+
private boolean executeTestSubscriber() throws InterruptedException {
if (DBG) Log.d(TAG, "executeTestSubscriber");
if (!executeSubscribe()) {
@@ -129,33 +165,118 @@
}
// 6. request network
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+ new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+ mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+ if (!mIsSecurityOpen) {
+ nsBuilder.setPskPassphrase(PASSPHRASE);
+ }
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
- : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
- PASSPHRASE)).build();
- CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
- cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+ nsBuilder.build()).build();
+ mNetworkCb = new CallbackUtils.NetworkCb();
+ mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
mListener.onTestMsgReceived(
mContext.getString(R.string.aware_status_network_requested));
if (DBG) Log.d(TAG, "executeTestSubscriber: requested network");
- NetworkCapabilities nc = networkCb.waitForNetwork();
- cm.unregisterNetworkCallback(networkCb);
- if (nc == null) {
+
+ // 7. wait for network
+ Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+ if (info == null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
- Log.e(TAG, "executeTestSubscriber: network request rejected - ON_UNAVAILABLE");
+ Log.e(TAG, "executeTestSubscriber: network request rejected or timed-out");
return false;
}
- if (nc.getNetworkSpecifier() != null) {
+ if (info.first == null || info.second == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestSubscriber: received a null Network or NetworkCapabilities!?");
+ return false;
+ }
+ if (info.second.getNetworkSpecifier() != null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
return false;
}
+
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
if (DBG) Log.d(TAG, "executeTestSubscriber: network request granted - AVAILABLE");
+ if (!mIsSecurityOpen) {
+ if (!(info.second.getTransportInfo() instanceof WifiAwareNetworkInfo)) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestSubscriber: did not get WifiAwareNetworkInfo from peer!?");
+ return false;
+ }
+ WifiAwareNetworkInfo peerAwareInfo =
+ (WifiAwareNetworkInfo) info.second.getTransportInfo();
+ Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
+ int peerPort = peerAwareInfo.getPort();
+ int peerTransportProtocol = peerAwareInfo.getTransportProtocol();
+ mListener.onTestMsgReceived(
+ mContext.getString(R.string.aware_status_socket_server_info_rx,
+ peerIpv6.toString(),
+ peerPort));
+ if (DBG) {
+ Log.d(TAG,
+ "executeTestPublisher: rx peer info IPv6=" + peerIpv6 + ", port=" + peerPort
+ + ", transportProtocol=" + peerTransportProtocol);
+ }
+ if (peerTransportProtocol != 6) { // 6 == TCP: hard coded at peer
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestSubscriber: Got incorrect transport protocol from peer");
+ return false;
+ }
+ if (peerPort <= 0) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestSubscriber: Got invalid port from peer (<=0)");
+ return false;
+ }
+
+ // 8. send/receive - can happen inline here - no need for another thread
+ String currentMethod = "";
+ try {
+ currentMethod = "createSocket";
+ Socket socket = info.first.getSocketFactory().createSocket(peerIpv6, peerPort);
+
+ // simple interaction: write X bytes, read Y bytes
+ currentMethod = "getOutputStream()";
+ OutputStream os = socket.getOutputStream();
+ currentMethod = "write()";
+ os.write(MSG_CLIENT_TO_SERVER, 0, MSG_CLIENT_TO_SERVER.length);
+
+ byte[] buffer = new byte[1024];
+ currentMethod = "getInputStream()";
+ InputStream is = socket.getInputStream();
+ currentMethod = "read()";
+ int numBytes = is.read(buffer, 0, MSG_SERVER_TO_CLIENT.length);
+
+ mListener.onTestMsgReceived(
+ mContext.getString(R.string.aware_status_socket_server_message_from_peer,
+ new String(buffer, 0, numBytes)));
+
+ if (numBytes != MSG_SERVER_TO_CLIENT.length) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG,
+ "executeTestSubscriber: didn't read expected number of bytes - only "
+ + "got -- " + numBytes);
+ return false;
+ }
+ if (!Arrays.equals(MSG_SERVER_TO_CLIENT,
+ Arrays.copyOf(buffer, MSG_SERVER_TO_CLIENT.length))) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG, "executeTestSubscriber: did not get expected message from server.");
+ return false;
+ }
+
+ currentMethod = "close()";
+ os.close();
+ } catch (IOException e) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG, "executeTestSubscriber: failure while executing " + currentMethod);
+ return false;
+ }
+ }
+
return true;
}
@@ -165,21 +286,90 @@
return false;
}
- // 4. Request network
- ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
+ // 4. create a ServerSocket
+ int port = 0;
+ if (!mIsSecurityOpen) {
+ ServerSocket server;
+ try {
+ server = new ServerSocket(0);
+ } catch (IOException e) {
+ setFailureReason(
+ mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG, "executeTestPublisher: failure creating a ServerSocket -- " + e);
+ return false;
+ }
+ port = server.getLocalPort();
+ mListener.onTestMsgReceived(
+ mContext.getString(R.string.aware_status_socket_server_socket_started, port));
+ if (DBG) Log.d(TAG, "executeTestPublisher: server socket started on port=" + port);
+
+ // accept connections on the server socket - has to be done in a separate thread!
+ mClientServerThread = new Thread(() -> {
+ String currentMethod = "";
+
+ try {
+ currentMethod = "accept()";
+ Socket socket = server.accept();
+ currentMethod = "getInputStream()";
+ InputStream is = socket.getInputStream();
+
+ // simple interaction: read X bytes, write Y bytes
+ byte[] buffer = new byte[1024];
+ currentMethod = "read()";
+ int numBytes = is.read(buffer, 0, MSG_CLIENT_TO_SERVER.length);
+
+ mListener.onTestMsgReceived(mContext.getString(
+ R.string.aware_status_socket_server_message_from_peer,
+ new String(buffer, 0, numBytes)));
+
+ if (numBytes != MSG_CLIENT_TO_SERVER.length) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG,
+ "executeTestPublisher: didn't read expected number of bytes - only "
+ + "got -- " + numBytes);
+ return;
+ }
+ if (!Arrays.equals(MSG_CLIENT_TO_SERVER,
+ Arrays.copyOf(buffer, MSG_CLIENT_TO_SERVER.length))) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG,
+ "executeTestPublisher: did not get expected message from client.");
+ return;
+ }
+
+ currentMethod = "getOutputStream()";
+ OutputStream os = socket.getOutputStream();
+ currentMethod = "write()";
+ os.write(MSG_SERVER_TO_CLIENT, 0, MSG_SERVER_TO_CLIENT.length);
+ currentMethod = "close()";
+ os.close();
+ } catch (IOException e) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG, "executeTestPublisher: failure while executing " + currentMethod);
+ return;
+ }
+ });
+ mClientServerThread.start();
+ }
+
+ // 5. Request network
+ WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+ new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+ mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+ if (!mIsSecurityOpen) {
+ nsBuilder.setPskPassphrase(PASSPHRASE).setPort(port).setTransportProtocol(
+ 6); // 6 == TCP
+ }
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
- mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
- : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
- PASSPHRASE)).build();
- CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
- cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+ nsBuilder.build()).build();
+ mNetworkCb = new CallbackUtils.NetworkCb();
+ mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
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
+ // 6. send message & wait for send status
mWifiAwareDiscoverySession.sendMessage(mPeerHandle, MESSAGE_ID, MSG_PUB_TO_SUB);
CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
@@ -204,15 +394,19 @@
return false;
}
- // 6. wait for network
- NetworkCapabilities nc = networkCb.waitForNetwork();
- cm.unregisterNetworkCallback(networkCb);
- if (nc == null) {
+ // 7. wait for network
+ Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+ if (info == null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
Log.e(TAG, "executeTestPublisher: request network rejected - ON_UNAVAILABLE");
return false;
}
- if (nc.getNetworkSpecifier() != null) {
+ if (info.first == null || info.second == null) {
+ setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+ Log.e(TAG, "executeTestPublisher: received a null Network or NetworkCapabilities!?");
+ return false;
+ }
+ if (info.second.getNetworkSpecifier() != null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
return false;
@@ -220,6 +414,18 @@
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
if (DBG) Log.d(TAG, "executeTestPublisher: network request granted - AVAILABLE");
+ // 8. Send/Receive data to validate connection - happens on thread above
+ if (!mIsSecurityOpen) {
+ mClientServerThread.join(CALLBACK_TIMEOUT_SEC * 1000);
+ if (mClientServerThread.isAlive()) {
+ setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+ Log.e(TAG,
+ "executeTestPublisher: failure while waiting for client-server thread to "
+ + "finish");
+ return false;
+ }
+ }
+
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
index be198e1..0d6ca8f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.aware.DiscoverySession;
@@ -284,14 +285,14 @@
cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
if (DBG) Log.d(TAG, "executeTestResponder: requested network");
- NetworkCapabilities nc = networkCb.waitForNetwork();
+ Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
cm.unregisterNetworkCallback(networkCb);
- if (nc == null) {
+ if (info == null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
return false;
}
- if (nc.getNetworkSpecifier() != null) {
+ if (info.second.getNetworkSpecifier() != null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
return false;
@@ -423,14 +424,14 @@
cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
- NetworkCapabilities nc = networkCb.waitForNetwork();
+ Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
cm.unregisterNetworkCallback(networkCb);
- if (nc == null) {
+ if (info == null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed));
Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
return false;
}
- if (nc.getNetworkSpecifier() != null) {
+ if (info.second.getNetworkSpecifier() != null) {
setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
return false;
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
index bf5dc39..7500050 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
@@ -54,6 +54,8 @@
@Override
protected void tearDown() throws Exception {
+ Log.v(TAG, getClass().getSimpleName() + ".tearDown(): hasFeature=" + mHasFeature
+ + " receiver=" + mActivityDoneReceiver);
if (mHasFeature && mActivityDoneReceiver != null) {
try {
mContext.unregisterReceiver(mActivityDoneReceiver);
diff --git a/hostsidetests/appbinding/app/app1/AndroidManifest.xml b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
index b3b55e8..b2c49db 100644
--- a/hostsidetests/appbinding/app/app1/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
@@ -31,9 +31,9 @@
android:name=".MyService"
android:exported="true"
android:process=":persistent"
- android:permission="android.permission.BIND_SMS_APP_SERVICE">
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE">
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/app2/AndroidManifest.xml b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
index 7890c6f..7be1599 100644
--- a/hostsidetests/appbinding/app/app2/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
@@ -31,9 +31,9 @@
android:name=".MyService2"
android:exported="false"
android:process=":persistent"
- android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/app3/AndroidManifest.xml b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
index ec7a4bf..52080ee 100644
--- a/hostsidetests/appbinding/app/app3/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
@@ -32,7 +32,7 @@
android:exported="false"
android:process=":persistent">
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/app4/AndroidManifest.xml b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
index 5df5fa8..560c4c1 100644
--- a/hostsidetests/appbinding/app/app4/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
@@ -31,18 +31,18 @@
android:name=".MyService"
android:exported="true"
android:process=":persistent"
- android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
<service
android:name=".MyService2"
android:exported="true"
android:process=":persistent"
- android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/app6/AndroidManifest.xml b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
index abea148..cf704d7 100644
--- a/hostsidetests/appbinding/app/app6/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
@@ -30,9 +30,9 @@
<service
android:name=".MyService2"
android:exported="false"
- android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/appb/AndroidManifest.xml b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
index 3a1c5d3..e6336a6 100644
--- a/hostsidetests/appbinding/app/appb/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
@@ -31,9 +31,9 @@
android:name="com.android.cts.appbinding.app.MyService"
android:exported="true"
android:process=":persistent"
- android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+ android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
<intent-filter>
- <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+ <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
</intent-filter>
</service>
diff --git a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
index 5df2fa9..9a569f3 100644
--- a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
+++ b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
@@ -15,12 +15,12 @@
*/
package com.android.cts.appbinding.app;
-import android.app.SmsAppService;
+import android.service.carrier.CarrierMessagingClientService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public class MyService extends SmsAppService {
+public class MyService extends CarrierMessagingClientService {
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -31,6 +31,6 @@
return;
}
writer.print("Package=[" + getPackageName() + "]");
- writer.println("Class=[" + this.getClass().getName() + "]");
+ writer.println(" Class=[" + this.getClass().getName() + "]");
}
}
diff --git a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
index dd4c438..5c37e01 100644
--- a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
+++ b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
@@ -321,7 +321,7 @@
*/
public void testSimpleNotBound3() throws Throwable {
installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
- "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+ "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
}
/**
@@ -336,7 +336,7 @@
*/
public void testSimpleNotBound5() throws Throwable {
installAndCheckNotBound(APK_5, PACKAGE_A, USER_SYSTEM,
- "Service with android.telephony.action.SMS_APP_SERVICE not found");
+ "Service with android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE not found");
}
/**
@@ -355,7 +355,7 @@
installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
installAndCheckBound(APK_2, PACKAGE_A, SERVICE_2, USER_SYSTEM);
installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
- "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+ "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
installAndCheckNotBound(APK_4, PACKAGE_A, USER_SYSTEM, "More than one");
}
@@ -398,7 +398,7 @@
// Replace the app on the primary user with an invalid one.
installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
- "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+ "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
// Secondary user should still have a valid connection.
checkBound(PACKAGE_B, SERVICE_1, userId);
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
deleted file mode 100644
index 1adf0f8..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitApp
-
-# Tag this module as a cts test artifact
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
deleted file mode 100644
index f37be44..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureA
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS += --custom-package com.android.cts.classloadersplitapp.feature_a
-LOCAL_AAPT_FLAGS += --package-id 0x80
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
deleted file mode 100644
index 3262e15..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureB
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp CtsClassloaderSplitAppFeatureA
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS := --custom-package com.android.cts.classloadersplitapp.feature_b
-LOCAL_AAPT_FLAGS += --package-id 0x81
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
deleted file mode 100644
index df12f82..0000000
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-
-LOCAL_PACKAGE_NAME := CtsUsesLibraryApp
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/classloaders/splits/Android.bp b/hostsidetests/classloaders/splits/Android.bp
new file mode 100644
index 0000000..17f02a7
--- /dev/null
+++ b/hostsidetests/classloaders/splits/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+ name: "CtsClassloaderSplitsHostTestCases",
+ defaults: [ "cts_defaults" ],
+ srcs: [ "src/**/*.java" ],
+ libs: [
+ "compatibility-host-util",
+ "cts-tradefed",
+ "tradefed",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ required: [
+ "CtsClassloaderSplitApp",
+ "CtsClassloaderSplitAppFeatureA",
+ "CtsClassloaderSplitAppFeatureB",
+ ],
+}
diff --git a/hostsidetests/classloaders/splits/AndroidTest.xml b/hostsidetests/classloaders/splits/AndroidTest.xml
new file mode 100644
index 0000000..77b5bce
--- /dev/null
+++ b/hostsidetests/classloaders/splits/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for the CTS Classloader Splits host tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsClassloaderSplitsHostTestCases.jar" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/hostsidetests/classloaders/splits/TEST_MAPPING b/hostsidetests/classloaders/splits/TEST_MAPPING
new file mode 100644
index 0000000..18f00dd
--- /dev/null
+++ b/hostsidetests/classloaders/splits/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsClassloaderSplitsHostTestCases"
+ }
+ ]
+}
diff --git a/hostsidetests/classloaders/splits/apps/Android.bp b/hostsidetests/classloaders/splits/apps/Android.bp
new file mode 100644
index 0000000..ebd9318
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsClassloaderSplitApp",
+ defaults: [ "cts_support_defaults" ],
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "android-support-test",
+ "ctstestrunner",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/AndroidManifest.xml
diff --git a/hostsidetests/classloaders/splits/apps/feature_a/Android.bp b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
new file mode 100644
index 0000000..0fd7091
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "CtsClassloaderSplitAppFeatureA",
+ defaults: [ "cts_support_defaults" ],
+ sdk_version: "current",
+ srcs: [ "src/**/*.java" ],
+ libs: [ "CtsClassloaderSplitApp" ],
+ aaptflags: [
+ "--custom-package",
+ "com.android.cts.classloadersplitapp.feature_a",
+ "--package-id",
+ "0x80",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
diff --git a/hostsidetests/classloaders/splits/apps/feature_b/Android.bp b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
new file mode 100644
index 0000000..2643840
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "CtsClassloaderSplitAppFeatureB",
+ defaults: [ "cts_support_defaults" ],
+ sdk_version: "current",
+ srcs: [ "src/**/*.java" ],
+ libs: [
+ "CtsClassloaderSplitApp",
+ "CtsClassloaderSplitAppFeatureA",
+ ],
+ aaptflags: [
+ "--custom-package",
+ "com.android.cts.classloadersplitapp.feature_a",
+ "--package-id",
+ "0x81",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
diff --git a/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ * private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+ * public InstallMultiple() {
+ * super(getDevice(), null, null);
+ * }
+ * }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+ private final ITestDevice mDevice;
+ private final IBuildInfo mBuild;
+ private final IAbi mAbi;
+
+ private final List<String> mArgs = new ArrayList<>();
+ private final List<File> mApks = new ArrayList<>();
+ private boolean mUseNaturalAbi;
+
+ public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+ mDevice = device;
+ mBuild = buildInfo;
+ mAbi = abi;
+ addArg("-g");
+ }
+
+ T addArg(String arg) {
+ mArgs.add(arg);
+ return (T) this;
+ }
+
+ T addApk(String apk) throws FileNotFoundException {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ mApks.add(buildHelper.getTestFile(apk));
+ return (T) this;
+ }
+
+ T inheritFrom(String packageName) {
+ addArg("-r");
+ addArg("-p " + packageName);
+ return (T) this;
+ }
+
+ T useNaturalAbi() {
+ mUseNaturalAbi = true;
+ return (T) this;
+ }
+
+ T allowTest() {
+ addArg("-t");
+ return (T) this;
+ }
+
+ T locationAuto() {
+ addArg("--install-location 0");
+ return (T) this;
+ }
+
+ T locationInternalOnly() {
+ addArg("--install-location 1");
+ return (T) this;
+ }
+
+ T locationPreferExternal() {
+ addArg("--install-location 2");
+ return (T) this;
+ }
+
+ T forceUuid(String uuid) {
+ addArg("--force-uuid " + uuid);
+ return (T) this;
+ }
+
+ T forUser(int userId) {
+ addArg("--user " + userId);
+ return (T) this;
+ }
+
+ void run() throws DeviceNotAvailableException {
+ run(true, null);
+ }
+
+ void runExpectingFailure() throws DeviceNotAvailableException {
+ run(false, null);
+ }
+
+ void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+ run(false, failure);
+ }
+
+ private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+ final ITestDevice device = mDevice;
+
+ // Create an install session
+ final StringBuilder cmd = new StringBuilder();
+ cmd.append("pm install-create");
+ for (String arg : mArgs) {
+ cmd.append(' ').append(arg);
+ }
+ if (!mUseNaturalAbi && mAbi != null) {
+ cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+ }
+
+ String result = device.executeShellCommand(cmd.toString());
+ TestCase.assertTrue(result, result.startsWith("Success"));
+
+ final int start = result.lastIndexOf("[");
+ final int end = result.lastIndexOf("]");
+ int sessionId = -1;
+ try {
+ if (start != -1 && end != -1 && start < end) {
+ sessionId = Integer.parseInt(result.substring(start + 1, end));
+ }
+ } catch (NumberFormatException e) {
+ }
+ if (sessionId == -1) {
+ throw new IllegalStateException("Failed to create install session: " + result);
+ }
+
+ // Push our files into session. Ideally we'd use stdin streaming,
+ // but ddmlib doesn't support it yet.
+ for (int i = 0; i < mApks.size(); i++) {
+ final File apk = mApks.get(i);
+ final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+ if (!device.pushFile(apk, remotePath)) {
+ throw new IllegalStateException("Failed to push " + apk);
+ }
+
+ cmd.setLength(0);
+ cmd.append("pm install-write");
+ cmd.append(' ').append(sessionId);
+ cmd.append(' ').append(i + "_" + apk.getName());
+ cmd.append(' ').append(remotePath);
+
+ result = device.executeShellCommand(cmd.toString());
+ TestCase.assertTrue(result, result.startsWith("Success"));
+ }
+
+ // Everything staged; let's pull trigger
+ cmd.setLength(0);
+ cmd.append("pm install-commit");
+ cmd.append(' ').append(sessionId);
+
+ result = device.executeShellCommand(cmd.toString()).trim();
+ if (failure == null) {
+ if (expectingSuccess) {
+ TestCase.assertTrue(result, result.startsWith("Success"));
+ } else {
+ TestCase.assertFalse(result, result.startsWith("Success"));
+ }
+ } else {
+ TestCase.assertTrue(result, result.contains(failure));
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
similarity index 89%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
rename to hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
index 4e54bc4..1460bfc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
@@ -13,11 +13,12 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
-package android.appsecurity.cts;
+package android.classloaders.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
@@ -25,7 +26,7 @@
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class ClassloaderSplitsTest extends BaseAppSecurityTest {
+public class ClassloaderSplitsTest extends BaseHostJUnit4Test {
private static final String PKG = "com.android.cts.classloadersplitapp";
private static final String TEST_CLASS = PKG + ".SplitAppTest";
@@ -47,7 +48,6 @@
@Before
public void setUp() throws Exception {
- Utils.prepareSingleUser(getDevice());
getDevice().uninstallPackage(PKG);
}
@@ -116,4 +116,14 @@
runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
runDeviceTests(getDevice(), PKG, TEST_CLASS, "testAllReceivers");
}
+
+ protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+ public InstallMultiple() {
+ this(false);
+ }
+ public InstallMultiple(boolean instant) {
+ super(getDevice(), getBuild(), getAbi());
+ addArg(instant ? "--instant" : "");
+ }
+ }
}
diff --git a/hostsidetests/classloaders/useslibrary/Android.bp b/hostsidetests/classloaders/useslibrary/Android.bp
new file mode 100644
index 0000000..603b2ec
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+ name: "CtsUsesLibraryHostTestCases",
+ defaults: [ "cts_defaults" ],
+ srcs: [ "src/**/*.java" ],
+ libs: [
+ "compatibility-host-util",
+ "cts-tradefed",
+ "tradefed",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ required: [ "CtsUsesLibraryApp" ],
+}
diff --git a/hostsidetests/classloaders/useslibrary/AndroidTest.xml b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
new file mode 100644
index 0000000..b7796d7
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for the CTS UsesLibrary host tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="framework" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsUsesLibraryHostTestCases.jar" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/hostsidetests/classloaders/useslibrary/TEST_MAPPING b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
new file mode 100644
index 0000000..72ef61b
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsUsesLibraryHostTestCases"
+ }
+ ]
+}
diff --git a/hostsidetests/classloaders/useslibrary/app/Android.bp b/hostsidetests/classloaders/useslibrary/app/Android.bp
new file mode 100644
index 0000000..faf7a22
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/app/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "CtsUsesLibraryApp",
+ defaults: [ "cts_support_defaults" ],
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.base.stubs",
+ ],
+ static_libs: [
+ "android-support-test",
+ "ctstestrunner",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml b/hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
rename to hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
similarity index 95%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
rename to hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
index 73b820d..7fa8b20 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -16,11 +16,6 @@
package com.android.cts.useslibrary;
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import dalvik.system.BaseDexClassLoader;
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ * private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+ * public InstallMultiple() {
+ * super(getDevice(), null, null);
+ * }
+ * }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+ private final ITestDevice mDevice;
+ private final IBuildInfo mBuild;
+ private final IAbi mAbi;
+
+ private final List<String> mArgs = new ArrayList<>();
+ private final List<File> mApks = new ArrayList<>();
+ private boolean mUseNaturalAbi;
+
+ public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+ mDevice = device;
+ mBuild = buildInfo;
+ mAbi = abi;
+ addArg("-g");
+ }
+
+ T addArg(String arg) {
+ mArgs.add(arg);
+ return (T) this;
+ }
+
+ T addApk(String apk) throws FileNotFoundException {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ mApks.add(buildHelper.getTestFile(apk));
+ return (T) this;
+ }
+
+ T inheritFrom(String packageName) {
+ addArg("-r");
+ addArg("-p " + packageName);
+ return (T) this;
+ }
+
+ T useNaturalAbi() {
+ mUseNaturalAbi = true;
+ return (T) this;
+ }
+
+ T allowTest() {
+ addArg("-t");
+ return (T) this;
+ }
+
+ T locationAuto() {
+ addArg("--install-location 0");
+ return (T) this;
+ }
+
+ T locationInternalOnly() {
+ addArg("--install-location 1");
+ return (T) this;
+ }
+
+ T locationPreferExternal() {
+ addArg("--install-location 2");
+ return (T) this;
+ }
+
+ T forceUuid(String uuid) {
+ addArg("--force-uuid " + uuid);
+ return (T) this;
+ }
+
+ T forUser(int userId) {
+ addArg("--user " + userId);
+ return (T) this;
+ }
+
+ void run() throws DeviceNotAvailableException {
+ run(true, null);
+ }
+
+ void runExpectingFailure() throws DeviceNotAvailableException {
+ run(false, null);
+ }
+
+ void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+ run(false, failure);
+ }
+
+ private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+ final ITestDevice device = mDevice;
+
+ // Create an install session
+ final StringBuilder cmd = new StringBuilder();
+ cmd.append("pm install-create");
+ for (String arg : mArgs) {
+ cmd.append(' ').append(arg);
+ }
+ if (!mUseNaturalAbi && mAbi != null) {
+ cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+ }
+
+ String result = device.executeShellCommand(cmd.toString());
+ TestCase.assertTrue(result, result.startsWith("Success"));
+
+ final int start = result.lastIndexOf("[");
+ final int end = result.lastIndexOf("]");
+ int sessionId = -1;
+ try {
+ if (start != -1 && end != -1 && start < end) {
+ sessionId = Integer.parseInt(result.substring(start + 1, end));
+ }
+ } catch (NumberFormatException e) {
+ }
+ if (sessionId == -1) {
+ throw new IllegalStateException("Failed to create install session: " + result);
+ }
+
+ // Push our files into session. Ideally we'd use stdin streaming,
+ // but ddmlib doesn't support it yet.
+ for (int i = 0; i < mApks.size(); i++) {
+ final File apk = mApks.get(i);
+ final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+ if (!device.pushFile(apk, remotePath)) {
+ throw new IllegalStateException("Failed to push " + apk);
+ }
+
+ cmd.setLength(0);
+ cmd.append("pm install-write");
+ cmd.append(' ').append(sessionId);
+ cmd.append(' ').append(i + "_" + apk.getName());
+ cmd.append(' ').append(remotePath);
+
+ result = device.executeShellCommand(cmd.toString());
+ TestCase.assertTrue(result, result.startsWith("Success"));
+ }
+
+ // Everything staged; let's pull trigger
+ cmd.setLength(0);
+ cmd.append("pm install-commit");
+ cmd.append(' ').append(sessionId);
+
+ result = device.executeShellCommand(cmd.toString()).trim();
+ if (failure == null) {
+ if (expectingSuccess) {
+ TestCase.assertTrue(result, result.startsWith("Success"));
+ } else {
+ TestCase.assertFalse(result, result.startsWith("Success"));
+ }
+ } else {
+ TestCase.assertTrue(result, result.contains(failure));
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
similarity index 84%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
rename to hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
index 41ce7a1..aecd87b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package android.appsecurity.cts;
+package android.classloaders.cts;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
@@ -32,7 +33,7 @@
*/
@AppModeFull(reason = "TODO verify whether or not these should run in instant mode")
@RunWith(DeviceJUnit4ClassRunner.class)
-public class UsesLibraryHostTest extends BaseAppSecurityTest {
+public class UsesLibraryHostTest extends BaseHostJUnit4Test {
private static final String PKG = "com.android.cts.useslibrary";
private static final String APK = "CtsUsesLibraryApp.apk";
@@ -79,4 +80,14 @@
new InstallMultiple(instant).addApk(APK).run();
Utils.runDeviceTests(getDevice(), PKG, ".UsesLibraryTest", "testDuplicateLibrary");
}
+
+ protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+ public InstallMultiple() {
+ this(false);
+ }
+ public InstallMultiple(boolean instant) {
+ super(getDevice(), getBuild(), getAbi());
+ addArg(instant ? "--instant" : "");
+ }
+ }
}
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
new file mode 100644
index 0000000..48497d8
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 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.classloaders.cts;
+
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class Utils {
+ public static final int USER_SYSTEM = 0;
+
+ public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+ String testMethodName) throws DeviceNotAvailableException {
+ runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, null);
+ }
+
+ public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+ String testMethodName, Map<String, String> testArgs)
+ throws DeviceNotAvailableException {
+ runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, testArgs);
+ }
+
+ public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+ String testMethodName, int userId) throws DeviceNotAvailableException {
+ runDeviceTests(device, packageName, testClassName, testMethodName, userId, null);
+ }
+
+ public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+ String testMethodName, int userId, Map<String, String> testArgs)
+ throws DeviceNotAvailableException {
+ // 60 min timeout per test by default
+ runDeviceTests(device, packageName, testClassName, testMethodName, userId, testArgs,
+ 60L, TimeUnit.MINUTES);
+ }
+
+ public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+ String testMethodName, int userId, Map<String, String> testArgs, long timeout,
+ TimeUnit unit)
+ throws DeviceNotAvailableException {
+ if (testClassName != null && testClassName.startsWith(".")) {
+ testClassName = packageName + testClassName;
+ }
+ RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
+ "android.support.test.runner.AndroidJUnitRunner", device.getIDevice());
+ // timeout_msec is the timeout per test for instrumentation
+ testRunner.addInstrumentationArg("timeout_msec", Long.toString(unit.toMillis(timeout)));
+ if (testClassName != null && testMethodName != null) {
+ testRunner.setMethodName(testClassName, testMethodName);
+ } else if (testClassName != null) {
+ testRunner.setClassName(testClassName);
+ }
+
+ if (testArgs != null && testArgs.size() > 0) {
+ for (String name : testArgs.keySet()) {
+ final String value = testArgs.get(name);
+ testRunner.addInstrumentationArg(name, value);
+ }
+ }
+ final CollectingTestListener listener = new CollectingTestListener();
+ device.runInstrumentationTestsAsUser(testRunner, userId, listener);
+
+ final TestRunResult result = listener.getCurrentRunResults();
+ if (result.isRunFailure()) {
+ throw new AssertionError("Failed to successfully run device tests for "
+ + result.getName() + ": " + result.getRunFailureMessage());
+ }
+ if (result.getNumTests() == 0) {
+ throw new AssertionError("No tests were run on the device");
+ }
+ if (result.hasFailedTests()) {
+ // build a meaningful error message
+ StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+ for (Map.Entry<TestDescription, TestResult> resultEntry :
+ result.getTestResults().entrySet()) {
+ if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+ errorBuilder.append(resultEntry.getKey().toString());
+ errorBuilder.append(":\n");
+ errorBuilder.append(resultEntry.getValue().getStackTrace());
+ }
+ }
+ throw new AssertionError(errorBuilder.toString());
+ }
+ }
+
+ /**
+ * Prepare and return a single user relevant for testing.
+ */
+ public static int[] prepareSingleUser(ITestDevice device)
+ throws DeviceNotAvailableException {
+ return prepareMultipleUsers(device, 1);
+ }
+
+ /**
+ * Prepare and return two users relevant for testing.
+ */
+ public static int[] prepareMultipleUsers(ITestDevice device)
+ throws DeviceNotAvailableException {
+ return prepareMultipleUsers(device, 2);
+ }
+
+ /**
+ * Prepare and return multiple users relevant for testing.
+ */
+ public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers)
+ throws DeviceNotAvailableException {
+ final int[] userIds = getAllUsers(device);
+ for (int i = 1; i < userIds.length; i++) {
+ if (i < maxUsers) {
+ device.startUser(userIds[i]);
+ } else {
+ device.stopUser(userIds[i]);
+ }
+ }
+ if (userIds.length > maxUsers) {
+ return Arrays.copyOf(userIds, maxUsers);
+ } else {
+ return userIds;
+ }
+ }
+
+ public static int[] getAllUsers(ITestDevice device)
+ throws DeviceNotAvailableException {
+ Integer primary = device.getPrimaryUserId();
+ if (primary == null) {
+ primary = USER_SYSTEM;
+ }
+ int[] users = new int[] { primary };
+ for (Integer user : device.listUsers()) {
+ if ((user != USER_SYSTEM) && (user != primary)) {
+ users = Arrays.copyOf(users, users.length + 1);
+ users[users.length - 1] = user;
+ }
+ }
+ return users;
+ }
+}
diff --git a/hostsidetests/dexmetadata/host/Android.mk b/hostsidetests/dexmetadata/host/Android.mk
index a51ddd2..cae13cd 100644
--- a/hostsidetests/dexmetadata/host/Android.mk
+++ b/hostsidetests/dexmetadata/host/Android.mk
@@ -29,6 +29,6 @@
tradefed
# tag this module as test artifact for cts
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/dumpsys/AndroidTest.xml b/hostsidetests/dumpsys/AndroidTest.xml
index ead52be..11ab26f 100644
--- a/hostsidetests/dumpsys/AndroidTest.xml
+++ b/hostsidetests/dumpsys/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<!-- This module tests system service dumps, which is irrelevant for Instant Apps. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
<option name="jar" value="CtsDumpsysHostTestCases.jar" />
</test>
diff --git a/hostsidetests/edi/AndroidTest.xml b/hostsidetests/edi/AndroidTest.xml
index b0d5d9f..fdbe2cb 100644
--- a/hostsidetests/edi/AndroidTest.xml
+++ b/hostsidetests/edi/AndroidTest.xml
@@ -16,8 +16,8 @@
<configuration description="Config for CTS EDI host test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="deviceinfo" />
- <!-- Included not for instant-app but to collect the required information for the run -->
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <!-- Do no need to run instant mode for collecting information -->
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsEdiHostTestCases.jar" />
</test>
diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml
index 2f1c7f0..bc6ca74 100644
--- a/hostsidetests/shortcuts/hostside/AndroidTest.xml
+++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<!-- Instant apps can't access ShortcutManager -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="android.cts.backup.BackupPreparer">
<option name="enable-backup-if-needed" value="true" />
<option name="select-local-transport" value="true" />
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 9298ac2..349578f 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -861,6 +861,19 @@
}
}
+ public void testSetDefaultSmsApplication_failIfNotDeviceOwner() {
+ if (!mDeviceAdmin) {
+ Log.w(TAG, "Skipping testSetDefaultSmsApplication_failIfNotDeviceOwner");
+ return;
+ }
+ try {
+ mDevicePolicyManager.setDefaultSmsApplication(mComponent, "android.admin.cts");
+ fail("did not throw expected SecurityException");
+ } catch (SecurityException e) {
+ assertDeviceOwnerMessage(e.getMessage());
+ }
+ }
+
public void testCreateAdminSupportIntent_returnNullIfRestrictionIsNotSet() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testCreateAdminSupportIntent");
diff --git a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
index 38f0b52..fb0ccf2 100644
--- a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
@@ -55,10 +55,12 @@
public enum Source {
ACTIVITY,
ACTIVITY_CALLBACK,
+ ACTIVITY_CALLBACK_CREATE_ONLY,
APPLICATION_ACTIVITY_CALLBACK
}
private final Application.ActivityLifecycleCallbacks mActivityCallbacks;
+ private final Application.ActivityLifecycleCallbacks mActivityCallbacksCreateOnly;
private ArrayList<Pair<Source, Event>> mCollectedEvents = new ArrayList<>();
@@ -161,6 +163,101 @@
}
};
registerActivityLifecycleCallbacks(mActivityCallbacks);
+ mActivityCallbacksCreateOnly = new Application.ActivityLifecycleCallbacks() {
+
+ @Override
+ public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_CREATE);
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_CREATE);
+ }
+
+ @Override
+ public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_CREATE);
+ // We shouldn't get any additional callbacks after this point
+ unregisterActivityLifecycleCallbacks(this);
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_START);
+ }
+
+ @Override
+ public void onActivityPostStarted(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_START);
+ }
+
+ @Override
+ public void onActivityPreResumed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_RESUME);
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_RESUME);
+ }
+
+ @Override
+ public void onActivityPostResumed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_RESUME);
+ }
+
+ @Override
+ public void onActivityPrePaused(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_PAUSE);
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PAUSE);
+ }
+
+ @Override
+ public void onActivityPostPaused(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_PAUSE);
+ }
+
+ @Override
+ public void onActivityPreStopped(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_STOP);
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_STOP);
+ }
+
+ @Override
+ public void onActivityPostStopped(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_STOP);
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+ }
+
+ @Override
+ public void onActivityPreDestroyed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_DESTROY);
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_DESTROY);
+ }
+
+ @Override
+ public void onActivityPostDestroyed(Activity activity) {
+ collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_DESTROY);
+ }
+ };
+ registerActivityLifecycleCallbacks(mActivityCallbacksCreateOnly);
}
public void collectEvent(Source source, Event event) {
diff --git a/tests/app/src/android/app/cts/ActivityCallbacksTest.java b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
index ff9c401..909748f 100644
--- a/tests/app/src/android/app/cts/ActivityCallbacksTest.java
+++ b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
@@ -229,11 +229,19 @@
Event preEvent, Event event, Event postEvent) {
expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, preEvent));
expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, preEvent));
+ if (preEvent == ON_PRE_CREATE) {
+ // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+ expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, preEvent));
+ }
expectedEvents.add(new Pair<>(Source.ACTIVITY, preEvent));
if (event == ON_CREATE || event == ON_START || event == ON_RESUME) {
// Application goes first on upward lifecycle events
expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, event));
expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
+ if (event == ON_CREATE) {
+ // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+ expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, event));
+ }
} else {
// Application goes last on downward lifecycle events
expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
@@ -241,6 +249,10 @@
}
expectedEvents.add(new Pair<>(Source.ACTIVITY, postEvent));
expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, postEvent));
+ if (postEvent == ON_POST_CREATE) {
+ // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+ expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, postEvent));
+ }
expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, postEvent));
}
}
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index f2b5cd4..cff8dcb 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -159,15 +159,11 @@
NotificationChannel channel =
new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
channel.setAllowBubbles(true);
- assertEquals("Only HIGH channels can have bubbles", false, channel.canBubble());
+ assertEquals(true, channel.canBubble());
- channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
+ channel = new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
channel.setAllowBubbles(false);
assertEquals(false, channel.canBubble());
-
- channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
- channel.setAllowBubbles(true);
- assertEquals(true, channel.canBubble());
}
public void testIsImportanceLockedByOEM() {
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index f639d56..543e7e8 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -965,6 +965,57 @@
mListener.resetData();
}
+ public void testCanBubble_ranking() throws Exception {
+ if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+ return;
+ }
+
+ assertEquals(1, Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BUBBLES));
+
+ toggleListenerAccess(TestNotificationListener.getId(),
+ InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
+
+ mListener = TestNotificationListener.getInstance();
+ assertNotNull(mListener);
+ try {
+ sendNotification(1, R.drawable.black);
+ Thread.sleep(500); // wait for notification listener to receive notification
+ NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+ NotificationListenerService.Ranking outRanking =
+ new NotificationListenerService.Ranking();
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ rankingMap.getRanking(key, outRanking);
+ // by default everything can bubble
+ assertTrue(outRanking.canBubble());
+ }
+ }
+
+ // turn off bubbles globally
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BUBBLES, 0));
+
+ Thread.sleep(500); // wait for ranking update
+
+ rankingMap = mListener.mRankingMap;
+ outRanking = new NotificationListenerService.Ranking();
+ for (String key : rankingMap.getOrderedKeys()) {
+ if (key.contains(mListener.getPackageName())) {
+ assertFalse(outRanking.canBubble());
+ }
+ }
+
+ mListener.resetData();
+ } finally {
+ SystemUtil.runWithShellPermissionIdentity(() ->
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_BUBBLES, 1));
+ }
+ }
+
public void testNotify_blockedChannel() throws Exception {
mNotificationManager.cancelAll();
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 3109a0e..94af896 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -188,7 +188,20 @@
assertFeature(manualPostProcessing,
PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
- assertFeature(motionTracking, PackageManager.FEATURE_CAMERA_AR);
+ if (!motionTracking) {
+ // FEATURE_CAMERA_AR requires the presence of
+ // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING but
+ // MOTION_TRACKING does not require the presence of FEATURE_CAMERA_AR
+ //
+ // Logic table:
+ // AR= F T
+ // MT=F Y N
+ // =T Y Y
+ //
+ // So only check the one disallowed condition: No motion tracking and FEATURE_CAMERA_AR is
+ // available
+ assertNotAvailable(PackageManager.FEATURE_CAMERA_AR);
+ }
}
private void checkFrontCamera() {
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index 4fe406f..e7413b1 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="autofill" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index be2625e..6997453 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -19,6 +19,7 @@
import static android.autofillservice.cts.Helper.getContext;
import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
import static android.content.Context.CLIPBOARD_SERVICE;
+import static android.provider.Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
@@ -38,7 +39,9 @@
import com.android.compatibility.common.util.RequiredFeatureRule;
import com.android.compatibility.common.util.RetryRule;
import com.android.compatibility.common.util.SafeCleanerRule;
+import com.android.compatibility.common.util.SettingsStateChangerRule;
import com.android.compatibility.common.util.SettingsStateKeeperRule;
+import com.android.compatibility.common.util.SettingsUtils;
import com.android.compatibility.common.util.TestNameUtils;
import org.junit.Before;
@@ -202,6 +205,10 @@
// mRetryRule should be closest to the main test as possible
.around(mRetryRule)
//
+ // Augmented Autofill should be disabled by default
+ .around(new SettingsStateChangerRule(sContext, SettingsUtils.NAMESPACE_GLOBAL,
+ AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
+ Integer.toString(getSmartSuggestionMode())))
//
// Finally, let subclasses add their own rules (like ActivityTestRule)
.around(getMainTestRule());
@@ -217,6 +224,10 @@
mUiBot.reset();
}
+ protected int getSmartSuggestionMode() {
+ return 0;
+ }
+
/**
* Gets how many times a test should be retried.
*
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
index f1b262f..83a938d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
@@ -17,31 +17,21 @@
import static android.autofillservice.cts.Helper.allowOverlays;
import static android.autofillservice.cts.Helper.disallowOverlays;
-import static android.provider.Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS;
import android.autofillservice.cts.AbstractAutoFillActivity;
import android.autofillservice.cts.AutoFillServiceTestCase;
import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedReplier;
import android.view.autofill.AutofillManager;
-import com.android.compatibility.common.util.SettingsStateChangerRule;
-import com.android.compatibility.common.util.SettingsUtils;
-
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.ClassRule;
// Must be public because of the @ClassRule
public abstract class AugmentedAutofillAutoActivityLaunchTestCase
<A extends AbstractAutoFillActivity> extends AutoFillServiceTestCase.AutoActivityLaunch<A> {
- @ClassRule
- public static final SettingsStateChangerRule sFeatureEnabler = new SettingsStateChangerRule(
- sContext, SettingsUtils.NAMESPACE_GLOBAL, AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
- Integer.toString(AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM));
-
protected static AugmentedReplier sAugmentedReplier;
protected AugmentedUiBot mAugmentedUiBot;
@@ -70,6 +60,11 @@
AugmentedHelper.resetAugmentedService();
}
+ @Override
+ protected int getSmartSuggestionMode() {
+ return AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+ }
+
protected void enableAugmentedService() {
AugmentedHelper.setAugmentedService(CtsAugmentedAutofillService.SERVICE_NAME);
}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index ebbd555..32b5932 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -82,12 +82,6 @@
LOCAL_JNI_SHARED_LIBRARIES := \
libctscamera2_jni \
libnativehelper_compat_libc++ \
- libdynamic_depth \
- libimage_io \
- libxml2 \
- libandroidicu \
- libbase \
- libc++ \
LOCAL_NDK_STL_VARIANT := c++_shared
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index 83cdd03..94f7ca3 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="camera" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsCameraTestCases.apk" />
@@ -24,7 +25,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.camera.cts" />
<option name="runtime-hint" value="12m7s" />
- <!-- test-timeout unit is ms, value = 20 min -->
- <option name="test-timeout" value="1200000" />
+ <!-- test-timeout unit is ms, value = 33 min -->
+ <option name="test-timeout" value="2000000" />
</test>
</configuration>
diff --git a/tests/camera/libctscamera2jni/Android.mk b/tests/camera/libctscamera2jni/Android.mk
index e9c301e..798674b 100644
--- a/tests/camera/libctscamera2jni/Android.mk
+++ b/tests/camera/libctscamera2jni/Android.mk
@@ -35,15 +35,18 @@
# Flags to avoid warnings from DNG SDK
LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-unused-value -Wno-unused-variable
+# Flags related to dynamic depth
+LOCAL_CFLAGS += -Wno-ignored-qualifiers -DSTATIC_LIBXML=1
LOCAL_STATIC_LIBRARIES := libdng_sdk_validate libjpeg_static_ndk
+# Dynamic depth libraries
+LOCAL_STATIC_LIBRARIES += libdynamic_depth_ndk libimage_io_ndk libbase_ndk libxml2_ndk
LOCAL_SHARED_LIBRARIES := libandroid \
libnativehelper_compat_libc++ \
liblog \
libcamera2ndk \
libmediandk \
libz \
- libdl \
# NDK build, shared C++ runtime
LOCAL_SDK_VERSION := current
diff --git a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
index a1d4b83..fbc63ef 100644
--- a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
+++ b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
@@ -17,11 +17,9 @@
#define LOG_TAG "DYNAMIC-DEPTH-JNI"
#include <jni.h>
#include <log/log.h>
-#include <dlfcn.h>
+#include <dynamic_depth/depth_jpeg.h>
-typedef int32_t (*validate_dynamic_depth_buffer) (const char *, size_t);
-static const char *kDynamicDepthLibraryName = "libdynamic_depth.so";
-static const char *kDynamicDepthValidateFunction = "ValidateAndroidDynamicDepthBuffer";
+using namespace dynamic_depth;
extern "C" jboolean
Java_android_hardware_camera2_cts_ImageReaderTest_validateDynamicDepthNative(
@@ -34,23 +32,8 @@
return JNI_FALSE;
}
- void* depthLibHandle = dlopen(kDynamicDepthLibraryName, RTLD_NOW | RTLD_LOCAL);
- if (depthLibHandle == nullptr) {
- ALOGE("Failed to load dynamic depth library!");
- return JNI_FALSE;
- }
-
- validate_dynamic_depth_buffer validate = reinterpret_cast<validate_dynamic_depth_buffer> (
- dlsym(depthLibHandle, kDynamicDepthValidateFunction));
- if (validate == nullptr) {
- ALOGE("Failed to link to dynamic depth validate function!");
- dlclose(depthLibHandle);
- return JNI_FALSE;
- }
-
- auto ret = (validate(reinterpret_cast<const char *> (buffer), bufferLength) == 0) ?
- JNI_TRUE : JNI_FALSE;
- dlclose(depthLibHandle);
+ auto ret = (ValidateAndroidDynamicDepthBuffer(reinterpret_cast<const char *> (buffer),
+ bufferLength) == 0) ? JNI_TRUE : JNI_FALSE;
return ret;
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index 3ed4fdb..e275aa4 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -367,6 +367,32 @@
}
/**
+ * If the camera device advertises the SECURE_IAMGE_DATA capability, test
+ * ImageFormat.PRIVATE + PROTECTED usage capture by using ImageReader with the
+ * ImageReader factory method that has usage flag argument, and uses a custom usage flag.
+ */
+ public void testImageReaderPrivateWithProtectedUsageFlag() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Private format and protected usage testing for camera " + id);
+ if (!mAllStaticInfo.get(id).isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA)) {
+ Log.i(TAG, "Camera " + id +
+ " does not support secure image data capability, skipping");
+
+ continue;
+ }
+ openDevice(id);
+ bufferFormatTestByCamera(ImageFormat.PRIVATE, /*setUsageFlag*/ true,
+ HardwareBuffer.USAGE_PROTECTED_CONTENT, /*repeating*/ true,
+ /*checkSession*/ true, /*validateImageData*/ false);
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
+
+ /**
* Test two image stream (YUV420_888 and RAW_SENSOR) capture by using ImageReader with the
* ImageReader factory method that has usage flag argument.
*
@@ -930,11 +956,23 @@
}
private void bufferFormatTestByCamera(int format, boolean repeating) throws Exception {
- bufferFormatTestByCamera(format, repeating, /*checkSession*/ false);
+ bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+ HardwareBuffer.USAGE_CPU_READ_OFTEN, repeating,
+ /*checkSession*/ false, /*validateImageData*/ true);
}
private void bufferFormatTestByCamera(int format, boolean repeating, boolean checkSession)
throws Exception {
+ bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+ HardwareBuffer.USAGE_CPU_READ_OFTEN,
+ repeating, checkSession, /*validateImageData*/true);
+ }
+
+ private void bufferFormatTestByCamera(int format, boolean setUsageFlag, long usageFlag,
+ // TODO: Consider having some sort of test configuration class passed to reduce the
+ // proliferation of parameters ?
+ boolean repeating, boolean checkSession, boolean validateImageData)
+ throws Exception {
Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
StaticMetadata.StreamDirection.Output);
@@ -948,7 +986,11 @@
// Create ImageReader.
mListener = new SimpleImageListener();
- createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+ if (setUsageFlag) {
+ createDefaultImageReader(sz, format, MAX_NUM_IMAGES, usageFlag, mListener);
+ } else {
+ createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+ }
if (checkSession) {
assertTrue("Camera capture session validation for format: " + format +
@@ -962,8 +1004,10 @@
int numFrameVerified = repeating ? NUM_FRAME_VERIFIED : 1;
- // Validate images.
- validateImage(sz, format, numFrameVerified, repeating);
+ if (validateImageData) {
+ // Validate images.
+ validateImage(sz, format, numFrameVerified, repeating);
+ }
// Validate capture result.
validateCaptureResult(format, sz, listener, numFrameVerified);
@@ -1191,7 +1235,6 @@
/** Load dynamic depth validation jni on initialization */
static {
- System.loadLibrary("dynamic_depth");
System.loadLibrary("ctscamera2_jni");
}
/**
diff --git a/tests/contentcaptureservice/AndroidTest.xml b/tests/contentcaptureservice/AndroidTest.xml
index 941df89..b3c8635 100644
--- a/tests/contentcaptureservice/AndroidTest.xml
+++ b/tests/contentcaptureservice/AndroidTest.xml
@@ -16,13 +16,18 @@
<configuration description="Config for ContentCapture CTS tests.">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsContentCaptureServiceTestCases.apk" />
</target_preparer>
- <!-- TODO(b/122605818): add preparer for instant-apps tests -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="cmd content_capture set bind-instant-service-allowed true" />
+ <option name="teardown-command" value="cmd content_capture set bind-instant-service-allowed false" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.contentcaptureservice.cts" />
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
index 96f94b4..7e6f6f2 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -42,7 +42,9 @@
import com.android.compatibility.common.util.SettingsUtils;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
@@ -54,6 +56,8 @@
public abstract class AbstractContentCaptureIntegrationTest
<A extends AbstractContentCaptureActivity> {
+ private static final String TAG = AbstractContentCaptureIntegrationTest.class.getSimpleName();
+
private final String mTag = getClass().getSimpleName();
protected static final Context sContext = InstrumentationRegistry.getTargetContext();
@@ -67,8 +71,24 @@
private final ContentCaptureLoggingTestRule mLoggingRule = new ContentCaptureLoggingTestRule();
+
+ /**
+ * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
+ * finishes.
+ */
+ private ServiceWatcher mServiceWatcher;
+
protected final SafeCleanerRule mSafeCleanerRule = new SafeCleanerRule()
.setDumper(mLoggingRule)
+ .run(() -> {
+ Log.v(mTag, "@SafeCleaner: resetDefaultService()");
+ resetService();
+
+ if (mServiceWatcher != null) {
+ mServiceWatcher.waitOnDestroy();
+ }
+
+ })
.add(() -> {
return CtsContentCaptureService.getExceptions();
});
@@ -93,16 +113,22 @@
// Finally, let subclasses set their ActivityTestRule
.around(getActivityTestRule());
- /**
- * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
- * finishes.
- */
- private ServiceWatcher mServiceWatcher;
-
protected AbstractContentCaptureIntegrationTest(@NonNull Class<A> activityClass) {
mActivityClass = activityClass;
}
+ @BeforeClass
+ public static void disableDefaultService() {
+ Log.v(TAG, "@BeforeClass: disableDefaultService()");
+ Helper.setDefaultServiceEnabled(false);
+ }
+
+ @AfterClass
+ public static void enableDefaultService() {
+ Log.v(TAG, "@AfterClass: enableDefaultService()");
+ Helper.setDefaultServiceEnabled(true);
+ }
+
@Before
public void prepareDevice() throws Exception {
Log.v(mTag, "@Before: prepareDevice()");
@@ -140,18 +166,6 @@
}
}
- // TODO(b/123539404): this method should be called from the SafeCleaner, but we'll need to
- // add a run() method that takes an object that can throw an exception
- @After
- public void restoreDefaultService() throws InterruptedException {
- Log.v(mTag, "@After: restoreDefaultService()");
- resetService();
-
- if (mServiceWatcher != null) {
- mServiceWatcher.waitOnDestroy();
- }
- }
-
@Nullable
public static void setFeatureEnabled(@Nullable String enabled) {
if (enabled == null) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index b74b22c..e3792ee 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -279,8 +279,18 @@
assertThat(events).hasSize(minimumSize + 1);
final ContentCaptureEvent batchDisappearEvent = events.get(minimumSize);
- final List<AutofillId> actualIds = batchDisappearEvent.getIds();
- assertThat(actualIds).containsExactly((Object[]) expectedIds);
+ if (expectedIds.length == 1) {
+ assertWithMessage("Should have just one deleted id on %s", batchDisappearEvent)
+ .that(batchDisappearEvent.getIds()).isNull();
+ assertWithMessage("wrong deleted id on %s", batchDisappearEvent)
+ .that(batchDisappearEvent.getId()).isEqualTo(expectedIds[0]);
+ } else {
+ assertWithMessage("Should not have individual deleted id on %s", batchDisappearEvent)
+ .that(batchDisappearEvent.getId()).isNull();
+ final List<AutofillId> actualIds = batchDisappearEvent.getIds();
+ assertWithMessage("wrong deleteds id on %s", batchDisappearEvent)
+ .that(actualIds).containsExactly((Object[]) expectedIds);
+ }
}
/**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
index 5a78cb6..abb0e7e 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
@@ -25,6 +25,7 @@
import android.content.ComponentName;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
@@ -33,6 +34,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
public class BlankActivityTest extends AbstractContentCaptureIntegrationTest<BlankActivity> {
private static final String TAG = BlankActivityTest.class.getSimpleName();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
index d99dfec..28dc2e7 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
@@ -60,6 +61,7 @@
activity.assertDefaultEvents(session);
}
+ @AppModeFull(reason = "testSimpleSessionLifecycle() is enough")
@Test
public void testSimpleSessionLifecycle_noAnimation() throws Exception {
final CtsContentCaptureService service = enableService();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 3af2c65..8dbda23 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -43,6 +43,7 @@
import android.contentcaptureservice.cts.common.ActivityLauncher;
import android.net.Uri;
import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
import android.view.View;
@@ -66,6 +67,7 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
public class ChildlessActivityTest
extends AbstractContentCaptureIntegrationTest<ChildlessActivity> {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
index e869fc1..04213ba 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
@@ -58,11 +58,6 @@
private static ServiceWatcher sServiceWatcher;
- // TODO(b/123421324): reuse with allSessions
- /** Used by {@link #getOnlyFinishedSession()}. */
- private static ContentCaptureSessionId sFirstSessionId;
-
-
private final int mId = ++sIdCounter;
private static final ArrayList<Throwable> sExceptions = new ArrayList<>();
@@ -118,7 +113,6 @@
public static void resetStaticState() {
- sFirstSessionId = null;
sExceptions.clear();
// TODO(b/123540602): should probably set sInstance to null as well, but first we would need
// to make sure each test unbinds the service.
@@ -202,11 +196,8 @@
public void onCreateContentCaptureSession(ContentCaptureContext context,
ContentCaptureSessionId sessionId) {
Log.i(TAG, "onCreateContentCaptureSession(id=" + mId + ", ctx=" + context
- + ", session=" + sessionId + ", firstId=" + sFirstSessionId + ")");
+ + ", session=" + sessionId);
mAllSessions.add(sessionId);
- if (sFirstSessionId == null) {
- sFirstSessionId = sessionId;
- }
safeRun(() -> {
final Session session = mOpenSessions.get(sessionId);
@@ -289,9 +280,11 @@
*/
@NonNull
public Session getOnlyFinishedSession() throws InterruptedException {
- // TODO(b/123421324): add some assertions to make sure There Can Be Only One!
- assertWithMessage("No session yet").that(sFirstSessionId).isNotNull();
- return getFinishedSession(sFirstSessionId);
+ final ArrayList<ContentCaptureSessionId> allSessions = mAllSessions;
+ assertWithMessage("Wrong number of sessions").that(allSessions).hasSize(1);
+ final ContentCaptureSessionId id = allSessions.get(0);
+ Log.d(TAG, "getOnlyFinishedSession(): id=" + id);
+ return getFinishedSession(id);
}
/**
@@ -319,7 +312,6 @@
super.dump(fd, pw, args);
pw.print("sServiceWatcher: "); pw.println(sServiceWatcher);
- pw.print("sFirstSessionId: "); pw.println(sFirstSessionId);
pw.print("sExceptions: "); pw.println(sExceptions);
pw.print("sIdCounter: "); pw.println(sIdCounter);
pw.print("mId: "); pw.println(mId);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
index 92b4f53..33cd31f 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
@@ -101,13 +101,16 @@
@NonNull
private List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session,
int additionalEvents) {
- final List<ContentCaptureEvent> events = session.getEvents();
- Log.v(TAG, "events(" + events.size() + "): " + events);
- assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
-
final View grandpa1 = (View) mCustomView.getParent();
final View grandpa2 = (View) grandpa1.getParent();
final View decorView = getDecorView();
+ Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+ + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+ + decorView.getAutofillId());
+
+ final List<ContentCaptureEvent> events = session.getEvents();
+ Log.v(TAG, "events(" + events.size() + "): " + events);
+ assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
// Assert just the relevant events
assertViewHierarchyStarted(events, 0);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index 0218b4a..0ab1425 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,7 +15,11 @@
*/
package android.contentcaptureservice.cts;
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyStarted;
import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
@@ -31,8 +35,10 @@
import android.contentcaptureservice.cts.common.DoubleVisitor;
import android.os.Handler;
import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
+import android.view.View;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ContentCaptureEvent;
@@ -40,13 +46,13 @@
import androidx.annotation.NonNull;
-import org.junit.Ignore;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
public class CustomViewActivityTest extends
AbstractContentCaptureIntegrationTest<CustomViewActivity> {
@@ -89,7 +95,6 @@
* the session notification methods instead - this is wrong because the main view will be
* notified last, but we cannot prevent the apps from doing so...
*/
- @Ignore("current broken, will be fixed by b/123777277")
@Test
public void testVirtualView_wrongWay() throws Exception {
final CtsContentCaptureService service = enableService();
@@ -123,24 +128,36 @@
assertRightActivity(session, session.id, activity);
-
- final int additionalEvents = 3;
- final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
- additionalEvents);
-
+ final View grandpa1 = (View) activity.mCustomView.getParent();
+ final View grandpa2 = (View) grandpa1.getParent();
+ final View decorView = activity.getDecorView();
final AutofillId customViewId = activity.mCustomView.getAutofillId();
+ Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+ + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+ + decorView.getAutofillId() + "customView=" + customViewId);
+
+ final List<ContentCaptureEvent> events = session.getEvents();
+ Log.v(TAG, "events(" + events.size() + "): " + events);
+ final int additionalEvents = 2;
+
+ assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
+
+ // Assert just the relevant events
+ assertViewHierarchyStarted(events, 0);
+ assertDecorViewAppeared(events, 1, decorView);
+ assertViewAppeared(events, 2, grandpa2, decorView.getAutofillId());
+ assertViewAppeared(events, 3, grandpa1, grandpa2.getAutofillId());
+
final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
-
- final int i = CustomViewActivity.MIN_EVENTS;
-
- assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "child");
- assertVirtualViewDisappeared(events, i + 1, customViewId, mainSession, 1);
+ assertVirtualViewAppeared(events, 4, mainSession, customViewId, 1, "child");
+ assertVirtualViewDisappeared(events, 5, customViewId, mainSession, 1);
// This is the "wrong" part - the parent is notified last
- assertViewWithUnknownParentAppeared(events, i + 2, session.id, activity.mCustomView);
+ assertViewWithUnknownParentAppeared(events, 6, session.id, activity.mCustomView);
+
+ assertViewHierarchyFinished(events, 7);
activity.assertInitialViewsDisappeared(events, additionalEvents);
- // TODO(b/122315042): assert views disappeared
}
/**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
index 9784213..30ba124 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -74,6 +74,15 @@
}
/**
+ * Enables / disables the default service.
+ */
+ public static void setDefaultServiceEnabled(boolean enabled) {
+ Log.d(TAG, "setDefaultServiceEnabled(): " + enabled);
+ runShellCommand("cmd content_capture set default-service-enabled 0 %s",
+ Boolean.toString(enabled));
+ }
+
+ /**
* Gets the component name for a given class.
*/
public static ComponentName componentNameFor(@NonNull Class<?> clazz) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
index d78c329..926f63a 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
@@ -38,6 +38,7 @@
import android.contentcaptureservice.cts.common.DoubleVisitor;
import android.net.Uri;
import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
import android.support.test.rule.ActivityTestRule;
import android.util.Log;
import android.view.View;
@@ -59,6 +60,7 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
public class LoginActivityTest extends AbstractContentCaptureIntegrationTest<LoginActivity> {
private static final String TAG = LoginActivityTest.class.getSimpleName();
diff --git a/tests/framework/base/activitymanager/util/Android.bp b/tests/framework/base/activitymanager/util/Android.bp
index 2e2f030..f71603b 100644
--- a/tests/framework/base/activitymanager/util/Android.bp
+++ b/tests/framework/base/activitymanager/util/Android.bp
@@ -24,9 +24,7 @@
static_libs: [
"platformprotosnano",
"compatibility-device-util",
- "android-support-test",
- "androidx.test.rules",
- "androidx.test.runner",
+ "android-support-test",
],
sdk_version: "test_current",
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
deleted file mode 100644
index 3307af1..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.am.compat;
-
-import com.android.compatibility.common.util.TestUtils;
-
-/**
- * {@link com.android.compatibility.common.util.AmUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AmUtils {
-
- public static void runKill(String packageName, boolean wait) throws Exception {
- SystemUtil.runShellCommandForNoOutput("am kill --user cur " + packageName);
-
- if (!wait) {
- return;
- }
-
- TestUtils.waitUntil("package process was not killed:" + packageName,
- () -> !isProcessRunning(packageName));
- }
-
- private static boolean isProcessRunning(String packageName) {
- final String output = SystemUtil.runShellCommand("ps -A -o NAME");
- String[] packages = output.split("\\n");
- for (int i = packages.length - 1; i >= 0; --i) {
- if (packages[i].equals(packageName)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
deleted file mode 100644
index f957d14..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.app.AppOpsManager;
-
-import java.io.IOException;
-
-/**
- * {@link com.android.compatibility.common.util.AppOpsUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AppOpsUtils {
- /**
- * Resets a package's app ops configuration to the device default. See AppOpsManager for the
- * default op settings.
- *
- * <p>
- * It's recommended to call this in setUp() and tearDown() of your test so the test starts and
- * ends with a reproducible default state, and so doesn't affect other tests.
- *
- * <p>
- * Some app ops are configured to be non-resettable, which means that the state of these will
- * not be reset even when calling this method.
- */
- public static String reset(String packageName) throws IOException {
- return SystemUtil.runShellCommand(getInstrumentation(), "appops reset " + packageName);
- }
-
- /**
- * Sets the app op mode (e.g. allowed, denied) for a single package and operation.
- */
- public static String setOpMode(String packageName, String opStr, int mode)
- throws IOException {
- String modeStr;
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- modeStr = "allow";
- break;
- case AppOpsManager.MODE_ERRORED:
- modeStr = "deny";
- break;
- case AppOpsManager.MODE_IGNORED:
- modeStr = "ignore";
- break;
- case AppOpsManager.MODE_DEFAULT:
- modeStr = "default";
- break;
- default:
- throw new IllegalArgumentException("Unexpected app op type");
- }
- String command = "appops set " + packageName + " " + opStr + " " + modeStr;
- return SystemUtil.runShellCommand(getInstrumentation(), command);
- }
-
- /**
- * Get the app op mode (e.g. MODE_ALLOWED, MODE_DEFAULT) for a single package and operation.
- */
- public static int getOpMode(String packageName, String opStr)
- throws IOException {
- String opState = getOpState(packageName, opStr);
- if (opState.contains(" allow")) {
- return AppOpsManager.MODE_ALLOWED;
- } else if (opState.contains(" deny")) {
- return AppOpsManager.MODE_ERRORED;
- } else if (opState.contains(" ignore")) {
- return AppOpsManager.MODE_IGNORED;
- } else if (opState.contains(" default")) {
- return AppOpsManager.MODE_DEFAULT;
- } else {
- throw new IllegalStateException("Unexpected app op mode returned " + opState);
- }
- }
-
- /**
- * Returns whether an allowed operation has been logged by the AppOpsManager for a
- * package. Operations are noted when the app attempts to perform them and calls e.g.
- * {@link AppOpsManager#noteOp}.
- *
- * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
- */
- public static boolean allowedOperationLogged(String packageName, String opStr)
- throws IOException {
- return getOpState(packageName, opStr).contains(" time=");
- }
-
- /**
- * Returns whether a rejected operation has been logged by the AppOpsManager for a
- * package. Operations are noted when the app attempts to perform them and calls e.g.
- * {@link AppOpsManager#noteOp}.
- *
- * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
- */
- public static boolean rejectedOperationLogged(String packageName, String opStr)
- throws IOException {
- return getOpState(packageName, opStr).contains(" rejectTime=");
- }
-
- /**
- * Returns the app op state for a package. Includes information on when the operation was
- * last attempted to be performed by the package.
- *
- * Format: "SEND_SMS: allow; time=+23h12m54s980ms ago; rejectTime=+1h10m23s180ms"
- */
- private static String getOpState(String packageName, String opStr) throws IOException {
- return SystemUtil.runShellCommand(
- getInstrumentation(), "appops get " + packageName + " " + opStr);
- }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
deleted file mode 100644
index 23f8784..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.server.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-
-/**
- * {@link com.android.compatibility.common.util.SystemUtil} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class SystemUtil {
-
- private static final String TAG = SystemUtil.class.getSimpleName();
-
- /**
- * Executes a shell command using shell user identity, and return the standard output in string
- * <p>Note: calling this function requires API level 21 or above
- * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
- * instrumentation framework
- * @param cmd the command to run
- * @return the standard output of the command
- * @throws Exception
- */
- public static String runShellCommand(Instrumentation instrumentation, String cmd)
- throws IOException {
- Log.v(TAG, "Running command: " + cmd);
- if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
- throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
- + "or revokeRuntimePermission() directly, which are more robust.");
- }
- ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
- byte[] buf = new byte[512];
- int bytesRead;
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- StringBuffer stdout = new StringBuffer();
- while ((bytesRead = fis.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
- }
- fis.close();
- return stdout.toString();
- }
-
- /**
- * Simpler version of {@link #runShellCommand(Instrumentation, String)}.
- */
- public static String runShellCommand(String cmd) {
- try {
- return runShellCommand(getInstrumentation(), cmd);
- } catch (IOException e) {
- fail("Failed reading command output: " + e);
- return "";
- }
- }
-
- /**
- * Same as {@link #runShellCommand(String)}, but fails if the output is not empty.
- */
- public static String runShellCommandForNoOutput(String cmd) {
- final String result = runShellCommand(cmd);
- assertTrue("Command failed. Command was: " + cmd + "\n"
- + "Didn't expect any output, but the output was:\n" + result,
- result.length() == 0);
- return result;
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting Shell's permissions.
- */
- public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable) {
- final UiAutomation automan = getInstrumentation().getUiAutomation();
- runWithShellPermissionIdentity(automan, runnable, (String[]) null /* permissions */);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting a subset of Shell's permissions.
- */
- public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable,
- String... permissions) {
- final UiAutomation automan = getInstrumentation().getUiAutomation();
- runWithShellPermissionIdentity(automan, runnable, permissions);
- }
-
- /**
- * Runs a {@link ThrowingRunnable} adopting Shell's permissions, where you can specify the
- * uiAutomation used.
- * @param automan UIAutomation to use.
- * @param runnable The code to run with Shell's identity.
- * @param permissions A subset of Shell's permissions. Passing {@code null} will use all
- * available permissions.
- */
- private static void runWithShellPermissionIdentity(@NonNull UiAutomation automan,
- @NonNull ThrowingRunnable runnable, String... permissions) {
- automan.adoptShellPermissionIdentity(permissions);
- try {
- runnable.run();
- } catch (Exception e) {
- throw new RuntimeException("Caught exception", e);
- } finally {
- automan.dropShellPermissionIdentity();
- }
- }
-
- /**
- * Calls a {@link Callable} adopting Shell's permissions.
- */
- public static <T> T callWithShellPermissionIdentity(@NonNull Callable<T> callable)
- throws Exception {
- final UiAutomation automan = getInstrumentation().getUiAutomation();
- automan.adoptShellPermissionIdentity();
- try {
- return callable.call();
- } finally {
- automan.dropShellPermissionIdentity();
- }
- }
-}
diff --git a/tests/jdwp/AndroidTest.xml b/tests/jdwp/AndroidTest.xml
index 462ed34..9b42fb9 100644
--- a/tests/jdwp/AndroidTest.xml
+++ b/tests/jdwp/AndroidTest.xml
@@ -36,6 +36,7 @@
<option name="dalvik-arg" value="-Djpda.settings.verbose=false" />
<option name="dalvik-arg" value="-Djpda.settings.timeout=10000" />
<option name="dalvik-arg" value="-Djpda.settings.waitingTime=10000" />
+ <option name="dalvik-arg" value="-Djpda.settings.dumpProcess='/system/xbin/su root /system/bin/logwrapper /system/bin/debuggerd'" />
<option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeAgentArgument=-agentpath:" />
<option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeAgentName=libjdwp.so" />
<option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeJavaPath='dalvikvm|#ABI#| -XXlib:libart.so -Xplugin:libopenjdkjvmti.so -Xcompiler-option --debuggable -Xusejit:true'" />
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index c398ab05..e2a3139 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="misc" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 99fbff7..23d555e 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@@ -971,6 +972,8 @@
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
context.startService(new Intent(context, TestService.class));
mUiDevice.wait(Until.hasObject(By.clazz(TestService.class)), TIMEOUT);
+ final long sleepTime = 500;
+ SystemClock.sleep(sleepTime);
context.stopService(new Intent(context, TestService.class));
mUiDevice.wait(Until.gone(By.clazz(TestService.class)), TIMEOUT);
final long endTime = System.currentTimeMillis();
@@ -1000,6 +1003,19 @@
assertEquals(numStarts, 1);
assertEquals(numStops, 1);
assertLessThan(startIdx, stopIdx);
+
+ final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
+ startTime, endTime);
+ final UsageStats stats = map.get(mTargetPackage);
+ assertNotNull(stats);
+ final long lastTimeUsed = stats.getLastTimeForegroundServiceUsed();
+ // lastTimeUsed should be falling between startTime and endTime.
+ assertLessThan(startTime, lastTimeUsed);
+ assertLessThan(lastTimeUsed, endTime);
+ final long totalTimeUsed = stats.getTotalTimeForegroundServiceUsed();
+ // because we slept for 500 milliseconds earlier, we know the totalTimeUsed must be more
+ // more than 500 milliseconds.
+ assertLessThan(sleepTime, totalTimeUsed);
}
@AppModeFull // No usage events access in instant apps
@@ -1050,6 +1066,8 @@
SystemClock.sleep(500);
}
+ mUiDevice.pressHome();
+
setUsageSourceSetting(Integer.toString(mUsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY));
launchSubActivity(TaskRootActivity.class);
// Usage should be attributed to the test app package
diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index ec79572..ffbaaa5 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -37,7 +37,6 @@
import java.util.List;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
index 3b9d8eb..c7cce6d 100644
--- a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
@@ -33,7 +33,6 @@
import java.util.stream.IntStream;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,7 +54,6 @@
@CddTest(requirement="2.5.1")
@Test
- @Ignore // Enable when b/120125891 is fixed
public void testRequiredSensorsForDrivingState() throws Exception {
boolean foundSpeed = false;
boolean foundGear = false;
diff --git a/tests/tests/contactsproviderwipe/AndroidTest.xml b/tests/tests/contactsproviderwipe/AndroidTest.xml
index 7bbb519..d73a717 100644
--- a/tests/tests/contactsproviderwipe/AndroidTest.xml
+++ b/tests/tests/contactsproviderwipe/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<!-- This is a test for apps with READ/WRITE_CONTACTS, which instant apps don't have -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/dynamic_linker/AndroidTest.xml b/tests/tests/dynamic_linker/AndroidTest.xml
index e4fa4cb..58fe8a0 100644
--- a/tests/tests/dynamic_linker/AndroidTest.xml
+++ b/tests/tests/dynamic_linker/AndroidTest.xml
@@ -16,7 +16,7 @@
<configuration description="Config for CTS dynamic linker test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="bionic" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
new file mode 100644
index 0000000..04d2d35
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright 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.graphics.cts;
+
+import static org.junit.Assert.assertEquals;
+//import static android.opengl.EGL14.*;
+//import static android.opengl.EGL15.*;
+
+import android.opengl.EGL14;
+import android.opengl.EGL15;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLImage;
+import android.opengl.EGLSurface;
+import android.opengl.EGLSync;
+import android.opengl.GLES20;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class)
+public class EGL15Test {
+
+ static {
+ System.loadLibrary("ctsgraphics_jni");
+ }
+
+ private static final String TAG = EGL15Test.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private EGLDisplay mEglDisplay = EGL15.EGL_NO_DISPLAY;
+ private EGLConfig mEglConfig = null;
+ private EGLSurface mEglPbuffer = EGL15.EGL_NO_SURFACE;
+ private EGLContext mEglContext = EGL15.EGL_NO_CONTEXT;
+ private int mEglVersion = 0;
+
+ @Before
+ public void setup() throws Throwable {
+ int error;
+
+ mEglDisplay = EGL15.eglGetPlatformDisplay(EGL15.EGL_PLATFORM_ANDROID_KHR,
+ EGL14.EGL_DEFAULT_DISPLAY,
+ new long[] {
+ EGL14.EGL_NONE },
+ 0);
+ if (mEglDisplay == EGL15.EGL_NO_DISPLAY) {
+ throw new RuntimeException("no EGL display");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglGetPlatformDisplay failed");
+ }
+
+ int[] major = new int[1];
+ int[] minor = new int[1];
+ if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
+ throw new RuntimeException("error in eglInitialize");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglInitialize failed");
+ }
+ mEglVersion = major[0] * 10 + minor[0];
+
+ // If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
+ // wouldn't have to create a config or pbuffer at all.
+
+ int[] numConfigs = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ if (!EGL14.eglChooseConfig(mEglDisplay,
+ new int[] {
+ EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+ EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
+ EGL14.EGL_NONE},
+ 0, configs, 0, 1, numConfigs, 0)) {
+ throw new RuntimeException("eglChooseConfig failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglChooseConfig failed");
+ }
+
+ mEglConfig = configs[0];
+
+ mEglPbuffer = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig,
+ new int[] {EGL14.EGL_WIDTH, 1, EGL14.EGL_HEIGHT, 1, EGL14.EGL_NONE}, 0);
+ if (mEglPbuffer == EGL15.EGL_NO_SURFACE) {
+ throw new RuntimeException("eglCreatePbufferSurface failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreatePbufferSurface failed");
+ }
+
+
+ mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT,
+ new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
+ if (mEglContext == EGL15.EGL_NO_CONTEXT) {
+ throw new RuntimeException("eglCreateContext failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreateContext failed");
+ }
+
+
+ if (!EGL14.eglMakeCurrent(mEglDisplay, mEglPbuffer, mEglPbuffer, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglMakeCurrent failed");
+ }
+ }
+
+ @After
+ public void teardown() throws Throwable {
+ EGL14.eglTerminate(mEglDisplay);
+ }
+
+ @Test
+ public void testEGL15SyncFence() {
+ if (mEglVersion < 15) {
+ return;
+ }
+ EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+ new long[] {
+ EGL14.EGL_NONE },
+ 0);
+ if (sync == EGL15.EGL_NO_SYNC) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+ int error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+
+ GLES20.glFlush();
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ throw new RuntimeException("glFlush failed");
+ }
+
+ int status = EGL15.eglClientWaitSync(mEglDisplay, sync, 0, EGL15.EGL_FOREVER);
+ if (status != EGL15.EGL_CONDITION_SATISFIED) {
+ throw new RuntimeException("eglClientWaitSync failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglClientWaitSync failed");
+ }
+
+ if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ }
+
+ @Test
+ public void testEGL15GetSyncType() {
+ if (mEglVersion < 15) {
+ return;
+ }
+ EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+ new long[] {
+ EGL14.EGL_NONE },
+ 0);
+ if (sync == EGL15.EGL_NO_SYNC) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+ int error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+
+ long[] type = new long[1];
+ boolean success = EGL15.eglGetSyncAttrib(mEglDisplay, sync, EGL15.EGL_SYNC_TYPE, type, 0);
+ if (!success) {
+ throw new RuntimeException("eglGetSyncAttrib failed (returned false)");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglGetSyncAttrib failed");
+ }
+ assertEquals(type[0], EGL15.EGL_SYNC_FENCE);
+
+ if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ }
+
+ @Test
+ public void testEGL15WaitSync() {
+ if (mEglVersion < 15) {
+ return;
+ }
+ EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+ new long[] {
+ EGL14.EGL_NONE },
+ 0);
+ if (sync == EGL15.EGL_NO_SYNC) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+ int error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreateSync failed");
+ }
+
+ boolean success = EGL15.eglWaitSync(mEglDisplay, sync, 0);
+ if (!success) {
+ throw new RuntimeException("eglWaitSync failed (returned false)");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglWaitSync failed");
+ }
+
+ if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglDestroySync failed");
+ }
+ }
+
+ @Test
+ public void testEGL15CreateImage() {
+ if (mEglVersion < 15) {
+ return;
+ }
+
+ int error;
+ int srcTex = 1;
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, srcTex);
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ throw new RuntimeException("glBindTexture failed");
+ }
+
+ GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 64, 64, 0,
+ GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ throw new RuntimeException("glTexImage2D failed");
+ }
+
+ GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_LINEAR);
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ throw new RuntimeException("glTexParameteri failed");
+ }
+
+ long[] attribs = new long[] {
+ EGL15.EGL_GL_TEXTURE_LEVEL, 0,
+ EGL14.EGL_NONE };
+ EGLImage image = EGL15.eglCreateImage(mEglDisplay, mEglContext,
+ EGL15.EGL_GL_TEXTURE_2D, srcTex, attribs, 0);
+ if (image == EGL15.EGL_NO_IMAGE) {
+ throw new RuntimeException("eglCreateImage failed, got EGL_NO_IMAGE");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglCreateImage failed");
+ }
+
+ boolean success = EGL15.eglDestroyImage(mEglDisplay, image);
+ if (!success) {
+ throw new RuntimeException("eglDestroyImage failed (returned false)");
+ }
+ error = EGL14.eglGetError();
+ if (error != EGL14.EGL_SUCCESS) {
+ throw new RuntimeException("eglDestroyImage failed");
+ }
+ }
+
+ @Test
+ public void testEGL15CreatePlatformPixmap() {
+ if (mEglVersion < 15) {
+ return;
+ }
+
+ long[] attribs = new long[] { EGL14.EGL_NONE };
+ boolean unsupported = false;
+ try {
+ EGLSurface surface = EGL15.eglCreatePlatformPixmapSurface(mEglDisplay,
+ mEglConfig, null, attribs, 0);
+ } catch (UnsupportedOperationException e) {
+ unsupported = true;
+ }
+ if (!unsupported) {
+ throw new RuntimeException("eglCreatePlatformPixmapSurface is not supported on Android,"
+ + " why did call not report that!");
+ }
+ }
+}
+
+// Note: Need to add tests for eglCreatePlatformWindowSurface
diff --git a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4 b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
index 8820340..157c222 100644
--- a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
+++ b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/lg_g4_iso_800.jpg b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
new file mode 100644
index 0000000..d264196
--- /dev/null
+++ b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
Binary files differ
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index 3443f33..f4f648d 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -49,6 +49,9 @@
<item>50</item>
<item>6</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="exifbyteordermm_jpg">
<item>false</item>
@@ -84,6 +87,9 @@
<item>146</item>
<item>0</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="lg_g4_iso_800_dng">
<item>true</item>
@@ -119,14 +125,55 @@
<item>800</item>
<item>1</item>
<item>0</item>
+ <item>true</item>
+ <item>826</item>
+ <item>10067</item>
+ </array>
+ <array name="lg_g4_iso_800_jpg">
+ <item>false</item>
+ <item />
+ <item />
+ <item />
+ <item />
+ <item />
+ <item>true</item>
+ <item>1662</item>
+ <item>24</item>
+ <item>53.834507</item>
+ <item>10.69585</item>
+ <item>0.0</item>
+ <item>LGE</item>
+ <item>LG-H815</item>
+ <item>1.800</item>
+ <item>2015:11:12 16:46:18</item>
+ <item>0.0040</item>
+ <item>0.0</item>
+ <item>442/100</item>
+ <item />
+ <item />
+ <item>1970:01:17</item>
+ <item>53/1,50/1,423/100</item>
+ <item>N</item>
+ <item>10/1,41/1,4506/100</item>
+ <item>E</item>
+ <item />
+ <item>18:08:10</item>
+ <item>337</item>
+ <item>600</item>
+ <item>800</item>
+ <item>1</item>
+ <item>0</item>
+ <item>true</item>
+ <item>1809</item>
+ <item>13197</item>
</array>
<array name="volantis_jpg">
<item>false</item>
<item />
<item />
- <item>0</item>
- <item>0</item>
- <item>false</item>
+ <item />
+ <item />
+ <item />
<item>true</item>
<item>3081</item>
<item>24</item>
@@ -154,6 +201,9 @@
<item>175</item>
<item>1</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="sony_rx_100_arw">
<item>true</item>
@@ -189,6 +239,9 @@
<item>125</item>
<item>8</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="canon_g7x_cr2">
<item>true</item>
@@ -224,6 +277,9 @@
<item>12800</item>
<item>8</item>
<item>1</item>
+ <item>true</item>
+ <item>14336</item>
+ <item>8192</item>
</array>
<array name="fuji_x20_raf">
<item>true</item>
@@ -259,6 +315,9 @@
<item>100</item>
<item>1</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="nikon_1aw1_nef">
<item>true</item>
@@ -294,6 +353,9 @@
<item>200</item>
<item>8</item>
<item>0</item>
+ <item>true</item>
+ <item>472</item>
+ <item>2048</item>
</array>
<array name="nikon_p330_nrw">
<item>true</item>
@@ -329,6 +391,9 @@
<item>3200</item>
<item>8</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="pentax_k5_pef">
<item>true</item>
@@ -364,6 +429,9 @@
<item>100</item>
<item>1</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="olympus_e_pl3_orf">
<item>true</item>
@@ -399,6 +467,9 @@
<item>200</item>
<item>1</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="panasonic_gm5_rw2">
<item>true</item>
@@ -434,6 +505,9 @@
<item>200</item>
<item>8</item>
<item>1</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
<array name="samsung_nx3000_srw">
<item>true</item>
@@ -469,5 +543,8 @@
<item>100</item>
<item>8</item>
<item>0</item>
+ <item>false</item>
+ <item />
+ <item />
</array>
</resources>
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 305a374..5bcfaa7 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -35,8 +35,11 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
@AppModeFull(reason = "Instant apps cannot access the SD card")
public class ExifInterfaceTest extends AndroidTestCase {
@@ -53,6 +56,7 @@
private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+ private static final String LG_G4_ISO_800_JPG = "lg_g4_iso_800.jpg";
private static final String SONY_RX_100_ARW = "sony_rx_100.arw";
private static final String CANON_G7X_CR2 = "canon_g7x.cr2";
private static final String FUJI_X20_RAF = "fuji_x20.raf";
@@ -128,6 +132,11 @@
public final int orientation;
public final int whiteBalance;
+ // XMP information.
+ public final boolean hasXmp;
+ public final int xmpOffset;
+ public final int xmpLength;
+
private static String getString(TypedArray typedArray, int index) {
String stringValue = typedArray.getString(index);
if (stringValue == null || stringValue.equals("")) {
@@ -178,6 +187,11 @@
orientation = typedArray.getInt(index++, 0);
whiteBalance = typedArray.getInt(index++, 0);
+ // Reads XMP information.
+ hasXmp = typedArray.getBoolean(index++, false);
+ xmpOffset = typedArray.getInt(index++, 0);
+ xmpLength = typedArray.getInt(index++, 0);
+
typedArray.recycle();
}
}
@@ -254,6 +268,7 @@
// Checks a thumbnail image.
assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
if (expectedValue.hasThumbnail) {
+ assertNotNull(exifInterface.getThumbnailRange());
if (assertRanges) {
final long[] thumbnailRange = exifInterface.getThumbnailRange();
assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
@@ -268,6 +283,7 @@
assertEquals(expectedValue.isThumbnailCompressed,
exifInterface.isThumbnailCompressed());
} else {
+ assertNull(exifInterface.getThumbnailRange());
assertNull(exifInterface.getThumbnail());
}
@@ -275,6 +291,7 @@
float[] latLong = new float[2];
assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
if (expectedValue.hasLatLong) {
+ assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
if (assertRanges) {
final long[] latitudeRange = exifInterface
.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE);
@@ -286,6 +303,7 @@
assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
} else {
+ assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
}
@@ -318,6 +336,26 @@
assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
+
+ if (expectedValue.hasXmp) {
+ assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+ if (assertRanges) {
+ final long[] xmpRange = exifInterface.getAttributeRange(ExifInterface.TAG_XMP);
+ assertEquals(expectedValue.xmpOffset, xmpRange[0]);
+ assertEquals(expectedValue.xmpLength, xmpRange[1]);
+ }
+ final String xmp = new String(exifInterface.getAttributeBytes(ExifInterface.TAG_XMP),
+ StandardCharsets.UTF_8);
+ // We're only interested in confirming that we were able to extract
+ // valid XMP data, which must always include this XML tag; a full
+ // XMP parser is beyond the scope of ExifInterface. See XMP
+ // Specification Part 1, Section C.2.2 for additional details.
+ if (!xmp.contains("<rdf:RDF")) {
+ fail("Invalid XMP: " + xmp);
+ }
+ } else {
+ assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+ }
}
private void testExifInterfaceCommon(String fileName, ExpectedValue expectedValue)
@@ -453,6 +491,12 @@
testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
}
+ public void testReadExifDataFromLgG4Iso800Jpg() throws Throwable {
+ stageFile(R.raw.lg_g4_iso_800, new File(Environment.getExternalStorageDirectory(),
+ EXTERNAL_BASE_DIRECTORY + LG_G4_ISO_800_JPG));
+ testExifInterfaceForJpeg(LG_G4_ISO_800_JPG, R.array.lg_g4_iso_800_jpg);
+ }
+
public void testDoNotFailOnCorruptedImage() throws Throwable {
// To keep the compatibility with old versions of ExifInterface, even on a corrupted image,
// it shouldn't raise any exceptions except an IOException when unable to open a file.
@@ -535,4 +579,11 @@
assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
imageFile.delete();
}
+
+ private void stageFile(int resId, File file) throws IOException {
+ try (InputStream source = getContext().getResources().openRawResource(resId);
+ OutputStream target = new FileOutputStream(file)) {
+ FileUtils.copy(source, target);
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
new file mode 100644
index 0000000..c5b3ed4
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.media.MediaFormat;
+import android.test.AndroidTestCase;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class MediaFormatTest extends AndroidTestCase {
+ private static ByteBuffer defaultByteBuffer = ByteBuffer.allocateDirect(16);
+
+ private void assertGetByteBuffersThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ ByteBuffer value = format.getByteBuffer(key);
+ throw new AssertionError("read " + type + " as ByteBuffer " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ ByteBuffer value = format.getByteBuffer(key, defaultByteBuffer);
+ throw new AssertionError("read " + type + " with default as ByteBuffer " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ private void assertGetFloatsThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ float value = format.getFloat(key);
+ throw new AssertionError("read " + type + " as float " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ float value = format.getFloat(key, 321.f);
+ throw new AssertionError("read " + type + " with default as float " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ private void assertGetIntegersThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ int value = format.getInteger(key);
+ throw new AssertionError("read " + type + " as int " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ int value = format.getInteger(key, 123);
+ throw new AssertionError("read " + type + " with default as int " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ private void assertGetLongsThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ long value = format.getLong(key);
+ throw new AssertionError("read " + type + " as long " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ long value = format.getLong(key, 321L);
+ throw new AssertionError("read " + type + " with default as long " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ private void assertGetNumbersThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ Number value = format.getNumber(key);
+ throw new AssertionError("read " + type + " as Number " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ Number value = format.getNumber(key, 321.f);
+ throw new AssertionError("read " + type + " with default as Number " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ private void assertGetStringsThrowClassCastException(
+ MediaFormat format, String key, String type) {
+ try {
+ String value = format.getString(key);
+ throw new AssertionError("read " + type + " as string " + value);
+ } catch (ClassCastException e) {
+ }
+
+ try {
+ String value = format.getString(key, "321");
+ throw new AssertionError("read " + type + " with default as string " + value);
+ } catch (ClassCastException e) {
+ }
+ }
+
+ public void testIntegerValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setInteger("int", 123);
+
+ assertEquals(123, format.getInteger("int"));
+
+ // We should be able to read int values as numbers.
+ assertEquals(123, format.getNumber("int").intValue());
+ assertEquals(123, format.getNumber("int", 321).intValue());
+
+ // We should not be able to get an integer value as any other type. Instead,
+ // we should receive a ClassCastException
+ assertGetByteBuffersThrowClassCastException(format, "int", "int");
+ assertGetFloatsThrowClassCastException(format, "int", "int");
+ assertGetLongsThrowClassCastException(format, "int", "int");
+ assertGetStringsThrowClassCastException(format, "int", "int");
+
+ // We should not have a feature enabled for an integer value
+ try {
+ boolean value = format.getFeatureEnabled("int");
+ throw new AssertionError("read int as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+
+ testSingleKeyRemoval(format, "int", MediaFormat.TYPE_INTEGER);
+ }
+
+ public void testLongValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setLong("long", 9876543210L);
+
+ assertEquals(9876543210L, format.getLong("long"));
+
+ // We should be able to read long values as numbers.
+ assertEquals(9876543210L, format.getNumber("long").longValue());
+ assertEquals(9876543210L, format.getNumber("long", 9012345678L).longValue());
+
+ // We should not be able to get a long value as any other type. Instead,
+ // we should receive a ClassCastException
+ assertGetByteBuffersThrowClassCastException(format, "long", "long");
+ assertGetFloatsThrowClassCastException(format, "long", "long");
+ assertGetIntegersThrowClassCastException(format, "long", "long");
+ assertGetStringsThrowClassCastException(format, "long", "long");
+
+ // We should not have a feature enabled for a long value
+ try {
+ boolean value = format.getFeatureEnabled("long");
+ throw new AssertionError("read long as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+
+ testSingleKeyRemoval(format, "long", MediaFormat.TYPE_LONG);
+ }
+
+ public void testFloatValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setFloat("float", 3.14f);
+
+ assertEquals(3.14f, format.getFloat("float"));
+
+ // We should be able to read float values as numbers.
+ assertEquals(3.14f, format.getNumber("float").floatValue());
+ assertEquals(3.14f, format.getNumber("float", 2.81f).floatValue());
+
+ // We should not be able to get a float value as any other type. Instead,
+ // we should receive a ClassCastException
+ assertGetByteBuffersThrowClassCastException(format, "float", "float");
+ assertGetIntegersThrowClassCastException(format, "float", "float");
+ assertGetLongsThrowClassCastException(format, "float", "float");
+ assertGetStringsThrowClassCastException(format, "float", "float");
+
+ // We should not have a feature enabled for a float value
+ try {
+ boolean value = format.getFeatureEnabled("float");
+ throw new AssertionError("read float as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+
+ testSingleKeyRemoval(format, "float", MediaFormat.TYPE_FLOAT);
+ }
+
+ public void testStringValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setString("string", "value");
+
+ assertEquals("value", format.getString("string"));
+
+ // We should not be able to get a string value as any other type. Instead,
+ // we should receive a ClassCastException
+ assertGetByteBuffersThrowClassCastException(format, "string", "string");
+ assertGetFloatsThrowClassCastException(format, "string", "string");
+ assertGetIntegersThrowClassCastException(format, "string", "string");
+ assertGetLongsThrowClassCastException(format, "string", "string");
+ assertGetNumbersThrowClassCastException(format, "string", "string");
+
+ // We should not have a feature enabled for an integer value
+ try {
+ boolean value = format.getFeatureEnabled("string");
+ throw new AssertionError("read string as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+
+ testSingleKeyRemoval(format, "string", MediaFormat.TYPE_STRING);
+ }
+
+ public void testByteBufferValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ ByteBuffer buffer = ByteBuffer.allocateDirect(123);
+ format.setByteBuffer("buffer", buffer);
+
+ assertEquals(buffer, format.getByteBuffer("buffer"));
+
+ // We should not be able to get a string value as any other type. Instead,
+ // we should receive a ClassCastException
+ assertGetFloatsThrowClassCastException(format, "buffer", "ByteBuffer");
+ assertGetIntegersThrowClassCastException(format, "buffer", "ByteBuffer");
+ assertGetLongsThrowClassCastException(format, "buffer", "ByteBuffer");
+ assertGetNumbersThrowClassCastException(format, "buffer", "ByteBuffer");
+ assertGetStringsThrowClassCastException(format, "buffer", "ByteBuffer");
+
+ // We should not have a feature enabled for an integer value
+ try {
+ boolean value = format.getFeatureEnabled("buffer");
+ throw new AssertionError("read ByteBuffer as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+
+ testSingleKeyRemoval(format, "buffer", MediaFormat.TYPE_BYTE_BUFFER);
+ }
+
+ public void testNullStringValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setString("null", null);
+ testNullOrMissingValue(format, "null");
+ testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+ }
+
+ public void testNullByteBufferValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ format.setByteBuffer("null", null);
+ testNullOrMissingValue(format, "null");
+ testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+ }
+
+ public void testMissingValue() throws Exception {
+ MediaFormat format = new MediaFormat();
+ // null values should be handled the same as missing values
+ assertEquals(MediaFormat.TYPE_NULL, format.getValueTypeForKey("missing"));
+ testNullOrMissingValue(format, "missing");
+ }
+
+ private void testSingleKeyRemoval(
+ MediaFormat format, String key, @MediaFormat.Type int type) {
+ assertEquals(type, format.getValueTypeForKey(key));
+ assertTrue(format.containsKey(key));
+
+ Set<String> keySet = format.getKeys();
+ assertEquals(1, keySet.size());
+ assertTrue(keySet.contains(key));
+
+ format.removeKey(key);
+ assertFalse(format.containsKey(key));
+
+ // test that keySet is connected to the format
+ assertFalse(keySet.contains(key));
+ assertEquals(0, keySet.size());
+ }
+
+ private static Set<String> asSet(String ... values) {
+ return new HashSet<>(Arrays.asList(values));
+ }
+
+ private void assertStringSetEquals(Set<String> set, String ... expected_members) {
+ Set<String> expected = new HashSet<>(Arrays.asList(expected_members));
+ assertEquals(expected, set);
+ }
+
+ public void testKeySetContainsAndRemove() {
+ MediaFormat format = new MediaFormat();
+ format.setInteger("int", 123);
+ format.setLong("long", 9876543210L);
+ format.setFloat("float", 321.f);
+ format.setFeatureEnabled("int", true);
+ format.setFeatureEnabled("long", false);
+ format.setFeatureEnabled("float", true);
+ format.setFeatureEnabled("string", false);
+
+ Set<String> keySet = format.getKeys();
+ // test size and contains
+ assertEquals(3, keySet.size());
+ assertTrue(keySet.contains("int"));
+ assertTrue(keySet.contains("long"));
+ assertTrue(keySet.contains("float"));
+ assertFalse(keySet.contains("string"));
+ assertStringSetEquals(keySet, "int", "long", "float");
+
+ // test adding an element
+ format.setString("string", "value");
+
+ // test that key set reflects format change in size and contains
+ assertEquals(4, keySet.size());
+ assertTrue(keySet.contains("int"));
+ assertTrue(keySet.contains("long"));
+ assertTrue(keySet.contains("float"));
+ assertTrue(keySet.contains("string"));
+
+ // test iterator
+ {
+ Set<String> toFind = asSet("int", "long", "float", "string");
+ Iterator<String> it = keySet.iterator();
+ while (it.hasNext()) {
+ String k = it.next();
+ assertTrue(toFind.remove(k));
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // remove via format
+ format.removeKey("float");
+
+ // test that key set reflects format change in size and contains
+ assertEquals(3, keySet.size());
+ assertTrue(keySet.contains("int"));
+ assertTrue(keySet.contains("long"));
+ assertFalse(keySet.contains("float"));
+ assertTrue(keySet.contains("string"));
+
+ // re-test iterator after removal
+ {
+ Set<String> toFind = asSet("int", "long", "string");
+ for (String k : keySet) {
+ assertTrue(toFind.remove(k));
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // test remove
+ keySet.remove("long");
+ assertEquals(2, keySet.size());
+ assertTrue(keySet.contains("int"));
+ assertFalse(keySet.contains("long"));
+ assertFalse(keySet.contains("float"));
+ assertTrue(keySet.contains("string"));
+ assertTrue(format.containsKey("int"));
+ assertFalse(format.containsKey("long"));
+ assertFalse(format.containsKey("float"));
+ assertTrue(format.containsKey("string"));
+
+ // test iterator by its interface as well as its remove
+ {
+ Set<String> toFind = asSet("int", "string");
+ Iterator<String> it = keySet.iterator();
+ while (it.hasNext()) {
+ String k = it.next();
+ assertTrue(toFind.remove(k));
+ if (k.equals("int")) {
+ it.remove();
+ }
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // test that removing via iterator also removes from format
+ assertEquals(1, keySet.size());
+ assertFalse(keySet.contains("int"));
+ assertFalse(keySet.contains("long"));
+ assertFalse(keySet.contains("float"));
+ assertTrue(keySet.contains("string"));
+ assertFalse(format.containsKey("int"));
+ assertFalse(format.containsKey("long"));
+ assertFalse(format.containsKey("float"));
+ assertTrue(format.containsKey("string"));
+
+ // verify that features are still present
+ assertTrue(format.getFeatureEnabled("int"));
+ assertFalse(format.getFeatureEnabled("long"));
+ assertTrue(format.getFeatureEnabled("float"));
+ assertFalse(format.getFeatureEnabled("string"));
+ }
+
+ public void testFeatureKeySetContainsAndRemove() {
+ MediaFormat format = new MediaFormat();
+ format.setInteger("int", 123);
+ format.setLong("long", 9876543210L);
+ format.setFloat("float", 321.f);
+ format.setString("string", "value");
+ format.setFeatureEnabled("int", true);
+ format.setFeatureEnabled("long", false);
+ format.setFeatureEnabled("float", true);
+
+ Set<String> featureSet = format.getFeatures();
+ // test size and contains
+ assertEquals(3, featureSet.size());
+ assertTrue(featureSet.contains("int"));
+ assertTrue(featureSet.contains("long"));
+ assertTrue(featureSet.contains("float"));
+ assertFalse(featureSet.contains("string"));
+ assertStringSetEquals(featureSet, "int", "long", "float");
+
+ // test adding an element
+ format.setFeatureEnabled("string", false);
+
+ // test that key set reflects format change in size and contains
+ assertEquals(4, featureSet.size());
+ assertTrue(featureSet.contains("int"));
+ assertTrue(featureSet.contains("long"));
+ assertTrue(featureSet.contains("float"));
+ assertTrue(featureSet.contains("string"));
+
+ // test iterator
+ {
+ Set<String> toFind = asSet("int", "long", "float", "string");
+ Iterator<String> it = featureSet.iterator();
+ while (it.hasNext()) {
+ String k = it.next();
+ assertTrue(toFind.remove(k));
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // test that features cannot be removed via format as keys, even though for backward
+ // compatibility, they can be accessed as integers and can be found via containsKey
+ format.removeKey("feature-float");
+ assertEquals(4, featureSet.size());
+ assertTrue(featureSet.contains("float"));
+
+ format.removeFeature("float");
+
+ // TODO: deprecate this usage
+ assertEquals(1, format.getInteger("feature-int"));
+ assertEquals(0, format.getInteger("feature-long"));
+ assertTrue(format.containsKey("feature-int"));
+
+ // Along these lines also verify that this is not true for the getKeys() set
+ assertFalse(format.getKeys().contains("feature-int"));
+
+ // Also verify that getKeys() cannot be used to remove a feature
+ assertFalse(format.getKeys().remove("feature-int"));
+
+ // test that key set reflects format change in size and contains
+ assertEquals(3, featureSet.size());
+ assertTrue(featureSet.contains("int"));
+ assertTrue(featureSet.contains("long"));
+ assertFalse(featureSet.contains("float"));
+ assertTrue(featureSet.contains("string"));
+
+ // re-test iterator after removal
+ {
+ Set<String> toFind = asSet("int", "long", "string");
+ for (String k : featureSet) {
+ assertTrue(toFind.remove(k));
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // test remove via set
+ featureSet.remove("long");
+ assertEquals(2, featureSet.size());
+ assertTrue(featureSet.contains("int"));
+ assertFalse(featureSet.contains("long"));
+ assertFalse(featureSet.contains("float"));
+ assertTrue(featureSet.contains("string"));
+
+ assertTrue(format.containsFeature("int"));
+ assertFalse(format.containsFeature("long"));
+ assertFalse(format.containsFeature("float"));
+ assertTrue(format.containsFeature("string"));
+
+ assertTrue(format.getFeatureEnabled("int"));
+ try {
+ format.getFeatureEnabled("long");
+ fail("should not contain feature long");
+ } catch (IllegalArgumentException e) {}
+ try {
+ format.getFeatureEnabled("float");
+ fail("should not contain feature float");
+ } catch (IllegalArgumentException e) {}
+ assertFalse(format.getFeatureEnabled("string"));
+
+ // test iterator by its interface as well as its remove
+ {
+ Set<String> toFind = asSet("int", "string");
+ Iterator<String> it = featureSet.iterator();
+ while (it.hasNext()) {
+ String k = it.next();
+ assertTrue(toFind.remove(k));
+ if (k.equals("int")) {
+ it.remove();
+ }
+ }
+ assertEquals(0, toFind.size());
+ }
+
+ // test that removing via iterator also removes from format
+ assertEquals(1, featureSet.size());
+ assertFalse(featureSet.contains("int"));
+ assertFalse(featureSet.contains("long"));
+ assertFalse(featureSet.contains("float"));
+ assertTrue(featureSet.contains("string"));
+
+ assertFalse(format.containsFeature("int"));
+ assertFalse(format.containsFeature("long"));
+ assertFalse(format.containsFeature("float"));
+ assertTrue(format.containsFeature("string"));
+
+ try {
+ format.getFeatureEnabled("int");
+ fail("should not contain feature int");
+ } catch (IllegalArgumentException e) {}
+ try {
+ format.getFeatureEnabled("long");
+ fail("should not contain feature long");
+ } catch (IllegalArgumentException e) {}
+ try {
+ format.getFeatureEnabled("float");
+ fail("should not contain feature float");
+ } catch (IllegalArgumentException e) {}
+ assertFalse(format.getFeatureEnabled("string"));
+
+ // verify that keys are still present
+ assertEquals(123, format.getInteger("int"));
+ assertEquals(9876543210L, format.getLong("long"));
+ assertEquals(321.f, format.getFloat("float"));
+ assertEquals("value", format.getString("string"));
+ }
+
+ private void testNullOrMissingValue(MediaFormat format, String key) throws Exception {
+ // We should not be able to get a string value as any primitive type. Instead,
+ // we should receive a NullPointerException
+ try {
+ int value = format.getInteger(key);
+ throw new AssertionError("read " + key + " as int " + value);
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ long value = format.getLong(key);
+ throw new AssertionError("read " + key + " as long " + value);
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ float value = format.getFloat(key);
+ throw new AssertionError("read " + key + " as float " + value);
+ } catch (NullPointerException e) {
+ }
+
+ // We should get null for all object types (ByteBuffer, Number, String)
+ assertNull(format.getNumber(key));
+ assertNull(format.getString(key));
+ assertNull(format.getByteBuffer(key));
+
+ // We should get the default value for all getters with default
+ assertEquals(123, format.getInteger(key, 123));
+ assertEquals(321L, format.getLong(key, 321L));
+ assertEquals(321.f, format.getFloat(key, 321.f));
+ assertEquals(321.f, format.getNumber(key, 321.f));
+ assertEquals("value", format.getString(key, "value"));
+ assertEquals(defaultByteBuffer, format.getByteBuffer(key, defaultByteBuffer));
+
+ // We should not have a feature enabled for a null value
+ try {
+ boolean value = format.getFeatureEnabled(key);
+ throw new AssertionError("read " + key + " as feature " + value);
+ } catch (IllegalArgumentException e) {
+ }
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 0d1796a..c19dba5 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -464,9 +464,8 @@
verifyAttributesMatch(srcMedia, outputMediaFile, degrees);
verifyLocationInFile(outputMediaFile);
}
- // Check the sample on 1s and 0.5s.
- verifySamplesMatch(srcMedia, outputMediaFile, 1000000);
- verifySamplesMatch(srcMedia, outputMediaFile, 500000);
+ // Verify timestamp of all samples.
+ verifyTimestampsWithSamplesDropSet(srcMedia, outputMediaFile, null, null);
} finally {
new File(outputMediaFile).delete();
}
@@ -1003,15 +1002,12 @@
}
extractorSrc.selectTrack(videoTrackIndex);
extractorTest.selectTrack(videoTrackIndex);
+ checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
+ videoStartOffsetUs);
+ extractorSrc.unselectTrack(videoTrackIndex);
+ extractorTest.unselectTrack(videoTrackIndex);
}
}
- if (videoTrackIndex != -1) {
- checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
- videoStartOffsetUs);
- }
-
- extractorSrc.unselectTrack(videoTrackIndex);
- extractorTest.unselectTrack(videoTrackIndex);
int audioTrackIndex = -1;
int audioSampleCount = 0;
@@ -1026,14 +1022,10 @@
}
extractorSrc.selectTrack(audioTrackIndex);
extractorTest.selectTrack(audioTrackIndex);
+ checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
}
}
- if (audioTrackIndex != -1) {
- // No audio track
- checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
- }
-
extractorSrc.release();
extractorTest.release();
srcFd.close();
@@ -1057,10 +1049,10 @@
srcSampleTimeUs = extractorSrc.getSampleTime();
testSampleTimeUs = extractorTest.getSampleTime();
if (VERBOSE) {
- Log.d(TAG, "videoSampleCount:" + videoSampleCount);
- Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
+ Log.i(TAG, "videoSampleCount:" + videoSampleCount);
+ Log.i(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
" testTrackIndex:" + extractorTest.getSampleTrackIndex());
- Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
+ Log.i(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
}
if (samplesDropSet == null || !samplesDropSet.contains(videoSampleCount)) {
if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
@@ -1114,6 +1106,7 @@
srcSampleTimeUs = extractorSrc.getSampleTime();
testSampleTimeUs = extractorTest.getSampleTime();
if(VERBOSE) {
+ Log.d(TAG, "audioSampleCount:" + audioSampleCount);
Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
" testTrackIndex:" + extractorTest.getSampleTrackIndex());
Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
@@ -1137,22 +1130,12 @@
else if ((audioSampleCount > 1 &&
(srcSampleTimeUs + audioStartOffsetUs) != testSampleTimeUs) ||
(audioSampleCount == 1 && srcSampleTimeUs != testSampleTimeUs)) {
- if (VERBOSE) {
- Log.d(TAG, "Fail:audio timestamps didn't match");
- Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
- " testTrackIndex:" + extractorTest.getSampleTrackIndex());
- Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
- Log.d(TAG, "audioSampleCount:" + audioSampleCount);
- }
fail("audio timestamps didn't match");
}
testAdvance = extractorTest.advance();
srcAdvance = extractorSrc.advance();
} while(srcAdvance && testAdvance);
if (srcAdvance != testAdvance) {
- if (VERBOSE) {
- Log.d(TAG, "audioSampleCount:" + audioSampleCount);
- }
fail("either audio track has not reached its last sample");
}
}
diff --git a/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
new file mode 100644
index 0000000..aa9894f
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresDevice;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+@SmallTest
+@RequiresDevice
+public class SurfaceEncodeTimestampTest extends AndroidTestCase {
+ private static final String TAG = SurfaceEncodeTimestampTest.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private static final Color COLOR_BLOCK =
+ Color.valueOf(1.0f, 1.0f, 1.0f);
+ private static final Color[] COLOR_BARS = {
+ Color.valueOf(0.0f, 0.0f, 0.0f),
+ Color.valueOf(0.0f, 0.0f, 0.64f),
+ Color.valueOf(0.0f, 0.64f, 0.0f),
+ Color.valueOf(0.0f, 0.64f, 0.64f),
+ Color.valueOf(0.64f, 0.0f, 0.0f),
+ Color.valueOf(0.64f, 0.0f, 0.64f),
+ Color.valueOf(0.64f, 0.64f, 0.0f),
+ };
+ private static final int BORDER_WIDTH = 16;
+
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+ private MediaCodec mEncoder;
+ private InputSurface mInputEglSurface;
+ private int mInputCount;
+
+ @Override
+ public void setUp() throws Exception {
+ if (mHandlerThread == null) {
+ mHandlerThread = new HandlerThread(
+ "EncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mHandler = null;
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ mHandlerThread = null;
+ }
+ }
+
+ /*
+ * Test KEY_MAX_PTS_GAP_TO_ENCODER
+ *
+ * This key is supposed to cap the gap between any two frames fed to the encoder,
+ * and restore the output pts back to the original. Since the pts is not supposed
+ * to be modified, we can't really verify that the "capping" actually took place.
+ * However, we can at least verify that the pts is preserved.
+ */
+ public void testMaxPtsGap() throws Throwable {
+ long[] inputPts = {1000000, 2000000, 3000000, 4000000};
+ long[] expectedOutputPts = {1000000, 2000000, 3000000, 4000000};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, 33333);
+ });
+ }
+
+ /*
+ * Test that by default backward-going frames get dropped.
+ */
+ public void testBackwardFrameDroppedWithoutFixedPtsGap() throws Throwable {
+ long[] inputPts = {33333, 66667, 66000, 100000};
+ long[] expectedOutputPts = {33333, 66667, 100000};
+ doTest(inputPts, expectedOutputPts, null);
+ }
+
+ /*
+ * Test KEY_MAX_PTS_GAP_TO_ENCODER
+ *
+ * Test that when fixed pts gap is used, backward-going frames are accepted
+ * and the pts is preserved.
+ */
+ public void testBackwardFramePreservedWithFixedPtsGap() throws Throwable {
+ long[] inputPts = {33333, 66667, 66000, 100000};
+ long[] expectedOutputPts = {33333, 66667, 66000, 100000};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, -33333);
+ });
+ }
+
+ /*
+ * Test KEY_MAX_FPS_TO_ENCODER
+ *
+ * Input frames are timestamped at 60fps, the key is supposed to drop
+ * one every other frame to maintain 30fps output.
+ */
+ public void testMaxFps() throws Throwable {
+ long[] inputPts = {16667, 33333, 50000, 66667, 83333};
+ long[] expectedOutputPts = {16667, 50000, 83333};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setFloat(MediaFormat.KEY_MAX_FPS_TO_ENCODER, 30.0f);
+ });
+ }
+
+ /*
+ * Test KEY_REPEAT_PREVIOUS_FRAME_AFTER
+ *
+ * Test that the frame is repeated at least once if no new frame arrives after
+ * the specified amount of time.
+ */
+ public void testRepeatPreviousFrameAfter() throws Throwable {
+ long[] inputPts = {16667, 33333, -100000, 133333};
+ long[] expectedOutputPts = {16667, 33333, 103333};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 70000);
+ });
+ }
+
+ /*
+ * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED and PARAMETER_KEY_SUSPEND
+ *
+ * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then resume
+ * by PARAMETER_KEY_SUSPEND. Verify only frames after resume are captured.
+ */
+ public void testCreateInputSurfaceSuspendedResume() throws Throwable {
+ // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+ // PARAMETER_KEY_SUSPEND_TIME) to resume doesn't enforce a time
+ // for the action to take effect. Due to the asynchronous operation
+ // between the MediaCodec's parameters and the input surface, frames
+ // rendered before the resume call may reach encoder input side after
+ // the resume. Here we do a slight wait (100000us) to make sure that
+ // the resume only takes effect on the frame with timestamp 100000.
+ long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+ long[] expectedOutputPts = {100000, 133333};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+ }, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+ return params;
+ });
+ }
+
+ /*
+ * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+ * PARAMETER_KEY_SUSPEND and PARAMETER_KEY_SUSPEND_TIME
+ *
+ * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then request resume
+ * at specific time using PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+ * Verify only frames after the specified time are captured.
+ */
+ public void testCreateInputSurfaceSuspendedResumeWithTime() throws Throwable {
+ // Unlike using PARAMETER_KEY_SUSPEND alone to resume, using PARAMETER_KEY_SUSPEND
+ // + PARAMETER_KEY_SUSPEND_TIME to resume can be scheduled any time before the
+ // frame with the specified time arrives. Here we do it immediately after start.
+ long[] inputPts = {-1, 33333, 66667, 100000, 133333};
+ long[] expectedOutputPts = {100000, 133333};
+ doTest(inputPts, expectedOutputPts, (format) -> {
+ format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+ }, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+ params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+ return params;
+ });
+ }
+
+ /*
+ * Test PARAMETER_KEY_SUSPEND.
+ *
+ * Suspend/resume during capture, and verify that frames during the suspension
+ * period are dropped.
+ */
+ public void testSuspendedResume() throws Throwable {
+ // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+ // PARAMETER_KEY_SUSPEND_TIME) to suspend/resume doesn't enforce a time
+ // for the action to take effect. Due to the asynchronous operation
+ // between the MediaCodec's parameters and the input surface, frames
+ // rendered before the request may reach encoder input side after
+ // the request. Here we do a slight wait (100000us) to make sure that
+ // the suspend/resume only takes effect on the next frame.
+ long[] inputPts = {33333, 66667, -100000, 100000, 133333, -100000, 166667};
+ long[] expectedOutputPts = {33333, 66667, 166667};
+ doTest(inputPts, expectedOutputPts, null, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+ return params;
+ }, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+ return params;
+ });
+ }
+
+ /*
+ * Test PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+ *
+ * Suspend/resume with specified time during capture, and verify that frames during
+ * the suspension period are dropped.
+ */
+ public void testSuspendedResumeWithTime() throws Throwable {
+ // Unlike using PARAMETER_KEY_SUSPEND alone to suspend/resume, requests using
+ // PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME can be scheduled any time
+ // before the frame with the specified time arrives. Queue both requests shortly
+ // after start and test that they take place at the proper frames.
+ long[] inputPts = {-1, 33333, -1, 66667, 100000, 133333, 166667};
+ long[] expectedOutputPts = {33333, 66667, 166667};
+ doTest(inputPts, expectedOutputPts, null, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+ params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+ return params;
+ }, () -> {
+ Bundle params = new Bundle();
+ params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+ params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 166667);
+ return params;
+ });
+ }
+
+ /*
+ * Test PARAMETER_KEY_OFFSET_TIME.
+ *
+ * Apply PARAMETER_KEY_OFFSET_TIME during capture, and verify that the pts
+ * of frames after the request are adjusted by the offset correctly.
+ */
+ public void testOffsetTime() throws Throwable {
+ long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+ long[] expectedOutputPts = {33333, 66667, 83333, 116666};
+ doTest(inputPts, expectedOutputPts, null, () -> {
+ Bundle params = new Bundle();
+ params.putLong(MediaCodec.PARAMETER_KEY_OFFSET_TIME, -16667);
+ return params;
+ });
+ }
+
+ private void doTest(long[] inputPtsUs, long[] expectedOutputPtsUs,
+ Consumer<MediaFormat> configSetter, Supplier<Bundle>... paramGetter) throws Exception {
+
+ try {
+ if (DEBUG) Log.d(TAG, "started");
+
+ // setup surface encoder format
+ mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
+ MediaFormat codecFormat = MediaFormat.createVideoFormat(
+ MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
+ codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
+ codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ CodecCapabilities.COLOR_FormatSurface);
+ codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+ codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+ MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
+ codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000);
+
+ if (configSetter != null) {
+ configSetter.accept(codecFormat);
+ }
+
+ CountDownLatch latch = new CountDownLatch(1);
+
+ // configure and start encoder
+ long[] actualOutputPtsUs = new long[expectedOutputPtsUs.length];
+ mEncoder.setCallback(new EncoderCallback(latch, actualOutputPtsUs), mHandler);
+ mEncoder.configure(codecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+ mInputEglSurface = new InputSurface(mEncoder.createInputSurface());
+
+ mEncoder.start();
+
+ mInputCount = 0;
+ int paramIndex = 0;
+ // perform input operations
+ for (int i = 0; i < inputPtsUs.length; i++) {
+ if (DEBUG) Log.d(TAG, "drawFrame: " + i + ", pts " + inputPtsUs[i]);
+
+ if (inputPtsUs[i] < 0) {
+ if (inputPtsUs[i] < -1) {
+ // larger negative number means that a sleep is required
+ // before the parameter test.
+ Thread.sleep(-inputPtsUs[i]/1000);
+ }
+ if (paramIndex < paramGetter.length && paramGetter[paramIndex] != null) {
+ // this means a pause to apply parameter to be tested
+ mEncoder.setParameters(paramGetter[paramIndex].get());
+ }
+ paramIndex++;
+ } else {
+ drawFrame(1280, 720, inputPtsUs[i]);
+ }
+ }
+
+ // if it worked there is really no reason to take longer..
+ latch.await(1000, TimeUnit.MILLISECONDS);
+
+ // verify output timestamps
+ assertTrue("mismatch in output timestamp",
+ Arrays.equals(expectedOutputPtsUs, actualOutputPtsUs));
+
+ if (DEBUG) Log.d(TAG, "stopped");
+ } finally {
+ if (mEncoder != null) {
+ mEncoder.stop();
+ mEncoder.release();
+ mEncoder = null;
+ }
+ if (mInputEglSurface != null) {
+ // This also releases the surface from encoder.
+ mInputEglSurface.release();
+ mInputEglSurface = null;
+ }
+ }
+ }
+
+ class EncoderCallback extends MediaCodec.Callback {
+ private boolean mOutputEOS;
+ private int mOutputCount;
+ private final CountDownLatch mLatch;
+ private final long[] mActualOutputPts;
+ private final int mMaxOutput;
+
+ EncoderCallback(CountDownLatch latch, long[] actualOutputPts) {
+ mLatch = latch;
+ mActualOutputPts = actualOutputPts;
+ mMaxOutput = actualOutputPts.length;
+ }
+
+ @Override
+ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+ if (codec != mEncoder) return;
+ if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
+ }
+
+ @Override
+ public void onInputBufferAvailable(MediaCodec codec, int index) {
+ if (codec != mEncoder) return;
+ if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
+ }
+
+ @Override
+ public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
+ if (codec != mEncoder || mOutputEOS) return;
+
+ if (DEBUG) {
+ Log.d(TAG, "onOutputBufferAvailable: " + index
+ + ", time " + info.presentationTimeUs
+ + ", size " + info.size
+ + ", flags " + info.flags);
+ }
+
+ if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
+ mActualOutputPts[mOutputCount++] = info.presentationTimeUs;
+ }
+
+ mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) ||
+ (mOutputCount == mMaxOutput);
+
+ codec.releaseOutputBuffer(index, false);
+
+ if (mOutputEOS) {
+ stopAndNotify(null);
+ }
+ }
+
+ @Override
+ public void onError(MediaCodec codec, CodecException e) {
+ if (codec != mEncoder) return;
+
+ Log.e(TAG, "onError: " + e);
+ stopAndNotify(e);
+ }
+
+ private void stopAndNotify(CodecException e) {
+ mLatch.countDown();
+ }
+ }
+
+ private void drawFrame(int width, int height, long ptsUs) {
+ mInputEglSurface.makeCurrent();
+ generateSurfaceFrame(mInputCount, width, height);
+ mInputEglSurface.setPresentationTime(1000 * ptsUs);
+ mInputEglSurface.swapBuffers();
+ mInputCount++;
+ }
+
+ private static Rect getColorBarRect(int index, int width, int height) {
+ int barWidth = (width - BORDER_WIDTH * 2) / COLOR_BARS.length;
+ return new Rect(BORDER_WIDTH + barWidth * index, BORDER_WIDTH,
+ BORDER_WIDTH + barWidth * (index + 1), height - BORDER_WIDTH);
+ }
+
+ private static Rect getColorBlockRect(int index, int width, int height) {
+ int blockCenterX = (width / 5) * (index % 4 + 1);
+ return new Rect(blockCenterX - width / 10, height / 6,
+ blockCenterX + width / 10, height / 3);
+ }
+
+ private void generateSurfaceFrame(int frameIndex, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
+ GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+ GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+
+ for (int i = 0; i < COLOR_BARS.length; i++) {
+ Rect r = getColorBarRect(i, width, height);
+
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ final Color color = COLOR_BARS[i];
+ GLES20.glClearColor(color.red(), color.green(), color.blue(), 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+
+ Rect r = getColorBlockRect(frameIndex, width, height);
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ r.inset(BORDER_WIDTH, BORDER_WIDTH);
+ GLES20.glScissor(r.left, r.top, r.width(), r.height());
+ GLES20.glClearColor(COLOR_BLOCK.red(), COLOR_BLOCK.green(), COLOR_BLOCK.blue(), 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ }
+}
diff --git a/tests/tests/multiuser/AndroidTest.xml b/tests/tests/multiuser/AndroidTest.xml
index 595fcd5..8edf9d6 100644
--- a/tests/tests/multiuser/AndroidTest.xml
+++ b/tests/tests/multiuser/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMultiUserTestCases.apk" />
diff --git a/tests/tests/neuralnetworks/benchmark/Android.mk b/tests/tests/neuralnetworks/benchmark/Android.mk
index 9670236..067db34 100644
--- a/tests/tests/neuralnetworks/benchmark/Android.mk
+++ b/tests/tests/neuralnetworks/benchmark/Android.mk
@@ -29,7 +29,7 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test androidx.test.rules \
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test \
compatibility-device-util ctstestrunner junit NeuralNetworksApiBenchmark_Lib
LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni
diff --git a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
index be6d40e..827b5dd 100644
--- a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
+++ b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
@@ -23,10 +23,9 @@
import android.os.Bundle;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
import android.util.Pair;
-import androidx.test.InstrumentationRegistry;
-
import com.android.nn.benchmark.core.BenchmarkException;
import com.android.nn.benchmark.core.BenchmarkResult;
import com.android.nn.benchmark.core.InferenceInOutSequence;
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 2292392..836214c 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -4410,9 +4410,9 @@
<permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
android:protectionLevel="signature|privileged" />
- <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. -->
- <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
- android:protectionLevel="signature" />
+ <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+ <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
+ android:protectionLevel="signature" />
<!-- @hide Permission that allows background clipboard access.
<p>Not for use by third-party applications. -->
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 9613c15..13caf39 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -206,7 +206,7 @@
boolean[] successful = new boolean[1];
CountDownLatch latch = new CountDownLatch(1);
runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
successful[0] = true;
@@ -229,7 +229,7 @@
boolean[] successful = new boolean[1];
CountDownLatch latch = new CountDownLatch(1);
runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
successful[0] = true;
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index f2f6a46..512330b 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<!-- Instant apps can't access ShortcutManager -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsShortcutManagerTestCases.apk" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index d3e0958..ef7a9ec 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -180,7 +180,7 @@
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
try {
@@ -209,7 +209,7 @@
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
try {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 27a7010..3abf52f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -163,7 +163,7 @@
Executor executor = mContext.getMainExecutor();
LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
runWithShellPermissionIdentity(() -> {
- mRoleManager.addRoleHolderAsUser(roleName, packageName, user, executor,
+ mRoleManager.addRoleHolderAsUser(roleName, packageName, 0, user, executor,
new RoleManagerCallback() {
@Override
public void onSuccess() {
@@ -186,7 +186,7 @@
Executor executor = mContext.getMainExecutor();
LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
runWithShellPermissionIdentity(() -> {
- mRoleManager.removeRoleHolderAsUser(roleName, packageName, user, executor,
+ mRoleManager.removeRoleHolderAsUser(roleName, packageName, 0, user, executor,
new RoleManagerCallback() {
@Override
public void onSuccess() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 7d1bae2..83f3995 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -454,7 +454,7 @@
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
try {
@@ -483,7 +483,7 @@
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
- packageName, user, executor, new RoleManagerCallback() {
+ packageName, 0, user, executor, new RoleManagerCallback() {
@Override
public void onSuccess() {
try {
diff --git a/tests/tests/transition/AndroidTest.xml b/tests/tests/transition/AndroidTest.xml
index e75e8de..cac2338 100644
--- a/tests/tests/transition/AndroidTest.xml
+++ b/tests/tests/transition/AndroidTest.xml
@@ -16,6 +16,9 @@
<configuration description="Config for CTS Transition test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+ <!-- There is no difference between instant apps and installed apps with
+ respect to transition tests, so don't run these in instant apps. -->
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsTransitionTestCases.apk" />
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index 71bb9f1..cabe7bf 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -71,7 +71,7 @@
private void resetChangeBoundsTransition() {
mListener = mock(Transition.TransitionListener.class);
mChangeBounds = new MyChangeBounds();
- mChangeBounds.setDuration(500);
+ mChangeBounds.setDuration(1000);
mChangeBounds.addListener(mListener);
mChangeBounds.setInterpolator(new LinearInterpolator());
mTransition = mChangeBounds;
diff --git a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
index c1248a5..70da07f 100644
--- a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
@@ -51,7 +51,7 @@
private void resetTransition() {
mExplode = new Explode();
- mExplode.setDuration(500);
+ mExplode.setDuration(1000);
mTransition = mExplode;
resetListener();
}
diff --git a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
index 63db5ef..dc4be47 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
@@ -72,7 +72,7 @@
for (int i = 0; i < sSlideEdgeArray.length; i++) {
final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
final Slide slide = new Slide(slideEdge);
- slide.setDuration(500);
+ slide.setDuration(1000);
final Transition.TransitionListener listener =
mock(Transition.TransitionListener.class);
slide.addListener(listener);
@@ -107,7 +107,7 @@
});
});
verify(listener, within(1000)).onTransitionStart(any());
- verify(listener, within(1000)).onTransitionEnd(any());
+ verify(listener, within(2000)).onTransitionEnd(any());
verifyMovement(redPoints, slideEdge, false);
verifyMovement(greenPoints, slideEdge, false);
@@ -128,7 +128,7 @@
for (int i = 0; i < sSlideEdgeArray.length; i++) {
final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
final Slide slide = new Slide(slideEdge);
- slide.setDuration(500);
+ slide.setDuration(1000);
final Transition.TransitionListener listener =
mock(Transition.TransitionListener.class);
slide.addListener(listener);
@@ -172,7 +172,7 @@
});
});
verify(listener, within(1000)).onTransitionStart(any());
- verify(listener, within(1000)).onTransitionEnd(any());
+ verify(listener, within(2000)).onTransitionEnd(any());
verifyMovement(redPoints, slideEdge, true);
verifyMovement(greenPoints, slideEdge, true);
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
index e401e88..bf8c7f7 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -16,7 +16,6 @@
package android.transition.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -77,6 +76,8 @@
enterScene(R.layout.scene1);
final CountDownLatch startLatch = new CountDownLatch(1);
final Scene scene6 = loadScene(R.layout.scene6);
+
+ final CountDownLatch moveLatch = watchForRedSquareMoving();
mActivityRule.runOnUiThread(() -> {
mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@@ -91,37 +92,56 @@
scene6.enter();
});
assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
- ensureRedSquareIsMoving();
+ assertTrue(moveLatch.await(1000, TimeUnit.MILLISECONDS));
endTransition();
}
- private void ensureRedSquareIsMoving() throws InterruptedException {
- final View view = mActivity.findViewById(R.id.redSquare);
- assertNotNull(view);
- // We should see a ChangeBounds on redSquare
- final Rect position = new Rect(view.getLeft(), view.getTop(), view.getRight(),
- view.getBottom());
-
+ private CountDownLatch watchForRedSquareMoving() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
- final Rect[] nextArr = new Rect[1];
- view.postOnAnimation(new Runnable() {
- // Wait at most 10 frames for the position to change
- int mFramesToChange = 10;
- @Override
- public void run() {
- nextArr[0] = new Rect(view.getLeft(), view.getTop(), view.getRight(),
- view.getBottom());
- mFramesToChange--;
- if (nextArr[0].equals(position) && mFramesToChange > 0) {
- view.postOnAnimation(this);
- } else {
- latch.countDown();
- }
- }
+ mActivityRule.runOnUiThread(() -> {
+ final View decor = mActivity.getWindow().getDecorView();
+ final View viewBeforeTransition = mActivity.findViewById(R.id.redSquare);
+ decor.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ // Wait at most 20 frames for the position to change
+ int mFramesToChange = 20;
+ Rect mLastPosition = null;
+ View mView = null;
+ int mPositionChanges = 0;
+
+ @Override
+ public boolean onPreDraw() {
+ final View view = mActivity.findViewById(R.id.redSquare);
+ if (mView == null && view != viewBeforeTransition) {
+ // Capture the new red square View. It will be in the end
+ // position now, so don't capture its position.
+ mView = view;
+ return true;
+ }
+ Rect nextPosition = new Rect(view.getLeft(), view.getTop(),
+ view.getRight(), view.getBottom());
+ if (mLastPosition == null) {
+ // This is the start position
+ mLastPosition = nextPosition;
+ return true;
+ }
+ mFramesToChange--;
+ if (!nextPosition.equals(mLastPosition)) {
+ mPositionChanges++;
+ mLastPosition = nextPosition;
+ if (mPositionChanges > 2) {
+ latch.countDown();
+ }
+ }
+ if (mFramesToChange <= 0 || mPositionChanges > 2) {
+ decor.getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ return true;
+ }
+ });
});
- assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
- assertNotEquals(position, nextArr[0]);
+ return latch;
}
@Test
@@ -149,6 +169,7 @@
enterScene(R.layout.scene1);
final CountDownLatch startLatch = new CountDownLatch(1);
final Scene scene6 = loadScene(R.layout.scene6);
+ final CountDownLatch moveLatch = watchForRedSquareMoving();
mActivityRule.runOnUiThread(() -> {
mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@@ -162,7 +183,7 @@
TransitionManager.go(scene6);
});
assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
- ensureRedSquareIsMoving();
+ assertTrue(moveLatch.await(1000, TimeUnit.MILLISECONDS));
endTransition();
}
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
index 2c2e951..d200299 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -70,6 +70,14 @@
@MediumTest
@RunWith(AndroidJUnit4.class)
public class TransitionTest extends BaseTransitionTest {
+ @Override
+ public void setup() {
+ super.setup();
+ // We want to be able to catch the transition in the middle of running, so
+ // it should be long enough that devices can catch it without trouble.
+ mTransition.setDuration(1000);
+ }
+
@Test
public void testAddListener() throws Throwable {
startTransition(R.layout.scene1);
@@ -103,13 +111,14 @@
@Test
public void testRemoveListener() throws Throwable {
+ TransitionListener listener = mock(TransitionListener.class);
+ mTransition.addListener(listener);
startTransition(R.layout.scene1);
waitForStart();
- mActivityRule.runOnUiThread(() -> mTransition.removeListener(mListener));
-
- SystemClock.sleep(250);
- verify(mListener, never()).onTransitionEnd(any());
+ mActivityRule.runOnUiThread(() -> mTransition.removeListener(listener));
+ waitForEnd(2000);
+ mActivityRule.runOnUiThread(() -> verify(listener, never()).onTransitionEnd(any()));
}
@Test
@@ -360,7 +369,7 @@
View redSquare1 = layout1.findViewById(R.id.redSquare);
mTransition.excludeTarget(redSquare1, true);
startTransition(R.layout.scene7);
- waitForEnd(600);
+ waitForEnd(2000);
mTransition.excludeTarget(redSquare1, false); // remove it
resetListener();
@@ -422,21 +431,22 @@
@Test
public void testDuration() throws Throwable {
- assertEquals(-1, mTransition.getDuration());
+ Transition transition = new AutoTransition();
+ assertEquals(-1, transition.getDuration());
enterScene(R.layout.scene1);
- mTransition.setDuration(500);
- assertEquals(500, mTransition.getDuration());
+ mTransition.setDuration(1000);
+ assertEquals(1000, mTransition.getDuration());
DurationListener durationListener = new DurationListener();
mTransition.addListener(durationListener);
startTransition(R.layout.scene3);
waitForEnd(5000);
// We can't be certain that the onTransitionStart() and onTransitionEnd()
- // are going to be called exactly 500ms apart. There could be more of a
+ // are going to be called exactly 1000ms apart. There could be more of a
// delay at the beginning than the end. So, we give it some room at the
// minimum. It can also take a lot longer on the larger side because of
// slow devices.
assertThat(durationListener.getDuration(),
- allOf(greaterThanOrEqualTo(400L), lessThan(900L)));
+ allOf(greaterThanOrEqualTo(500L), lessThan(2000L)));
}
@Test
@@ -468,7 +478,7 @@
assertFalse(transition.animators.isEmpty());
Animator animator = transition.animators.get(redSquare);
Animator.AnimatorListener listener = transition.listeners.get(redSquare);
- verify(listener, within(100)).onAnimationStart(any(), eq(false));
+ verify(listener, within(1000)).onAnimationStart(any(), eq(false));
assertSame(interpolator, animator.getInterpolator());
endTransition();
}
@@ -525,7 +535,7 @@
Animator redSquareAnimator = transition.animators.get(redSquare);
Animator greenSquareAnimator = transition.animators.get(greenSquare);
Animator.AnimatorListener listener = transition.listeners.get(redSquare);
- verify(listener, within(100)).onAnimationStart(any(), eq(false));
+ verify(listener, within(1000)).onAnimationStart(any(), eq(false));
assertEquals(0, redSquareAnimator.getStartDelay());
assertEquals(diffTop, greenSquareAnimator.getStartDelay());
endTransition();
@@ -569,8 +579,8 @@
mTransition.setDuration(10);
resetListener();
startTransition(R.layout.scene2);
- assertTrue(transition.onDisappearCalled.await(500, TimeUnit.MILLISECONDS));
- assertTrue(transition.onAppearCalled.await(500, TimeUnit.MILLISECONDS));
+ assertTrue(transition.onDisappearCalled.await(2000, TimeUnit.MILLISECONDS));
+ assertTrue(transition.onAppearCalled.await(2000, TimeUnit.MILLISECONDS));
// The transition has all the asserts in it, so we can just end it now.
endTransition();
}
@@ -583,7 +593,7 @@
startTransition(R.layout.scene8);
// scene 8 swaps the ids, but not the names. No transition should happen.
- waitForEnd(1000);
+ waitForEnd(2000);
// now change the match order to prefer the id
mTransition.setMatchOrder(new int[] {Transition.MATCH_ID, Transition.MATCH_NAME});
@@ -591,7 +601,7 @@
resetListener();
startTransition(R.layout.scene1);
verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
- waitForEnd(1000);
+ waitForEnd(2000);
}
@Test
@@ -602,7 +612,7 @@
mTransition = transition;
resetListener();
startTransition(R.layout.scene2);
- assertTrue(transition.latch.await(500, TimeUnit.MILLISECONDS));
+ assertTrue(transition.latch.await(2000, TimeUnit.MILLISECONDS));
endTransition();
// Now make the transition only make changes to unimportant properties.
@@ -610,7 +620,7 @@
mTransition = transition;
resetListener();
startTransition(R.layout.scene1);
- verify(mListener, within(500)).onTransitionEnd(any());
+ verify(mListener, within(2000)).onTransitionEnd(any());
// createAnimator shouldn't have been called.
assertEquals(1, transition.latch.getCount());
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerTest.java b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
index a232b51..2adbc13 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
@@ -81,15 +81,15 @@
Choreographer.CALLBACK_ANIMATION, removedCallback, null);
// We expect the remaining callbacks to have been invoked once.
- verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(1)).run();
- verify(addedCallback2, timeout(NOMINAL_VSYNC_PERIOD * 10).times(1)).run();
+ verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(1)).run();
+ verify(addedCallback2, timeout(NOMINAL_VSYNC_PERIOD * 30).times(1)).run();
verifyZeroInteractions(removedCallback);
// If we post a callback again, then it should be invoked again.
mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
- verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(2)).run();
+ verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(2)).run();
verify(addedCallback2, times(1)).run();
verifyZeroInteractions(removedCallback);
@@ -100,7 +100,7 @@
Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, null, TOKEN);
- verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(3)).run();
+ verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(3)).run();
verifyZeroInteractions(removedCallback);
// If the action and token matches, then the callback should be removed.
@@ -111,7 +111,7 @@
Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
- verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(4)).run();
+ verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(4)).run();
verifyZeroInteractions(removedCallback);
} finally {
mChoreographer.removeCallbacks(
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
index 8e34571..484644f 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
@@ -313,7 +313,7 @@
assertThat(request.getConversation().get(0).getText().toString()).isEqualTo(TEXT);
assertThat(request.getConversation().get(0).getAuthor()).isEqualTo(PERSON);
assertThat(request.getHints()).isEmpty();
- assertThat(request.getMaxSuggestions()).isEqualTo(0);
+ assertThat(request.getMaxSuggestions()).isEqualTo(-1);
assertThat(request.getTypeConfig()).isNotNull();
assertThat(request.getConversationId()).isNull();
}
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 5b97823..7bdb094 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -16,6 +16,8 @@
<configuration description="Config for CTS Voice Settings test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
@@ -27,7 +29,9 @@
<!-- Close the "turn on battery saver?" dialog, and wait for the broadcast queue to drain. -->
<option name="teardown-command" value="am broadcast --receiver-foreground -a android.intent.action.CLOSE_SYSTEM_DIALOGS" />
+ <!-- TODO(b/123958025): disabled because it hangs most of the time
<option name="teardown-command" value="am wait-for-broadcast-idle" />
+ -->
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.voicesettings.cts" />
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index db6bbb9..2ef1999 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -40,6 +40,7 @@
super.setUp();
mContext = getInstrumentation().getTargetContext();
mHasFeature = mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS);
+ Log.v(TAG, "setUp(): mHasFeature=" + mHasFeature);
}
public AirplaneModeTest() {
@@ -84,6 +85,7 @@
}
runTest(BroadcastUtils.TestcaseType.AIRPLANE_MODE_ON, AIRPLANE_MODE_IS_ON);
}
+ Log.i(TAG, "All done!");
}
private boolean runTest(BroadcastUtils.TestcaseType test, int expectedMode) throws Exception {
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 5a68273..1904710 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -559,6 +559,38 @@
assertEquals(oldSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
}
+ @UiThreadTest
+ @Test
+ public void testGetAndSetMinWidth() {
+ final int minWidth = 20;
+ mProgressBar.setMinWidth(minWidth);
+ assertEquals(minWidth, mProgressBar.getMinWidth());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testGetAndSetMaxWidth() {
+ final int maxWidth = 20;
+ mProgressBar.setMaxWidth(maxWidth);
+ assertEquals(maxWidth, mProgressBar.getMaxWidth());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testGetAndSetMinHeight() {
+ final int minHeight = 20;
+ mProgressBar.setMinHeight(minHeight);
+ assertEquals(minHeight, mProgressBar.getMinHeight());
+ }
+
+ @UiThreadTest
+ @Test
+ public void testGetAndSetMaxHeight() {
+ final int maxHeight = 20;
+ mProgressBar.setMaxHeight(maxHeight);
+ assertEquals(maxHeight, mProgressBar.getMaxHeight());
+ }
+
/*
* Mock class for ProgressBar to test protected methods
*/
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 3abb023..bae62ed 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -800,6 +800,22 @@
assertTrue(myScrollView.getBottomFadingEdgeStrength() >= 0.0f);
}
+ @Test
+ public void testScrollDescendant() throws Throwable {
+ assertEquals(0, mScrollViewCustom.getScrollX());
+ assertEquals(0, mScrollViewCustom.getScrollY());
+
+ View lastChild = mScrollViewCustom.findViewById(R.id.last_child);
+ int lastChildTop = (ITEM_COUNT - 1) * mItemHeight;
+
+ mActivityRule.runOnUiThread(() -> mScrollViewCustom.scrollToDescendant(lastChild));
+ // smoothScrollBy doesn't scroll in X
+ pollingCheckSmoothScrolling(0, 0, 0, lastChildTop);
+
+ assertEquals(0, mScrollViewCustom.getScrollX());
+ assertEquals(lastChildTop, mScrollViewCustom.getScrollY());
+ }
+
private boolean isInRange(int current, int from, int to) {
if (from < to) {
return current >= from && current <= to;