Merge "Add CTS tests to ensure platform extensions are present" into nyc-dev
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 6c89b11..185059e 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -23,6 +23,8 @@
CtsNetSecPolicyUsesCleartextTrafficFalse \
CtsNetSecPolicyUsesCleartextTrafficTrue \
CtsNetSecPolicyUsesCleartextTrafficUnspecified \
+ CtsNoRestartBase \
+ CtsNoRestartFeature \
CtsUsePermissionApp \
CtsUsePermissionAppCompat \
CtsPermissionDeclareApp \
@@ -46,6 +48,7 @@
CtsSplitAppFeature \
CtsTargetInstrumentationApp \
CtsUsePermissionDiffCert \
+ CtsUsesLibraryApp \
CtsWriteExternalStorageApp \
CtsMultiUserStorageApp
@@ -290,7 +293,8 @@
CtsJdwpApp
cts_target_junit_tests := \
- CtsJdwp
+ CtsJdwp \
+ CtsLibcoreOj
cts_deqp_test_apis := \
egl \
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 3ed908e..7239c9a 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -62,6 +62,9 @@
"scene5" : "Capture images with a diffuser attached to the camera. See "
"CameraITS.pdf section 2.3.4 for more details"
}
+ scene_extra_args = {
+ "scene5" : ["doAF=False"]
+ }
tests = []
for d in scenes:
tests += [(d,s[:-3],os.path.join("tests", d, s))
@@ -120,9 +123,11 @@
out_path = os.path.join(topdir, camera_id, scene+".jpg")
out_arg = "out=" + out_path
scene_arg = "scene=" + scene_req[scene]
+ extra_args = scene_extra_args.get(scene, [])
cmd = ['python',
os.path.join(os.getcwd(),"tools/validate_scene.py"),
- camera_id_arg, out_arg, scene_arg, device_id_arg]
+ camera_id_arg, out_arg, scene_arg, device_id_arg] + \
+ extra_args
retcode = subprocess.call(cmd,cwd=topdir)
assert(retcode == 0)
print "Start running tests for", scene
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index 1f35163..cfe14e2 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -26,6 +26,7 @@
out_path = ""
scene_name = ""
scene_desc = "No requirement"
+ do_af = True
for s in sys.argv[1:]:
if s[:7] == "camera=" and len(s) > 7:
camera_id = s[7:]
@@ -33,6 +34,8 @@
out_path = s[4:]
elif s[:6] == "scene=" and len(s) > 6:
scene_desc = s[6:]
+ elif s[:5] == "doAF=" and len(s) > 5:
+ do_af = s[5:] == "True"
if out_path != "":
scene_name = re.split("/|\.", out_path)[-2]
@@ -46,7 +49,7 @@
" to frame the test scene: " + scene_name +
"\nThe scene setup should be: " + scene_desc )
# Converge 3A prior to capture.
- cam.do_3a(do_af=True, lock_ae=True, lock_awb=True)
+ cam.do_3a(do_af=do_af, lock_ae=True, lock_awb=True)
props = cam.get_camera_properties()
req = its.objects.fastest_auto_capture_request(props)
if its.caps.ae_lock(props):
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 02466c9..ca525ee 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1184,8 +1184,8 @@
user preferences about relative package priorities.
</string>
<string name="package_priority_bot">Verifying that the CTS Robot helper package is installed.</string>
- <string name="package_priority_high">Find \"%s\" under \"App notifications\" in the \"Sound & notifications\" settings panel, and mark it as having notification priority.</string>
- <string name="package_priority_default">Find \"%s\" under \"App notifications\" in the \"Sound & notifications\" settings panel, and make sure it has default priority.</string>
+ <string name="package_priority_high">Find \"%s\" in the \"Notifications\" settings panel, and allow it to Override Do Not Disturb.</string>
+ <string name="package_priority_default">Find \"%s\" in the \"Notifications\" settings panel, and disallow it to Override Do Not Disturb.</string>
<string name="package_priority_user_order">Check that ranker respects user priorities.</string>
<string name="attention_test">Notification Attention Management Test</string>
@@ -1208,7 +1208,7 @@
<string name="attention_email_order">Check that ranker respects mailto URIs for contacts.</string>
<string name="attention_phone_order">Check that ranker respects telephone URIs for contacts.</string>
<string name="attention_interruption_order">Check that ranker temporarily boosts interruptions.
- This test takes 15 seconds to complete.</string>
+ This test takes 30 seconds to complete.</string>
<string name="attention_none_are_filtered">Check that \"All\" mode doesn\'t filter any notifications.</string>
<string name="attention_some_are_filtered">Check that \"Priority\" mode doesn\'t filter priority notifications.</string>
<string name="attention_all_are_filtered">Check that \"None\" mode filters all notifications.</string>
@@ -1236,9 +1236,9 @@
<string name="vr_disable_service">Please disable \"VR Listener for CTS Verifier\"
under Apps > Gear Icon > Special Access > VR Helper Services and return here.</string>
<string name="nls_enable_service">Please enable \"Notification Listener for CTS Verifier\"
- under Security > Notification Access and return here.</string>
+ under Apps > Gear Icon > Special Access > Notification Access and return here.</string>
<string name="nls_disable_service">Please disable \"Notification Listener for CTS Verifier\"
- under Security > Notification Access and return here.</string>
+ under Apps > Gear Icon > Special Access > Notification Access and return here.</string>
<string name="nls_start_settings">Launch Settings</string>
<string name="nls_service_started">Service should start once enabled.</string>
<string name="nls_note_received">Check that notification was received.</string>
@@ -2245,12 +2245,19 @@
<string name="device_owner_request_bugreport">Request bugreport</string>
<string name="bugreport_sharing_declined">Bugreport sharing declined</string>
<string name="bugreport_shared_successfully">Bugreport shared successfully</string>
+ <string name="bugreport_already_in_progress">Bugreport is already being collected on this device</string>
+ <string name="bugreport_failed_completing">Bugreport collection operation failed</string>
<string name="device_owner_bugreport_sharing_declined_while_being_taken">Sharing of requested bugreport declined while being taken</string>
<string name="device_owner_bugreport_sharing_declined_while_being_taken_info">
Please press the \"Request bugreport\" button to invoke the bugreport sharing operation.
Open the notifications panel and verify that:\n
\n
- Notification titled \"Taking bugreport...\" with an indefinite progress bar is present.\n
+ \n
+ Press the \"Request bugreport\" button again to try to invoke a second bugreport sharing operation.
+ Open the notifications panel and verify that:\n
+ \n
+ - Notification titled \"Device Owner Requesting Bugreport Tests\" with message \"Bugreport is already being collected on this device\" is present. Dismiss that notification.\n
- Tapping on the \"Taking bugreport...\" notification opens a dialog titled \"Share bug report?\", that contains a message \"Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared, and your device may temporarily slow down.\" and two buttons - \"DECLINE\" and \"SHARE\".\n
\n
Tap the \"DECLINE\" button and verify that:\n
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 4e39720..1349694 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -26,6 +26,9 @@
import android.os.UserManager;
import android.util.Log;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.managedprovisioning.Utils;
+
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
@@ -149,7 +152,12 @@
if (!mDpm.isDeviceOwnerApp(getPackageName())) {
return;
}
- mDpm.requestBugreport(mAdmin);
+ final boolean bugreportStarted = mDpm.requestBugreport(mAdmin);
+ if (!bugreportStarted) {
+ Utils.showBugreportNotification(this, getString(
+ R.string.bugreport_already_in_progress),
+ Utils.BUGREPORT_NOTIFICATION_ID);
+ }
} break;
case COMMAND_DEVICE_OWNER_CLEAR_POLICIES: {
if (!mDpm.isDeviceOwnerApp(getPackageName())) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 6ca07ce..e6ba855 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -16,8 +16,6 @@
package com.android.cts.verifier.managedprovisioning;
-import android.app.Notification;
-import android.app.NotificationManager;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -29,6 +27,7 @@
import com.android.cts.verifier.R;
import com.android.cts.verifier.location.LocationListenerActivity;
+import com.android.cts.verifier.managedprovisioning.Utils;
/**
* Profile owner receiver for BYOD flow test.
@@ -42,7 +41,6 @@
DEVICE_OWNER_PKG + ".managedprovisioning.DeviceAdminTestReceiver";
private static final ComponentName RECEIVER_COMPONENT_NAME = new ComponentName(
DEVICE_OWNER_PKG, ADMIN_RECEIVER_TEST_CLASS);
- private static final int BUGREPORT_NOTIFICATION_ID = 12345;
public static ComponentName getReceiverComponentName() {
return RECEIVER_COMPONENT_NAME;
@@ -57,15 +55,22 @@
@Override
public void onBugreportSharingDeclined(Context context, Intent intent) {
Log.i(TAG, "Bugreport sharing declined");
- showBugreportNotification(context, context.getString(
- R.string.bugreport_sharing_declined), BUGREPORT_NOTIFICATION_ID);
+ Utils.showBugreportNotification(context, context.getString(
+ R.string.bugreport_sharing_declined), Utils.BUGREPORT_NOTIFICATION_ID);
}
@Override
public void onBugreportShared(Context context, Intent intent, String bugreportFileHash) {
Log.i(TAG, "Bugreport shared");
- showBugreportNotification(context, context.getString(
- R.string.bugreport_shared_successfully), BUGREPORT_NOTIFICATION_ID);
+ Utils.showBugreportNotification(context, context.getString(
+ R.string.bugreport_shared_successfully), Utils.BUGREPORT_NOTIFICATION_ID);
+ }
+
+ @Override
+ public void onBugreportFailed(Context context, Intent intent, int failureCode) {
+ Log.i(TAG, "Bugreport collection operation failed, code: " + failureCode);
+ Utils.showBugreportNotification(context, context.getString(
+ R.string.bugreport_failed_completing), Utils.BUGREPORT_NOTIFICATION_ID);
}
private void setupProfile(Context context) {
@@ -124,17 +129,4 @@
context.startActivity(intent);
}
- private void showBugreportNotification(Context context, String msg,
- int notificationId) {
- NotificationManager mNotificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- Notification notification = new Notification.Builder(context)
- .setSmallIcon(R.drawable.icon)
- .setContentTitle(context.getString(
- R.string.device_owner_requesting_bugreport_tests))
- .setContentText(msg)
- .setStyle(new Notification.BigTextStyle().bigText(msg))
- .build();
- mNotificationManager.notify(notificationId, notification);
- }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
index abccb43..17e83c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
@@ -17,6 +17,8 @@
package com.android.cts.verifier.managedprovisioning;
import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.widget.Toast;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -32,6 +34,7 @@
public class Utils {
private static final String TAG = "CtsVerifierByodUtils";
+ static final int BUGREPORT_NOTIFICATION_ID = 12345;
static TestListItem createInteractiveTestItem(Activity activity, String id, int titleRes,
int infoRes, ButtonInfo[] buttonInfos) {
@@ -61,4 +64,17 @@
Log.d(TAG, "requestDeleteProfileOwner: ActivityNotFoundException", e);
}
}
+
+ static void showBugreportNotification(Context context, String msg, int notificationId) {
+ NotificationManager mNotificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ Notification notification = new Notification.Builder(context)
+ .setSmallIcon(R.drawable.icon)
+ .setContentTitle(context.getString(
+ R.string.device_owner_requesting_bugreport_tests))
+ .setContentText(msg)
+ .setStyle(new Notification.BigTextStyle().bigText(msg))
+ .build();
+ mNotificationManager.notify(notificationId, notification);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
index 4898ab2..9d9a4bc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/AttentionManagementVerifierActivity.java
@@ -60,6 +60,11 @@
private static final int MODE_URI = 1;
private static final int MODE_PHONE = 2;
private static final int MODE_EMAIL = 3;
+ private static final int SEND_A = 0x1;
+ private static final int SEND_B = 0x2;
+ private static final int SEND_C = 0x4;
+ private static final int SEND_ALL = SEND_A | SEND_B | SEND_C;
+
private Uri mAliceUri;
private Uri mBobUri;
@@ -129,7 +134,17 @@
if (mAliceUri == null) { status = FAIL; }
if (mBobUri == null) { status = FAIL; }
if (mCharlieUri != null) { status = FAIL; }
- next();
+
+ if (status == PASS && !isStarred(mAliceUri)) {
+ status = RETEST;
+ Log.i("InsertContactsTest", "Alice is not yet starred");
+ delay();
+ } else {
+ Log.i("InsertContactsTest", "Alice is: " + mAliceUri);
+ Log.i("InsertContactsTest", "Bob is: " + mBobUri);
+ Log.i("InsertContactsTest", "Charlie is: " + mCharlieUri);
+ next();
+ }
}
}
@@ -528,6 +543,8 @@
// A starts at the top then falls to the bottom
protected class InterruptionOrderTest extends InteractiveTestCase {
+ boolean mSawElevation = false;
+
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.attention_interruption_order);
@@ -535,15 +552,21 @@
@Override
void setUp() {
- sendNotifications(MODE_NONE, false, true);
+ // send B & C noisy
+ sendNotifications(SEND_B | SEND_C, MODE_NONE, false, true);
status = READY;
- // wait for notifications to move through the system
- delay();
+ // wait for then to not be recently noisy any more
+ delay(15000);
}
@Override
void test() {
if (status == READY) {
+ // send A noisy
+ sendNotifications(SEND_A, MODE_NONE, false, true);
+ status = RETEST;
+ delay();
+ } else if (status == RETEST) {
MockListener.probeListenerOrder(mContext,
new MockListener.StringListResultCatcher() {
@Override
@@ -551,36 +574,28 @@
int rankA = findTagInKeys(ALICE, orderedKeys);
int rankB = findTagInKeys(BOB, orderedKeys);
int rankC = findTagInKeys(CHARLIE, orderedKeys);
- if (rankA < rankB && rankA < rankC) {
- status = RETEST;
- delay(12000);
+ if (!mSawElevation) {
+ if (rankA < rankB && rankA < rankC) {
+ mSawElevation = true;
+ status = RETEST;
+ delay(15000);
+ } else {
+ logFail("noisy notification did not sort to top.");
+ status = FAIL;
+ next();
+ }
} else {
- logFail("noisy notification did not sort to top.");
- status = FAIL;
- next();
+ if (rankA > rankB && rankA > rankC) {
+ status = PASS;
+ } else {
+ logFail("noisy notification did not fade back into the list.");
+ status = FAIL;
+ }
}
}
});
delay(); // in case the catcher never returns
- } else {
- MockListener.probeListenerOrder(mContext,
- new MockListener.StringListResultCatcher() {
- @Override
- public void accept(List<String> orderedKeys) {
- int rankA = findTagInKeys(ALICE, orderedKeys);
- int rankB = findTagInKeys(BOB, orderedKeys);
- int rankC = findTagInKeys(CHARLIE, orderedKeys);
- if (rankA > rankB && rankA > rankC) {
- status = PASS;
- } else {
- logFail("noisy notification did not fade back into the list.");
- status = FAIL;
- }
- next();
- }
- });
- delay(); // in case the catcher never returns
- }
+ }
}
@Override
@@ -796,11 +811,12 @@
// usePriorities false:
// MODE_NONE: C, B, A
// otherwise: A, B ,C
- private void sendNotifications(int annotationMode, boolean usePriorities, boolean noisy) {
- // TODO(cwren) Fixes flakey tests due to bug 17644321. Remove this line when it is fixed.
- int baseId = NOTIFICATION_ID + (noisy ? 3 : 0);
+ private void sendNotifications(int annotationMode, boolean uriMode, boolean noisy) {
+ sendNotifications(SEND_ALL, annotationMode, uriMode, noisy);
+ }
- // C, B, A when sorted by time. Times must be in the past.
+ private void sendNotifications(int which, int uriMode, boolean usePriorities, boolean noisy) {
+ // C, B, A when sorted by time. Times must be in the past
long whenA = System.currentTimeMillis() - 4000000L;
long whenB = System.currentTimeMillis() - 2000000L;
long whenC = System.currentTimeMillis() - 1000000L;
@@ -810,36 +826,42 @@
int priorityB = usePriorities ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
int priorityC = usePriorities ? Notification.PRIORITY_LOW : Notification.PRIORITY_DEFAULT;
- Notification.Builder alice = new Notification.Builder(mContext)
- .setContentTitle(ALICE)
- .setContentText(ALICE)
- .setSmallIcon(R.drawable.ic_stat_alice)
- .setPriority(priorityA)
- .setCategory(Notification.CATEGORY_MESSAGE)
- .setWhen(whenA);
- alice.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
- addPerson(annotationMode, alice, mAliceUri, ALICE_PHONE, ALICE_EMAIL);
- mNm.notify(ALICE, baseId + 1, alice.build());
-
- Notification.Builder bob = new Notification.Builder(mContext)
- .setContentTitle(BOB)
- .setContentText(BOB)
- .setSmallIcon(R.drawable.ic_stat_bob)
- .setPriority(priorityB)
- .setCategory(Notification.CATEGORY_MESSAGE)
- .setWhen(whenB);
- addPerson(annotationMode, bob, mBobUri, BOB_PHONE, BOB_EMAIL);
- mNm.notify(BOB, baseId + 2, bob.build());
-
- Notification.Builder charlie = new Notification.Builder(mContext)
- .setContentTitle(CHARLIE)
- .setContentText(CHARLIE)
- .setSmallIcon(R.drawable.ic_stat_charlie)
- .setPriority(priorityC)
- .setCategory(Notification.CATEGORY_MESSAGE)
- .setWhen(whenC);
- addPerson(annotationMode, charlie, mCharlieUri, CHARLIE_PHONE, CHARLIE_EMAIL);
- mNm.notify(CHARLIE, baseId + 3, charlie.build());
+ if ((which & SEND_B) != 0) {
+ Notification.Builder bob = new Notification.Builder(mContext)
+ .setContentTitle(BOB)
+ .setContentText(BOB)
+ .setSmallIcon(R.drawable.ic_stat_bob)
+ .setPriority(priorityB)
+ .setCategory(Notification.CATEGORY_MESSAGE)
+ .setWhen(whenB);
+ bob.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
+ addPerson(uriMode, bob, mBobUri, BOB_PHONE, BOB_EMAIL);
+ mNm.notify(BOB, NOTIFICATION_ID + 2, bob.build());
+ }
+ if ((which & SEND_C) != 0) {
+ Notification.Builder charlie = new Notification.Builder(mContext)
+ .setContentTitle(CHARLIE)
+ .setContentText(CHARLIE)
+ .setSmallIcon(R.drawable.ic_stat_charlie)
+ .setPriority(priorityC)
+ .setCategory(Notification.CATEGORY_MESSAGE)
+ .setWhen(whenC);
+ charlie.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
+ addPerson(uriMode, charlie, mCharlieUri, CHARLIE_PHONE, CHARLIE_EMAIL);
+ mNm.notify(CHARLIE, NOTIFICATION_ID + 3, charlie.build());
+ }
+ if ((which & SEND_A) != 0) {
+ Notification.Builder alice = new Notification.Builder(mContext)
+ .setContentTitle(ALICE)
+ .setContentText(ALICE)
+ .setSmallIcon(R.drawable.ic_stat_alice)
+ .setPriority(priorityA)
+ .setCategory(Notification.CATEGORY_MESSAGE)
+ .setWhen(whenA);
+ alice.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0);
+ addPerson(uriMode, alice, mAliceUri, ALICE_PHONE, ALICE_EMAIL);
+ mNm.notify(ALICE, NOTIFICATION_ID + 1, alice.build());
+ }
}
private void addPerson(int mode, Notification.Builder note,
@@ -920,6 +942,28 @@
return null;
}
+ private boolean isStarred(Uri uri) {
+ Cursor c = null;
+ boolean starred = false;
+ try {
+ String[] projection = new String[] { ContactsContract.Contacts.STARRED };
+ c = mContext.getContentResolver().query(uri, projection, null, null, null);
+ if (c != null && c.getCount() > 0) {
+ int starredIdx = c.getColumnIndex(ContactsContract.Contacts.STARRED);
+ while (c.moveToNext()) {
+ starred |= c.getInt(starredIdx) == 1;
+ }
+ }
+ } catch (Throwable t) {
+ Log.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return starred;
+ }
+
/** Search a list of notification keys for a givcen tag. */
private int findTagInKeys(String tag, List<String> orderedKeys) {
for (int i = 0; i < orderedKeys.size(); i++) {
diff --git a/build/config.mk b/build/config.mk
index 306c5fd..3b9723b 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -50,3 +50,4 @@
BUILD_CTS_SUPPORT_PACKAGE := cts/build/support_package.mk
BUILD_CTS_MODULE_TEST_CONFIG := cts/build/module_test_config.mk
BUILD_CTS_DEVICE_INFO_PACKAGE := cts/build/device_info_package.mk
+BUILD_CTS_TARGET_TESTNG_PACKAGE := cts/build/test_target_testng_package.mk
diff --git a/build/test_target_testng_package.mk b/build/test_target_testng_package.mk
new file mode 100644
index 0000000..0621109
--- /dev/null
+++ b/build/test_target_testng_package.mk
@@ -0,0 +1,53 @@
+# 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.
+
+#
+# Builds a host library and defines a rule to generate the associated test
+# package XML needed by CTS.
+#
+# Disable by default so "m cts" will work in emulator builds
+LOCAL_DEX_PREOPT := false
+include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_CTS_MODULE_TEST_CONFIG)
+
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+ $(copy-file-to-target)
+
+CTS_DEQP_CONFIG_PATH := $(call my-dir)
+
+cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml
+$(cts_library_xml): MUSTPASS_XML_FILE := $(LOCAL_CTS_TESTCASE_XML_INPUT)
+$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
+$(cts_library_xml): $(cts_library_jar)
+$(cts_library_xml): $(cts_module_test_config)
+$(cts_library_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR) $(CTS_TESTCASE_XML_INPUT)
+ $(hide) echo Generating test description for target testng package $(PRIVATE_LIBRARY)
+ $(hide) mkdir -p $(CTS_TESTCASES_OUT)
+
+# Query build ABIs by routing a dummy test list through xml generator and parse result. Use sed to insert the ABI string into the XML files.
+ $(hide) SUPPORTED_ABI_ATTR=`$(CTS_XML_GENERATOR) -t dummyTest \
+ -n dummyName \
+ -p invalid.dummy \
+ -e $(CTS_EXPECTATIONS) \
+ -b $(CTS_UNSUPPORTED_ABIS) \
+ -a $(CTS_TARGET_ARCH) \
+ < $(PRIVATE_DUMMY_CASELIST) \
+ | grep --only-matching -e " abis=\"[^\"]*\""` && \
+ $(SED_EXTENDED) -e "s:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $${SUPPORTED_ABI_ATTR}\4>:" \
+ < $(MUSTPASS_XML_FILE) \
+ > $@
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_library_jar) $(cts_library_xml) $(cts_module_test_config)
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
index cb81d0b..4ba1237 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -27,6 +27,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.List;
/**
* Handles adding results to the report for device side tests.
@@ -56,6 +57,8 @@
public DeviceReportLog(String reportLogName, String streamName) {
super(reportLogName, streamName);
try {
+ // dir value must match the src-dir value configured in ReportLogCollector target
+ // preparer in cts/tools/cts-tradefed/res/config/cts-preconditions.xml
final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
throw new IOException("External storage is not mounted");
@@ -71,6 +74,9 @@
}
}
+ /**
+ * Adds a double metric to the report.
+ */
@Override
public void addValue(String source, String message, double value, ResultType type,
ResultUnit unit) {
@@ -82,6 +88,9 @@
}
}
+ /**
+ * Adds a double metric to the report.
+ */
@Override
public void addValue(String message, double value, ResultType type, ResultUnit unit) {
super.addValue(message, value, type, unit);
@@ -92,6 +101,9 @@
}
}
+ /**
+ * Adds a double array of metrics to the report.
+ */
@Override
public void addValues(String source, String message, double[] values, ResultType type,
ResultUnit unit) {
@@ -103,6 +115,9 @@
}
}
+ /**
+ * Adds a double array of metrics to the report.
+ */
@Override
public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
super.addValues(message, values, type, unit);
@@ -113,6 +128,144 @@
}
}
+ /**
+ * Adds an int metric to the report.
+ */
+ @Override
+ public void addValue(String message, int value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a long metric to the report.
+ */
+ @Override
+ public void addValue(String message, long value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a float metric to the report.
+ */
+ @Override
+ public void addValue(String message, float value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a boolean metric to the report.
+ */
+ @Override
+ public void addValue(String message, boolean value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a String metric to the report.
+ */
+ @Override
+ public void addValue(String message, String value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds an int array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, int[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a long array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, long[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a float array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, float[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a boolean array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, boolean[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Adds a String List of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, List<String> values, ResultType type, ResultUnit unit) {
+ try {
+ store.addListResult(message, values);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Sets the summary double metric of the report.
+ *
+ * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+ */
+ @Override
+ public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
+ super.setSummary(message, value, type, unit);
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not log metric.", e);
+ }
+ }
+
+ /**
+ * Closes report file and submits report to instrumentation.
+ */
public void submit(Instrumentation instrumentation) {
Log.i(TAG, "Submit");
try {
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
index fd61b08..504a02d 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
@@ -27,10 +27,12 @@
public class ReportLogDeviceInfoStore extends DeviceInfoStore {
private final String mStreamName;
+ private final File tempJsonFile;
public ReportLogDeviceInfoStore(File jsonFile, String streamName) throws Exception {
mJsonFile = jsonFile;
mStreamName = streamName;
+ tempJsonFile = File.createTempFile(streamName, "-temp-report-log");
}
/**
@@ -38,30 +40,32 @@
*/
@Override
public void open() throws IOException {
+ // Write new metrics to a temp file to avoid invalid JSON files due to failed tests.
BufferedWriter formatWriter;
- String oldMetrics;
+ tempJsonFile.createNewFile();
+ formatWriter = new BufferedWriter(new FileWriter(tempJsonFile));
if (mJsonFile.exists()) {
BufferedReader jsonReader = new BufferedReader(new FileReader(mJsonFile));
- StringBuilder oldMetricsBuilder = new StringBuilder();
- String line;
- while ((line = jsonReader.readLine()) != null) {
- oldMetricsBuilder.append(line);
+ String currentLine;
+ String nextLine = jsonReader.readLine();
+ while ((currentLine = nextLine) != null) {
+ nextLine = jsonReader.readLine();
+ if (nextLine == null && currentLine.charAt(currentLine.length() - 1) == '}') {
+ // Reopen overall JSON object to write new metrics.
+ currentLine = currentLine.substring(0, currentLine.length() - 1) + ",";
+ }
+ // Copy to temp file directly to avoid large metrics string in memory.
+ formatWriter.write(currentLine, 0, currentLine.length());
}
- oldMetrics = oldMetricsBuilder.toString().trim();
- if (oldMetrics.charAt(oldMetrics.length() - 1) == '}') {
- oldMetrics = oldMetrics.substring(0, oldMetrics.length() - 1);
- }
- oldMetrics = oldMetrics + ",";
+ jsonReader.close();
} else {
- oldMetrics = "{";
+ formatWriter.write("{", 0 , 1);
}
- mJsonFile.createNewFile();
- formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
- formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
- mStreamName.length() + 3);
+ // Start new JSON object for new metrics.
+ formatWriter.write("\"" + mStreamName + "\":", 0, mStreamName.length() + 3);
formatWriter.flush();
formatWriter.close();
- mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
+ mJsonWriter = new JsonWriter(new FileWriter(tempJsonFile, true));
mJsonWriter.beginObject();
}
@@ -70,12 +74,24 @@
*/
@Override
public void close() throws IOException {
+ // Close JSON Writer.
mJsonWriter.endObject();
mJsonWriter.close();
- // Close the overall JSON object
- BufferedWriter formatWriter = new BufferedWriter(new FileWriter(mJsonFile, true));
- formatWriter.write("}", 0, 1);
- formatWriter.flush();
- formatWriter.close();
+ // Close overall JSON Object.
+ try (BufferedWriter formatWriter = new BufferedWriter(new FileWriter(tempJsonFile, true))) {
+ formatWriter.write("}", 0, 1);
+ }
+ // Copy metrics from temp file and delete temp file.
+ mJsonFile.createNewFile();
+ try (
+ BufferedReader jsonReader = new BufferedReader(new FileReader(tempJsonFile));
+ BufferedWriter metricsWriter = new BufferedWriter(new FileWriter(mJsonFile))
+ ) {
+ String line;
+ while ((line = jsonReader.readLine()) != null) {
+ // Copy from temp file directly to avoid large metrics string in memory.
+ metricsWriter.write(line, 0, line.length());
+ }
+ }
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index c9ee92a..bae1bfa 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -35,7 +35,6 @@
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.ILogSaver;
import com.android.tradefed.result.ILogSaverListener;
import com.android.tradefed.result.ITestInvocationListener;
@@ -358,12 +357,12 @@
}
// Save the full results folder.
if (zippedResults != null) {
- FileInputStreamSource fiss = null;
+ FileInputStream zipResultStream = null;
try {
- fiss = new FileInputStreamSource(zippedResults);
- testLog("results", LogDataType.ZIP, fiss);
+ zipResultStream = new FileInputStream(zippedResults);
+ mLogSaver.saveLogData("results", LogDataType.ZIP, zipResultStream);
} finally {
- StreamUtil.cancel(fiss);
+ StreamUtil.close(zipResultStream);
}
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
index 33ee5d8..6b87977 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -17,7 +17,6 @@
package com.android.compatibility.common.tradefed.targetprep;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
@@ -51,16 +50,6 @@
@Option(name = "package", description = "Name of the package", mandatory = true)
protected String mPackageName = null;
- @Option(name = CompatibilityTest.INCLUDE_FILTER_OPTION,
- description = "the include module filters to apply.",
- importance = Importance.ALWAYS)
- private List<String> mIncludeFilters = new ArrayList<>();
-
- @Option(name = CompatibilityTest.EXCLUDE_FILTER_OPTION,
- description = "the exclude module filters to apply.",
- importance = Importance.ALWAYS)
- private List<String> mExcludeFilters = new ArrayList<>();
-
public enum When {
BEFORE, AFTER, BOTH;
}
@@ -133,8 +122,6 @@
instrTest.setDevice(device);
instrTest.setInstallFile(apkFile);
instrTest.setPackageName(mPackageName);
- instrTest.addAllIncludeFilters(mIncludeFilters);
- instrTest.addAllExcludeFilters(mExcludeFilters);
instrTest.run(listener);
boolean success = true;
if (!testFailures.isEmpty()) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
index 1ee7dd3..e620f19 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
@@ -91,40 +91,32 @@
CLog.e("%s is not a directory", resultDir.getAbsolutePath());
return;
}
- String resultPath = resultDir.getAbsolutePath();
final File hostReportDir = FileUtil.createNamedTempDir(mTempReportFolder);
if (!hostReportDir.isDirectory()) {
CLog.e("%s is not a directory", hostReportDir.getAbsolutePath());
return;
}
- String hostReportsPath = hostReportDir.getAbsolutePath();
- pull(device, mSrcDir, hostReportsPath, resultPath);
+ pull(device, mSrcDir, hostReportDir, resultDir);
} catch (Exception exception) {
exception.printStackTrace();
}
}
- private void pull(ITestDevice device, String deviceSrc, String hostSrc, String dest) {
+ private void pull(ITestDevice device, String deviceSrc, File hostDir, File destDir) {
+ String hostSrc = hostDir.getAbsolutePath();
+ String dest = destDir.getAbsolutePath();
String deviceSideCommand = String.format("adb -s %s pull %s %s", device.getSerialNumber(),
deviceSrc, dest);
- String hostSideCommand = String.format("cp -r %s/* %s", hostSrc, dest);
- String cleanUpCommand = String.format("rm -rf %s", hostSrc);
try {
- Process deviceProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
- deviceSideCommand});
- if (deviceProcess.waitFor() != 0) {
- CLog.v("No device-side report logs pulled.");
+ if (device.doesFileExist(deviceSrc)) {
+ Process deviceProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+ deviceSideCommand});
+ if (deviceProcess.waitFor() != 0) {
+ CLog.e("Failed to run %s", deviceSideCommand);
+ }
}
- Process hostProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
- hostSideCommand});
- if (hostProcess.waitFor() != 0) {
- CLog.v("No host-side report logs pulled");
- }
- Process cleanUpProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
- cleanUpCommand});
- if (cleanUpProcess.waitFor() != 0) {
- CLog.e("Failed to run %s", cleanUpCommand);
- }
+ FileUtil.recursiveCopy(hostDir, destDir);
+ FileUtil.recursiveDelete(hostDir);
} catch (Exception e) {
CLog.e("Caught exception during pull.");
CLog.e(e);
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
index e590b91..ad7d098 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.List;
/**
* A {@link ReportLog} that can be used with the in memory metrics store used for host side metrics.
@@ -47,11 +48,26 @@
this(deviceSerial, abi, classMethodName, DEFAULT_REPORT_LOG_NAME, DEFAULT_STREAM_NAME);
}
+ /**
+ * @param deviceSerial serial number of the device
+ * @param abi abi the test was run on
+ * @param classMethodName class name and method name of the test in class#method format.
+ * Note that ReportLog.getClassMethodNames() provide this.
+ * @param reportLogName the name of the report log file. Metrics will be written out to this.
+ */
public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
String reportLogName) {
this(deviceSerial, abi, classMethodName, reportLogName, DEFAULT_STREAM_NAME);
}
+ /**
+ * @param deviceSerial serial number of the device
+ * @param abi abi the test was run on
+ * @param classMethodName class name and method name of the test in class#method format.
+ * Note that ReportLog.getClassMethodNames() provide this.
+ * @param reportLogName the name of the report log file. Metrics will be written out to this.
+ * @param streamName the key for the JSON object of the set of metrics to be logged.
+ */
public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
String reportLogName, String streamName) {
super(reportLogName, streamName);
@@ -68,6 +84,9 @@
}
}
+ /**
+ * Adds a double metric to the report.
+ */
@Override
public void addValue(String source, String message, double value, ResultType type,
ResultUnit unit) {
@@ -79,6 +98,9 @@
}
}
+ /**
+ * Adds a double metric to the report.
+ */
@Override
public void addValue(String message, double value, ResultType type, ResultUnit unit) {
super.addValue(message, value, type, unit);
@@ -90,6 +112,171 @@
}
+ /**
+ * Adds a double array of metrics to the report.
+ */
+ @Override
+ public void addValues(String source, String message, double[] values, ResultType type,
+ ResultUnit unit) {
+ super.addValues(source, message, values, type, unit);
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a double array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
+ super.addValues(message, values, type, unit);
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds an int metric to the report.
+ */
+ @Override
+ public void addValue(String message, int value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a long metric to the report.
+ */
+ @Override
+ public void addValue(String message, long value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a float metric to the report.
+ */
+ @Override
+ public void addValue(String message, float value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a boolean metric to the report.
+ */
+ @Override
+ public void addValue(String message, boolean value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a String metric to the report.
+ */
+ @Override
+ public void addValue(String message, String value, ResultType type, ResultUnit unit) {
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds an int array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, int[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a long array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, long[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a float array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, float[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a boolean array of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, boolean[] values, ResultType type, ResultUnit unit) {
+ try {
+ store.addArrayResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds a String List of metrics to the report.
+ */
+ @Override
+ public void addValues(String message, List<String> values, ResultType type, ResultUnit unit) {
+ try {
+ store.addListResult(message, values);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sets the summary double metric of the report.
+ *
+ * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+ */
+ @Override
+ public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
+ super.setSummary(message, value, type, unit);
+ try {
+ store.addResult(message, value);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Closes report file and submits report.
+ */
public void submit() {
try {
store.close();
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
index 65114d9..38b742b 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
@@ -27,10 +27,12 @@
public class ReportLogHostInfoStore extends HostInfoStore {
private final String mStreamName;
+ private final File tempJsonFile;
public ReportLogHostInfoStore(File jsonFile, String streamName) throws Exception {
mJsonFile = jsonFile;
mStreamName = streamName;
+ tempJsonFile = File.createTempFile(streamName, "-temp-report-log");
}
/**
@@ -38,30 +40,32 @@
*/
@Override
public void open() throws IOException {
+ // Write new metrics to a temp file to avoid invalid JSON files due to failed tests.
BufferedWriter formatWriter;
- String oldMetrics;
+ tempJsonFile.createNewFile();
+ formatWriter = new BufferedWriter(new FileWriter(tempJsonFile));
if (mJsonFile.exists()) {
BufferedReader jsonReader = new BufferedReader(new FileReader(mJsonFile));
- StringBuilder oldMetricsBuilder = new StringBuilder();
- String line;
- while ((line = jsonReader.readLine()) != null) {
- oldMetricsBuilder.append(line);
+ String currentLine;
+ String nextLine = jsonReader.readLine();
+ while ((currentLine = nextLine) != null) {
+ nextLine = jsonReader.readLine();
+ if (nextLine == null && currentLine.charAt(currentLine.length() - 1) == '}') {
+ // Reopen overall JSON object to write new metrics.
+ currentLine = currentLine.substring(0, currentLine.length() - 1) + ",";
+ }
+ // Copy to temp file directly to avoid large metrics string in memory.
+ formatWriter.write(currentLine, 0, currentLine.length());
}
- oldMetrics = oldMetricsBuilder.toString().trim();
- if (oldMetrics.charAt(oldMetrics.length() - 1) == '}') {
- oldMetrics = oldMetrics.substring(0, oldMetrics.length() - 1);
- }
- oldMetrics = oldMetrics + ",";
+ jsonReader.close();
} else {
- oldMetrics = "{";
+ formatWriter.write("{", 0 , 1);
}
- mJsonFile.createNewFile();
- formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
- formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
- mStreamName.length() + 3);
+ // Start new JSON object for new metrics.
+ formatWriter.write("\"" + mStreamName + "\":", 0, mStreamName.length() + 3);
formatWriter.flush();
formatWriter.close();
- mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
+ mJsonWriter = new JsonWriter(new FileWriter(tempJsonFile, true));
mJsonWriter.beginObject();
}
@@ -70,12 +74,24 @@
*/
@Override
public void close() throws IOException {
+ // Close JSON Writer.
mJsonWriter.endObject();
mJsonWriter.close();
- // Close the overall JSON object
- BufferedWriter formatWriter = new BufferedWriter(new FileWriter(mJsonFile, true));
- formatWriter.write("}", 0, 1);
- formatWriter.flush();
- formatWriter.close();
+ // Close overall JSON Object.
+ try (BufferedWriter formatWriter = new BufferedWriter(new FileWriter(tempJsonFile, true))) {
+ formatWriter.write("}", 0, 1);
+ }
+ // Copy metrics from temp file and delete temp file.
+ mJsonFile.createNewFile();
+ try (
+ BufferedReader jsonReader = new BufferedReader(new FileReader(tempJsonFile));
+ BufferedWriter metricsWriter = new BufferedWriter(new FileWriter(mJsonFile))
+ ) {
+ String line;
+ while ((line = jsonReader.readLine()) != null) {
+ // Copy from temp file directly to avoid large metrics string in memory.
+ metricsWriter.write(line, 0, line.length());
+ }
+ }
}
}
diff --git a/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java b/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
index 0f4b597..a7b1153 100644
--- a/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
+++ b/common/util/src/com/android/compatibility/common/util/MetricsXmlSerializer.java
@@ -38,7 +38,6 @@
return;
}
ReportLog.Metric summary = reportLog.getSummary();
- List<ReportLog.Metric> detailedMetrics = reportLog.getDetailedMetrics();
// <Summary message="Average" scoreType="lower_better" unit="ms">195.2</Summary>
if (summary != null) {
mXmlSerializer.startTag(null, "Summary");
@@ -48,24 +47,5 @@
mXmlSerializer.text(Double.toString(summary.getValues()[0]));
mXmlSerializer.endTag(null, "Summary");
}
-
- if (!detailedMetrics.isEmpty()) {
- mXmlSerializer.startTag(null, "Details");
- for (ReportLog.Metric result : detailedMetrics) {
- mXmlSerializer.startTag(null, "ValueArray");
- mXmlSerializer.attribute(null, "source", result.getSource());
- mXmlSerializer.attribute(null, "message", result.getMessage());
- mXmlSerializer.attribute(null, "scoreType", result.getType().toReportString());
- mXmlSerializer.attribute(null, "unit", result.getUnit().toReportString());
-
- for (double value : result.getValues()) {
- mXmlSerializer.startTag(null, "Value");
- mXmlSerializer.text(Double.toString(value));
- mXmlSerializer.endTag(null, "Value");
- }
- mXmlSerializer.endTag(null, "ValueArray");
- }
- mXmlSerializer.endTag(null, "Details");
- }
}
}
\ No newline at end of file
diff --git a/common/util/src/com/android/compatibility/common/util/ReportLog.java b/common/util/src/com/android/compatibility/common/util/ReportLog.java
index 37c39ef..08b1d76 100644
--- a/common/util/src/com/android/compatibility/common/util/ReportLog.java
+++ b/common/util/src/com/android/compatibility/common/util/ReportLog.java
@@ -38,7 +38,6 @@
private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
// XML constants
- private static final String DETAIL_TAG = "Detail";
private static final String METRIC_TAG = "Metric";
private static final String MESSAGE_ATTR = "message";
private static final String SCORETYPE_ATTR = "score_type";
@@ -51,7 +50,6 @@
protected Metric mSummary;
protected String mReportLogName;
protected String mStreamName;
- protected final List<Metric> mDetails = new ArrayList<>();
public static class Metric implements Serializable {
private static final int MAX_SOURCE_LENGTH = 200;
@@ -174,54 +172,103 @@
}
/**
- * @param elem
- */
- /* package */ void addMetric(Metric elem) {
- mDetails.add(elem);
- }
-
- /**
- * Adds an array of metrics to the report.
- *
- * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
- * NOTE: arrays with length over {@value Metric#MAX_NUM_VALUES} will be truncated.
+ * Adds a double array of metrics to the report.
*/
public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
- addMetric(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(),
- message, values, type, unit));
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
- * Adds an array of metrics to the report.
- *
- * NOTE: sources over {@value Metric#MAX_SOURCE_LENGTH} chars will be trimmed.
- * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
- * NOTE: arrays with length over {@value Metric#MAX_NUM_VALUES} will be truncated.
+ * Adds a double array of metrics to the report.
*/
public void addValues(String source, String message, double[] values, ResultType type,
ResultUnit unit) {
- addMetric(new Metric(source, message, values, type, unit));
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
- * Adds a metric to the report.
- *
- * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+ * Adds a double metric to the report.
*/
public void addValue(String message, double value, ResultType type, ResultUnit unit) {
- addMetric(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(), message,
- value, type, unit));
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
- * Adds a metric to the report.
- *
- * NOTE: sources over {@value Metric#MAX_SOURCE_LENGTH} chars will be trimmed.
- * NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
+ * Adds a double metric to the report.
*/
public void addValue(String source, String message, double value, ResultType type,
ResultUnit unit) {
- addMetric(new Metric(source, message, value, type, unit));
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds an int metric to the report.
+ */
+ public void addValue(String message, int value, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a long metric to the report.
+ */
+ public void addValue(String message, long value, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a float metric to the report.
+ */
+ public void addValue(String message, float value, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a boolean metric to the report.
+ */
+ public void addValue(String message, boolean value, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a String metric to the report.
+ */
+ public void addValue(String message, String value, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds an int array of metrics to the report.
+ */
+ public void addValues(String message, int[] values, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a long array of metrics to the report.
+ */
+ public void addValues(String message, long[] values, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a float array of metrics to the report.
+ */
+ public void addValues(String message, float[] values, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a boolean array of metrics to the report.
+ */
+ public void addValues(String message, boolean[] values, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
+ }
+
+ /**
+ * Adds a String List of metrics to the report.
+ */
+ public void addValues(String message, List<String> values, ResultType type, ResultUnit unit) {
+ // Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
@@ -232,7 +279,7 @@
}
/**
- * Sets the summary of the report.
+ * Sets the double metric summary of the report.
*
* NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
*/
@@ -241,16 +288,10 @@
type, unit));
}
- // TODO(mishragaurav): Add support for values of other types.
-
public Metric getSummary() {
return mSummary;
}
- public List<Metric> getDetailedMetrics() {
- return new ArrayList<Metric>(mDetails);
- }
-
/**
* Serializes a given {@link ReportLog} to a String.
* @throws XmlPullParserException
@@ -282,20 +323,11 @@
throw new IllegalArgumentException("Metrics reports was null");
}
Metric summary = reportLog.getSummary();
- List<Metric> detailedMetrics = reportLog.getDetailedMetrics();
- if (summary == null) {
- throw new IllegalArgumentException("Metrics reports must have a summary");
- }
- serializer.startTag(null, SUMMARY_TAG);
- summary.serialize(serializer);
- serializer.endTag(null, SUMMARY_TAG);
-
- if (!detailedMetrics.isEmpty()) {
- serializer.startTag(null, DETAIL_TAG);
- for (Metric elem : detailedMetrics) {
- elem.serialize(serializer);
- }
- serializer.endTag(null, DETAIL_TAG);
+ // Summary is optional. Details are not included in result report.
+ if (summary != null) {
+ serializer.startTag(null, SUMMARY_TAG);
+ summary.serialize(serializer);
+ serializer.endTag(null, SUMMARY_TAG);
}
}
@@ -305,13 +337,22 @@
* @throws IOException
*/
public static ReportLog parse(String result) throws XmlPullParserException, IOException {
- if (result == null || result.trim().isEmpty()) {
- throw new IllegalArgumentException("Metrics string was empty");
+ if (result == null){
+ throw new IllegalArgumentException("Metrics string was null");
+ }
+ if (result.trim().isEmpty()) {
+ // Empty report.
+ return new ReportLog();
}
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new ByteArrayInputStream(result.getBytes(ENCODING)), ENCODING);
- parser.nextTag();
+ try {
+ parser.nextTag();
+ } catch (XmlPullParserException e) {
+ // Empty Report.
+ return new ReportLog();
+ }
return parse(parser);
}
@@ -328,18 +369,6 @@
report.setSummary(Metric.parse(parser));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, SUMMARY_TAG);
- try {
- parser.nextTag();
- } catch (XmlPullParserException e) {
- // Report doesn't have any details, it's ok
- return report;
- }
- if (parser.getName().equals(DETAIL_TAG)) {
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- report.addMetric(Metric.parse(parser));
- }
- parser.require(XmlPullParser.END_TAG, null, DETAIL_TAG);
- }
return report;
}
}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
index c6f3ec1..dbbb479 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/MetricsXmlSerializerTest.java
@@ -34,18 +34,7 @@
private static final double[] VALUES = new double[] {1, 11, 21, 1211, 111221};
private static final String HEADER = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>";
private static final String EXPECTED_XML = HEADER
- + "<Summary message=\"Sample\" scoreType=\"higher_better\" unit=\"byte\">1.0</Summary>"
- + "<Details>"
- + "<ValueArray source=\"com.android.compatibility.common.util."
- + "MetricsXmlSerializerTest#testSerialize:84\""
- + " message=\"Details\" scoreType=\"neutral\" unit=\"fps\">"
- + "<Value>1.0</Value>"
- + "<Value>11.0</Value>"
- + "<Value>21.0</Value>"
- + "<Value>1211.0</Value>"
- + "<Value>111221.0</Value>"
- + "</ValueArray>"
- + "</Details>";
+ + "<Summary message=\"Sample\" scoreType=\"higher_better\" unit=\"byte\">1.0</Summary>";
private LocalReportLog mLocalReportLog;
private MetricsXmlSerializer mMetricsXmlSerializer;
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
index 0b4a639..c8d4682 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -42,18 +42,7 @@
" <Value>1.0</Value>\r\n" +
" </Metric>\r\n" +
"</Summary>";
- private static final String DETAIL_XML =
- "<Detail>\r\n" +
- " <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Details\" score_type=\"neutral\" score_unit=\"fps\">\r\n" +
- " <Value>0.1</Value>\r\n" +
- " <Value>124.0</Value>\r\n" +
- " <Value>4736.0</Value>\r\n" +
- " <Value>835.683</Value>\r\n" +
- " <Value>98.0</Value>\r\n" +
- " <Value>395.0</Value>\r\n" +
- " </Metric>\r\n" +
- "</Detail>";
- private static final String FULL_XML = SUMMARY_XML + "\r\n" + DETAIL_XML;
+ private static final String FULL_XML = SUMMARY_XML;
private ReportLog mReportLog;
@@ -72,34 +61,24 @@
}
public void testSerialize_noData() throws Exception {
- try {
- ReportLog.serialize(mReportLog);
- fail("Expected IllegalArgumentException when serializing an empty report");
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ ReportLog.serialize(mReportLog);
}
public void testSerialize_summaryOnly() throws Exception {
mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
- assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:84"),
+ assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:68"),
ReportLog.serialize(mReportLog));
}
public void testSerialize_detailOnly() throws Exception {
mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
- try {
- ReportLog.serialize(mReportLog);
- fail("Expected IllegalArgumentException when serializing report without summary");
- } catch(IllegalArgumentException e) {
- // Expected
- }
+ assertEquals(HEADER_XML, ReportLog.serialize(mReportLog));
}
public void testSerialize_full() throws Exception {
mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
- assertEquals(String.format(FULL_XML, "testSerialize_full:100", "testSerialize_full:101"),
+ assertEquals(String.format(FULL_XML, "testSerialize_full:79"),
ReportLog.serialize(mReportLog));
}
@@ -113,12 +92,8 @@
}
public void testParse_noData() throws Exception {
- try {
- ReportLog.parse(HEADER_XML);
- fail("Expected XmlPullParserException when passing a report with no content");
- } catch(XmlPullParserException e) {
- // Expected
- }
+ ReportLog report = ReportLog.parse(HEADER_XML);
+ assertNull(report.getSummary());
}
public void testParse_summaryOnly() throws Exception {
@@ -127,23 +102,10 @@
assertEquals("Sample", report.getSummary().getMessage());
}
- public void testParse_detailOnly() throws Exception {
- try {
- ReportLog.parse(String.format(DETAIL_XML, "testParse_detailOnly:132"));
- fail("Expected XmlPullParserException when serializing report without summary");
- } catch (XmlPullParserException e) {
- // Expected
- }
- }
-
public void testParse_full() throws Exception {
- ReportLog report = ReportLog.parse(String.format(FULL_XML, "testParse_full:140",
- "testParse_full:138"));
+ ReportLog report = ReportLog.parse(String.format(FULL_XML, "testParse_full:140"));
assertNotNull(report);
assertEquals("Sample", report.getSummary().getMessage());
- List<Metric> details = report.getDetailedMetrics();
- assertEquals(1, details.size());
- assertEquals("Details", details.get(0).getMessage());
}
public void testLimits_source() throws Exception {
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index c88fe8e..3009ec4 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -122,13 +122,6 @@
" <Value>%s</Value>\n" +
" </Metric>\n" +
" </Summary>\n" +
- " <Detail>\n" +
- " <Metric source=\"%s\" message=\"%s\" score_type=\"%s\" score_unit=\"%s\">\n" +
- " <Value>%s</Value>\n" +
- " <Value>%s</Value>\n" +
- " <Value>%s</Value>\n" +
- " </Metric>\n" +
- " </Detail>\n" +
" </Test>\n";
private File resultsDir = null;
private File resultDir = null;
@@ -173,10 +166,6 @@
ReportLog.Metric summary = new ReportLog.Metric(SUMMARY_SOURCE, SUMMARY_MESSAGE,
SUMMARY_VALUE, ResultType.HIGHER_BETTER, ResultUnit.SCORE);
report.setSummary(summary);
- ReportLog.Metric details = new ReportLog.Metric(DETAILS_SOURCE, DETAILS_MESSAGE,
- new double[] {DETAILS_VALUE_1, DETAILS_VALUE_2, DETAILS_VALUE_3},
- ResultType.LOWER_BETTER, ResultUnit.MS);
- report.addMetric(details);
moduleBTest4.setReportLog(report);
// Serialize to file
@@ -332,14 +321,5 @@
assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
assertTrue("Incorrect values", Arrays.equals(new double[] { SUMMARY_VALUE },
summary.getValues()));
- List<ReportLog.Metric> details = report.getDetailedMetrics();
- assertEquals("Expected 1 report detail", 1, details.size());
- ReportLog.Metric detail = details.get(0);
- assertEquals("Incorrect source", DETAILS_SOURCE, detail.getSource());
- assertEquals("Incorrect message", DETAILS_MESSAGE, detail.getMessage());
- assertEquals("Incorrect type", ResultType.LOWER_BETTER, detail.getType());
- assertEquals("Incorrect unit", ResultUnit.MS, detail.getUnit());
- assertTrue("Incorrect values", Arrays.equals(new double[] { DETAILS_VALUE_1,
- DETAILS_VALUE_2, DETAILS_VALUE_3 }, detail.getValues()));
}
}
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-sig.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-sig.apk
new file mode 100644
index 0000000..1133085
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-sig.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-supported-sig.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-supported-sig.apk
new file mode 100644
index 0000000..2fab38a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers-second-signer-no-supported-sig.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
index 90ab764..51ed3ff 100644
--- a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
index 101602a..acf5cb6 100644
--- a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 6c5e4a5..461bcd7 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -31,8 +31,9 @@
public class PermissionsHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
private static final String PKG = "com.android.cts.usepermission";
- private static final String APK = "CtsUsePermissionApp.apk";
- private static final String APK_COMPAT = "CtsUsePermissionAppCompat.apk";
+ private static final String APK_22 = "CtsUsePermissionApp22.apk";
+ private static final String APK_23 = "CtsUsePermissionApp23.apk";
+ private static final String APK_24 = "CtsUsePermissionApp24.apk";
private IAbi mAbi;
private IBuildInfo mCtsBuild;
@@ -67,9 +68,10 @@
public void testFail() throws Exception {
// Sanity check that remote failure is host failure
assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
try {
- runDeviceTests(PKG, ".UsePermissionTest", "testFail");
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testFail");
fail("Expected remote failure");
} catch (AssertionError expected) {
}
@@ -78,82 +80,216 @@
public void testKill() throws Exception {
// Sanity check that remote kill is host failure
assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
try {
- runDeviceTests(PKG, ".UsePermissionTest", "testKill");
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testKill");
fail("Expected remote failure");
} catch (AssertionError expected) {
}
}
- public void testDefault() throws Exception {
+ public void testCompatDefault22() throws Exception {
assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
- runDeviceTests(PKG, ".UsePermissionTest", "testDefault");
- }
-
- public void testGranted() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
- grantPermission(PKG, "android.permission.READ_EXTERNAL_STORAGE");
- grantPermission(PKG, "android.permission.WRITE_EXTERNAL_STORAGE");
- runDeviceTests(PKG, ".UsePermissionTest", "testGranted");
- }
-
- public void testInteractiveGrant() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
- runDeviceTests(PKG, ".UsePermissionTest", "testInteractiveGrant");
- }
-
- public void testRuntimeGroupGrantSpecificity() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
- runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantSpecificity");
- }
-
- public void testRuntimeGroupGrantExpansion() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
- runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantExpansion");
- }
-
- public void testCompatDefault() throws Exception {
- assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+ MigrationHelper.getTestFile(mCtsBuild, APK_22),
false, false));
- runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatDefault");
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testCompatDefault");
}
- public void testCompatRevoked() throws Exception {
- assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+ public void testCompatRevoked22() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_22),
false, false));
- setAppOps(PKG, "android:read_external_storage", "deny");
- setAppOps(PKG, "android:write_external_storage", "deny");
- runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatRevoked");
+ try {
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testCompatRevoked_part1");
+ fail("App must be killed on a permission revoke");
+ } catch (AssertionError expected) {
+ }
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testCompatRevoked_part2");
+ }
+
+ public void testNoRuntimePrompt22() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_22),
+ false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testNoRuntimePrompt");
+ }
+
+ public void testDefault23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testDefault");
+ }
+
+ public void testGranted23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testGranted");
+ }
+
+ public void testInteractiveGrant23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testInteractiveGrant");
+ }
+
+ public void testRuntimeGroupGrantSpecificity23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRuntimeGroupGrantSpecificity");
+ }
+
+ public void testRuntimeGroupGrantExpansion23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRuntimeGroupGrantExpansion");
+ }
+
+ public void testCancelledPermissionRequest23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testCancelledPermissionRequest");
+ }
+
+ public void testRequestGrantedPermission23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRequestGrantedPermission");
+ }
+
+ public void testDenialWithPrejudice23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testDenialWithPrejudice");
+ }
+
+ public void testRevokeAffectsWholeGroup23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ try {
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23_part1",
+ "testRevokeAffectsWholeGroup");
+ } catch (AssertionError expected) {
+ }
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23_part2",
+ "testRevokeAffectsWholeGroup");
+ }
+
+ public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ try {
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1");
+ fail("App must be killed on a permission revoke");
+ } catch (Throwable expected) {
+ }
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part2");
+ }
+
+ public void testRequestNonRuntimePermission23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRequestNonRuntimePermission");
+ }
+
+ public void testRequestNonExistentPermission23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRequestNonExistentPermission");
+ }
+
+ public void testRequestPermissionFromTwoGroups23() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRequestPermissionFromTwoGroups");
+ }
+
+ public void testOnlyRequestedPermissionsGranted24() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_24), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest24",
+ "testOnlyRequestedPermissionsGranted");
+ }
+
+ public void testUpgradeKeepsPermissions() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testAllPermissionsGrantedByDefault");
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testAllPermissionsGrantedOnUpgrade");
+ }
+
+ public void testNoDowngradePermissionModel() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ try {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_22), true, false));
+ fail("Permission mode downgrade not allowed");
+ } catch (AssertionError expected) {
+ }
+ }
+
+ public void testNoResidualPermissionsOnUninstall() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testNoResidualPermissionsOnUninstall_part1");
+ assertNull(getDevice().uninstallPackage(PKG));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testNoResidualPermissionsOnUninstall_part2");
+ }
+
+ public void testRevokePropagatedOnUpgradeOldToNewModel() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+ try {
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
+ "testRevokePropagatedOnUpgradeOldToNewModel_part1");
+ fail("App must be killed on a permission revoke");
+ } catch (AssertionError expected) {
+ }
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRevokePropagatedOnUpgradeOldToNewModel_part2");
+ }
+
+ public void testRevokePropagatedOnUpgradeNewToNewModel() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRevokePropagatedOnUpgradeNewToNewModel_part1");
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
+ "testRevokePropagatedOnUpgradeNewToNewModel_part2");
}
private void runDeviceTests(String packageName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
}
-
- private void grantPermission(String pkg, String permission) throws Exception {
- assertEmpty(getDevice().executeShellCommand("pm grant " + pkg + " " + permission));
- }
-
- private void revokePermission(String pkg, String permission) throws Exception {
- assertEmpty(getDevice().executeShellCommand("pm revoke " + pkg + " " + permission));
- }
-
- private void setAppOps(String pkg, String op, String mode) throws Exception {
- assertEmpty(getDevice().executeShellCommand("appops set " + pkg + " " + op + " " + mode));
- }
-
- private static void assertEmpty(String str) {
- if (str == null || str.length() == 0) {
- return;
- } else {
- fail("Expected empty string but found " + str);
- }
- }
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index f6c6f18..254dda8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -317,6 +317,21 @@
"two-signers-second-signer-v2-broken.apk", "signature did not verify");
}
+ public void testInstallV2TwoSignersRejectsWhenOneWithoutSignatures() throws Exception {
+ // APK v2-signed by two different signers. However, there are no signatures for the second
+ // signer.
+ assertInstallFailsWithError(
+ "v2-only-two-signers-second-signer-no-sig.apk", "No signatures");
+ }
+
+ public void testInstallV2TwoSignersRejectsWhenOneWithoutSupportedSignatures() throws Exception {
+ // APK v2-signed by two different signers. However, there are no supported signatures for
+ // the second signer.
+ assertInstallFailsWithError(
+ "v2-only-two-signers-second-signer-no-supported-sig.apk",
+ "No supported signatures");
+ }
+
public void testInstallV2RejectsWhenMissingCode() throws Exception {
// Obtained by removing classes.dex from original.apk and then signing with v2 only.
// Although this has nothing to do with v2 signature verification, package manager wants
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
new file mode 100644
index 0000000..b2b4476
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Tests that verify intent filters.
+ */
+public class PrivilegedUpdateTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+ private static final String SHIM_PKG = "com.android.cts.priv.ctsshim";
+ /** Package name of the tests to be run */
+ private static final String TEST_PKG = "com.android.cts.privilegedupdate";
+
+ /** APK that contains the shim; to test upgrading */
+ private static final String SHIM_UPDATE_APK = "CtsShimPrivUpgradePrebuilt.apk";
+ /** APK that contains individual shim test cases */
+ private static final String TEST_APK = "CtsPrivilegedUpdateTests.apk";
+
+ private IAbi mAbi;
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ assertNotNull(mAbi);
+ assertNotNull(mCtsBuild);
+
+ getDevice().uninstallPackage(SHIM_PKG);
+ getDevice().uninstallPackage(TEST_PKG);
+
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ getDevice().uninstallPackage(SHIM_PKG);
+ getDevice().uninstallPackage(TEST_PKG);
+ }
+
+ public void testSystemAppPriorities() throws Exception {
+ runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testSystemAppPriorities");
+ }
+
+ public void testPrivilegedAppPriorities() throws Exception {
+ runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testPrivilegedAppPriorities");
+ }
+
+ public void testPrivilegedAppUpgradePriorities() throws Exception {
+ getDevice().uninstallPackage(SHIM_PKG);
+
+ try {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+ runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testPrivilegedAppUpgradePriorities");
+ } finally {
+ getDevice().uninstallPackage(SHIM_PKG);
+ }
+ }
+
+ private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+ throws DeviceNotAvailableException {
+ Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+ }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
new file mode 100644
index 0000000..c8e608e
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import com.android.cts.migration.MigrationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of runtime permissions, including both
+ * dynamic granting and behavior of legacy apps.
+ */
+public class UsesLibraryHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+ private static final String PKG = "com.android.cts.useslibrary";
+
+ private static final String APK = "CtsUsesLibraryApp.apk";
+ private static final String APK_COMPAT = "CtsUsesLibraryAppCompat.apk";
+
+ private IAbi mAbi;
+ private IBuildInfo mCtsBuild;
+
+ @Override
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = buildInfo;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ assertNotNull(mAbi);
+ assertNotNull(mCtsBuild);
+
+ getDevice().uninstallPackage(PKG);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ getDevice().uninstallPackage(PKG);
+ }
+
+ public void testUsesLibrary() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ runDeviceTests(PKG, ".UsesLibraryTest", "testUsesLibrary");
+ }
+
+ public void testMissingLibrary() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ runDeviceTests(PKG, ".UsesLibraryTest", "testMissingLibrary");
+ }
+
+ public void testDuplicateLibrary() throws Exception {
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ runDeviceTests(PKG, ".UsesLibraryTest", "testDuplicateLibrary");
+ }
+
+ private void runDeviceTests(String packageName, String testClassName, String testMethodName)
+ throws DeviceNotAvailableException {
+ Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index c528ad4..f5666d1 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -355,15 +355,22 @@
}
}
- public static void assertMediaNoAccess(ContentResolver resolver) throws Exception {
+ public static void assertMediaNoAccess(ContentResolver resolver, boolean legacyApp)
+ throws Exception {
final ContentValues values = new ContentValues();
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(Images.Media.DATA,
buildProbeFile(Environment.getExternalStorageDirectory()).getAbsolutePath());
try {
- resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
- fail("Expected access to be blocked");
+ Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+ if (legacyApp) {
+ // For legacy apps we do not crash - just make the operation do nothing
+ assertEquals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+ .buildUpon().appendPath("0").build().toString(), uri.toString());
+ } else {
+ fail("Expected access to be blocked");
+ }
} catch (Exception expected) {
}
}
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
new file mode 100644
index 0000000..6d6e805
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/Android.mk
@@ -0,0 +1,67 @@
+#
+# 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)
+
+###########################################################
+# Package w/ tests
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+LOCAL_PACKAGE_NAME := CtsPrivilegedUpdateTests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+
+###########################################################
+# Variant: Privileged app upgrade
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := CtsShimPrivUpgradePrebuilt
+LOCAL_MODULE_TAGS := tests
+#LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MODULE_CLASS := APPS
+LOCAL_BUILT_MODULE_STEM := package.apk
+# Make sure the build system doesn't try to resign the APK
+LOCAL_CERTIFICATE := PRESIGNED
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_SRC_FILES := CtsShimPrivUpgrade.apk
+
+include $(BUILD_PREBUILT)
+
+# Add package to the set of APKs available to CTS
+# Unceremoneously ripped from cts/build/support_package.mk
+cts_support_apks :=
+$(foreach fp, $(ALL_MODULES.$(LOCAL_MODULE).BUILT_INSTALLED),\
+ $(eval pair := $(subst :,$(space),$(fp)))\
+ $(eval built := $(word 1,$(pair)))\
+ $(eval installed := $(CTS_TESTCASES_OUT)/$(notdir $(word 2,$(pair))))\
+ $(eval $(call copy-one-file, $(built), $(installed)))\
+ $(eval cts_support_apks += $(installed)))
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_support_apks)
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
similarity index 73%
copy from hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
copy to hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
index 253d85d..58f34b9 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -15,13 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.usepermission">
- <application>
+ package="com.android.cts.privilegedupdate">
+
+ <application android:label="PrivilegedUpdateApp">
<uses-library android:name="android.test.runner" />
- <activity android:name=".MyActivity" />
+ <activity android:name=".MainActivity" />
</application>
+
<instrumentation
android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.usepermission" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ android:targetPackage="com.android.cts.privilegedupdate" />
+
</manifest>
+
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/CtsShimPrivUpgrade.apk
new file mode 100644
index 0000000..c71163d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/CtsShimPrivUpgrade.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedUpdateTest.java b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedUpdateTest.java
new file mode 100644
index 0000000..7b92bea
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/src/com/android/cts/privilegedupdate/PrivilegedUpdateTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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 com.android.cts.intentfilter;
+
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Tests for intent filter.
+ */
+public class PrivilegedUpdateTest extends InstrumentationTestCase {
+ /** Package name of the privileged CTS shim */
+ private static final String PRIVILEGED_SHIM_PKG = "com.android.cts.priv.ctsshim";
+ /** Package name of the system CTS shim */
+ private static final String SYSTEM_SHIM_PKG = "com.android.cts.ctsshim";
+ /** Class name for the install tests */
+ private static final String INSTALL_CLASS = ".InstallPriority";
+
+ /**
+ * Tests the filter priorities for a system package are set correctly.
+ * <p>
+ * System packages can NOT obtain higher priorities for any action.
+ */
+ public void testSystemAppPriorities() throws Exception {
+ final ComponentName testComponent =
+ new ComponentName(SYSTEM_SHIM_PKG, SYSTEM_SHIM_PKG + INSTALL_CLASS);
+ assertFilterPriority(testComponent, Intent.ACTION_SEARCH, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_VIEW, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND_MULTIPLE, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SENDTO, 0);
+ }
+
+ /**
+ * Tests the filter priorities for a privileged package are set correctly.
+ * <p>
+ * Privileged packages can obtain higher priorities except for those on
+ * protected actions.
+ */
+ public void testPrivilegedAppPriorities() throws Exception {
+ final ComponentName testComponent =
+ new ComponentName(PRIVILEGED_SHIM_PKG, PRIVILEGED_SHIM_PKG + INSTALL_CLASS);
+ assertFilterPriority(testComponent, Intent.ACTION_SEARCH, 100);
+ assertFilterPriority(testComponent, Intent.ACTION_VIEW, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND_MULTIPLE, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SENDTO, 0);
+ }
+
+ /**
+ * Tests the filter priorities for a privileged package are set correctly after update.
+ * <p>
+ * Test various forms of filter equivalency [eg. action, category, scheme and host].
+ * Also, don't allow any filter obtain a higher priority than what was defined on
+ * system image.
+ */
+ public void testPrivilegedAppUpgradePriorities() throws Exception {
+ final ComponentName testComponent =
+ new ComponentName(PRIVILEGED_SHIM_PKG, PRIVILEGED_SHIM_PKG + INSTALL_CLASS);
+ assertFilterPriority(testComponent, Intent.ACTION_VIEW, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SEND_MULTIPLE, 0);
+ assertFilterPriority(testComponent, Intent.ACTION_SENDTO, 0);
+
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeMatch"),
+ "com.android.cts.action.MATCH", 100);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeMatchMultiple"),
+ "com.android.cts.action.MATCH_MULTIPLE", 150);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeLowerPriority"),
+ "com.android.cts.action.LOWER_PRIORITY", 75);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeActionSubset"),
+ "com.android.cts.action.ACTION_SUB_2", 100);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeCategorySubset"),
+ "com.android.cts.action.CATEGORY_SUB", 100);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeSchemeSubset"),
+ "com.android.cts.action.SCHEME_SUB", "flubber:", 100);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeAuthoritySubset"),
+ "com.android.cts.action.AUTHORITY_SUB", 100);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeNewActivity"),
+ "com.android.cts.action.NEW_ACTIVITY", 0);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeNewAction"),
+ "com.android.cts.action.NEW_ACTION", 0);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeNewCategory"),
+ "com.android.cts.action.NEW_CATEGORY", 0);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeNewScheme"),
+ "com.android.cts.action.NEW_SCHEME", "zowie:", 0);
+ assertFilterPriority(
+ new ComponentName(PRIVILEGED_SHIM_PKG,
+ PRIVILEGED_SHIM_PKG + ".UpgradeNewAuthority"),
+ "com.android.cts.action.NEW_AUTHORITY", 0);
+ }
+
+ private void assertFilterPriority(ComponentName component, String action, int priority) {
+ assertFilterPriority(component, action, null /*data*/, priority);
+ }
+ private void assertFilterPriority(
+ ComponentName component, String action, String data, int priority) {
+ final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ final String className = component.getClassName();
+ final Intent intent = new Intent(action);
+ intent.setPackage(component.getPackageName());
+ if (data != null) {
+ intent.setData(Uri.parse(data));
+ }
+ final List<ResolveInfo> entries =
+ pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
+ assertNotNull(entries);
+ ResolveInfo foundInfo = null;
+ for (ResolveInfo ri : entries) {
+ if (ri.activityInfo.name.equals(className)) {
+ foundInfo = ri;
+ break;
+ }
+ }
+ assertTrue(action + "; didn't find class \"" + className + "\"", foundInfo != null);
+ assertEquals(action + "; wrong priority", priority, foundInfo.filter.getPriority());
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp/AndroidManifest.xml
deleted file mode 100644
index ece4ebe..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.usepermission">
- <application>
- <uses-library android:name="android.test.runner" />
- <activity android:name=".MyActivity" />
- </application>
- <instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.usepermission" />
-
- <!-- Note that WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE;
- this is a special case. -->
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
- <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
-
- <!-- Request two different permissions within the same group -->
- <uses-permission android:name="android.permission.SEND_SMS" />
- <uses-permission android:name="android.permission.RECEIVE_SMS" />
-
-</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/UsePermissionTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/UsePermissionTest.java
deleted file mode 100644
index 8d3b976..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/UsePermissionTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.usepermission;
-
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaNoAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.logCommand;
-
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
-import android.test.InstrumentationTestCase;
-
-public class UsePermissionTest extends InstrumentationTestCase {
- private static final String TAG = "UsePermissionTest";
-
- private UiDevice mDevice;
- private MyActivity mActivity;
-
- public void testFail() throws Exception {
- fail("Expected");
- }
-
- public void testKill() throws Exception {
- android.os.Process.killProcess(android.os.Process.myPid());
- }
-
- public void testDefault() throws Exception {
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- // New permission model is denied by default
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE));
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
- assertDirNoAccess(Environment.getExternalStorageDirectory());
- assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
- assertMediaNoAccess(getInstrumentation().getContext().getContentResolver());
- }
-
- public void testGranted() throws Exception {
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE));
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
- assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
- assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
- assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
- }
-
- public void testInteractiveGrant() throws Exception {
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- // Start out without permission
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE));
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
- assertDirNoAccess(Environment.getExternalStorageDirectory());
- assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
- assertMediaNoAccess(getInstrumentation().getContext().getContentResolver());
-
- // Go through normal grant flow
- mDevice = UiDevice.getInstance(getInstrumentation());
- mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
- MyActivity.class, null);
- mDevice.waitForIdle();
-
- mActivity.requestPermissions(new String[] {
- android.Manifest.permission.READ_EXTERNAL_STORAGE,
- android.Manifest.permission.WRITE_EXTERNAL_STORAGE }, 42);
- mDevice.waitForIdle();
-
- new UiObject(new UiSelector()
- .resourceId("com.android.packageinstaller:id/permission_allow_button")).click();
- mDevice.waitForIdle();
-
- MyActivity.Result result = mActivity.getResult();
- assertEquals(42, result.requestCode);
- assertEquals(android.Manifest.permission.READ_EXTERNAL_STORAGE, result.permissions[0]);
- assertEquals(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, result.permissions[1]);
- assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
- assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[1]);
-
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- // We should have permission now!
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE));
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
- assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
- assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
- assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
-
- mActivity.finish();
- }
-
- public void testRuntimeGroupGrantSpecificity() throws Exception {
- // Start out without permission
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_CONTACTS));
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_CONTACTS));
-
- // Go through normal grant flow
- mDevice = UiDevice.getInstance(getInstrumentation());
- mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
- MyActivity.class, null);
- mDevice.waitForIdle();
-
- // request only one permission from the 'contacts' permission group
- mActivity.requestPermissions(new String[] {
- android.Manifest.permission.WRITE_CONTACTS }, 43);
- mDevice.waitForIdle();
-
- new UiObject(new UiSelector()
- .resourceId("com.android.packageinstaller:id/permission_allow_button")).click();
- mDevice.waitForIdle();
-
- MyActivity.Result result = mActivity.getResult();
- assertEquals(43, result.requestCode);
- assertEquals(android.Manifest.permission.WRITE_CONTACTS, result.permissions[0]);
- assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
-
- // We should have only the explicitly requested permission from this group
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.WRITE_CONTACTS));
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.READ_CONTACTS));
-
- mActivity.finish();
- }
-
- public void testRuntimeGroupGrantExpansion() throws Exception {
- // Start out without permission
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.RECEIVE_SMS));
- assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.SEND_SMS));
-
- // Go through normal grant flow
- mDevice = UiDevice.getInstance(getInstrumentation());
- mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
- MyActivity.class, null);
- mDevice.waitForIdle();
-
- // request only one permission from the 'SMS' permission group at runtime,
- // but two from this group are <uses-permission> in the manifest
- mActivity.requestPermissions(new String[] {
- android.Manifest.permission.RECEIVE_SMS }, 44);
- mDevice.waitForIdle();
-
- new UiObject(new UiSelector()
- .resourceId("com.android.packageinstaller:id/permission_allow_button")).click();
- mDevice.waitForIdle();
-
- MyActivity.Result result = mActivity.getResult();
- assertEquals(44, result.requestCode);
- assertEquals(android.Manifest.permission.RECEIVE_SMS, result.permissions[0]);
- assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
-
- // We should now have been granted both of the permissions from this group
- // that are mentioned in our manifest
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.RECEIVE_SMS));
- assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
- .checkSelfPermission(android.Manifest.permission.SEND_SMS));
-
- mActivity.finish();
- }
-}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
similarity index 81%
copy from hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
copy to hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
index 4630f1f..9ee5921 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
@@ -19,13 +19,14 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+ ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java \
+ ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
+ ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp
+LOCAL_PACKAGE_NAME := CtsUsePermissionApp22
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml
new file mode 100644
index 0000000..ebb0cbf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/AndroidManifest.xml
@@ -0,0 +1,77 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <!-- Contacts -->
+ <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR"/>
+ <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
+ <uses-permission android:name="android.permission.RECEIVE_MMS"/>
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/>
+
+ <!-- Storage -->
+ <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <!-- Location -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"/>
+ <uses-permission android:name="android.permission.USE_SIP"/>
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <!-- Camera -->
+ <uses-permission android:name="android.permission.CAMERA"/>
+
+ <!-- Body Sensors -->
+ <uses-permission android:name="android.permission.BODY_SENSORS"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name=".BasePermissionActivity" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.usepermission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
new file mode 100644
index 0000000..1478015
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
@@ -0,0 +1,172 @@
+/*
+ * 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.usepermission;
+
+import static junit.framework.Assert.assertEquals;
+
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.logCommand;
+import static junit.framework.Assert.assertTrue;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.os.Process;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Arrays;
+
+/**
+ * Runtime permission behavior tests for apps targeting API 22
+ */
+public class UsePermissionTest22 extends BasePermissionsTest {
+ private static final int REQUEST_CODE_PERMISSIONS = 42;
+
+ @Test
+ public void testCompatDefault() throws Exception {
+ final Context context = getInstrumentation().getContext();
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+
+ // Legacy permission model is granted by default
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ context.checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ Process.myPid(), Process.myUid()));
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ context.checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Process.myPid(), Process.myUid()));
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
+ for (File path : getAllPackageSpecificPaths(context)) {
+ if (path != null) {
+ assertDirReadWriteAccess(path);
+ }
+ }
+ assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
+ }
+
+ @Test
+ public void testCompatRevoked_part1() throws Exception {
+ // Revoke the permission
+ revokePermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, true);
+ }
+
+ @Test
+ public void testCompatRevoked_part2() throws Exception {
+ final Context context = getInstrumentation().getContext();
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+
+ // Legacy permission model appears granted, but storage looks and
+ // behaves like it's ejected
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ context.checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ Process.myPid(), Process.myUid()));
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ context.checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Process.myPid(), Process.myUid()));
+ assertEquals(Environment.MEDIA_UNMOUNTED, Environment.getExternalStorageState());
+
+ assertDirNoAccess(Environment.getExternalStorageDirectory());
+ for (File dir : getAllPackageSpecificPaths(context)) {
+ if (dir != null) {
+ assertDirNoAccess(dir);
+ }
+ }
+ assertMediaNoAccess(getInstrumentation().getContext().getContentResolver(), true);
+
+ // Just to be sure, poke explicit path
+ assertDirNoAccess(new File(Environment.getExternalStorageDirectory(),
+ "/Android/data/" + getInstrumentation().getContext().getPackageName()));
+ }
+
+ @Test
+ public void testAllPermissionsGrantedByDefault() throws Exception {
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+ // The APK does not request because of other tests Manifest.permission.READ_CONTACTS
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_SMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_WAP_PUSH));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_MMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission("android.permission.READ_CELL_BROADCASTS"));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_PHONE_STATE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.CALL_PHONE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALL_LOG));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CALL_LOG));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.ADD_VOICEMAIL));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.USE_SIP));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.PROCESS_OUTGOING_CALLS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.CAMERA));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.BODY_SENSORS));
+ }
+
+ @Test
+ public void testNoRuntimePrompt() throws Exception {
+ // Request the permission and do nothing
+ BasePermissionActivity.Result result = requestPermissions(
+ new String[] {Manifest.permission.SEND_SMS}, REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class, null);
+
+ // Expect the permission is not granted
+ assertEquals(REQUEST_CODE_PERMISSIONS, result.requestCode);
+ assertTrue(Arrays.equals(result.permissions, new String[0]));
+ assertTrue(Arrays.equals(result.grantResults, new int[0]));
+ }
+
+ @Test
+ public void testRevokePropagatedOnUpgradeOldToNewModel_part1() throws Exception {
+ // Revoke a permission
+ revokePermissions(new String[] {Manifest.permission.WRITE_CALENDAR}, true);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
similarity index 94%
copy from hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
copy to hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
index 4630f1f..c8e05c5 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
@@ -19,13 +19,12 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp
+LOCAL_PACKAGE_NAME := CtsUsePermissionApp23
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/AndroidManifest.xml
new file mode 100644
index 0000000..71eadaa
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/AndroidManifest.xml
@@ -0,0 +1,76 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.usepermission">
+
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
+ <!-- Contacts -->
+ <!-- Deliberately request WRITE_CONTACTS but *not* READ_CONTACTS -->
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+ <!-- Calendar -->
+ <uses-permission android:name="android.permission.READ_CALENDAR"/>
+ <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
+
+ <!-- SMS -->
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
+ <uses-permission android:name="android.permission.RECEIVE_MMS"/>
+ <uses-permission android:name="android.permission.READ_CELL_BROADCASTS"/>
+
+ <!-- Storage -->
+ <!-- Special case: WRITE_EXTERNAL_STORAGE implies READ_EXTERNAL_STORAGE -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <!-- Location -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+ <uses-permission android:name="android.permission.CALL_PHONE"/>
+ <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+ <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"/>
+ <uses-permission android:name="android.permission.USE_SIP"/>
+ <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
+
+ <!-- Phone -->
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <!-- Camera -->
+ <uses-permission android:name="android.permission.CAMERA"/>
+
+ <!-- Body Sensors -->
+ <uses-permission android:name="android.permission.BODY_SENSORS"/>
+
+ <application>
+ <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.usepermission" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/MyActivity.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
similarity index 78%
rename from hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/MyActivity.java
rename to hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
index 5af3886..cacfa80 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/src/com/android/cts/usepermission/MyActivity.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java
@@ -20,11 +20,15 @@
import android.os.Bundle;
import android.view.WindowManager;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-public class MyActivity extends Activity {
+public class BasePermissionActivity extends Activity {
+ private static final long OPERATION_TIMEOUT_MILLIS = 5000;
+
private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+ private final CountDownLatch mOnCreateSync = new CountDownLatch(1);
public static class Result {
public final int requestCode;
@@ -45,6 +49,8 @@
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+
+ mOnCreateSync.countDown();
}
@Override
@@ -57,9 +63,17 @@
}
}
+ public void waitForOnCreate() {
+ try {
+ mOnCreateSync.await(OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public Result getResult() {
try {
- return mResult.take();
+ return mResult.poll(OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
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
new file mode 100644
index 0000000..5b7dfb6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -0,0 +1,297 @@
+/*
+ * 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 com.android.cts.usepermission;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiSelector;
+import android.util.ArrayMap;
+import android.widget.Switch;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+public abstract class BasePermissionsTest {
+ private static final String PLATFORM_PACKAGE_NAME = "android";
+
+ private static final long IDLE_TIMEOUT_MILLIS = 500;
+ private static final long GLOBAL_TIMEOUT_MILLIS = 5000;
+
+ private static Map<String, String> sPermissionToLabelResNameMap = new ArrayMap<>();
+ static {
+ // Contacts
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_CONTACTS,
+ "@android:string/permgrouplab_contacts");
+ sPermissionToLabelResNameMap.put(Manifest.permission.WRITE_CONTACTS,
+ "@android:string/permgrouplab_contacts");
+ // Calendar
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_CALENDAR,
+ "@android:string/permgrouplab_calendar");
+ sPermissionToLabelResNameMap.put(Manifest.permission.WRITE_CALENDAR,
+ "@android:string/permgrouplab_calendar");
+ // SMS
+ sPermissionToLabelResNameMap.put(Manifest.permission.SEND_SMS,
+ "@android:string/permgrouplab_sms");
+ sPermissionToLabelResNameMap.put(Manifest.permission.RECEIVE_SMS,
+ "@android:string/permgrouplab_sms");
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_SMS,
+ "@android:string/permgrouplab_sms");
+ sPermissionToLabelResNameMap.put(Manifest.permission.RECEIVE_WAP_PUSH,
+ "@android:string/permgrouplab_sms");
+ sPermissionToLabelResNameMap.put(Manifest.permission.RECEIVE_MMS,
+ "@android:string/permgrouplab_sms");
+ sPermissionToLabelResNameMap.put("android.permission.READ_CELL_BROADCASTS",
+ "@android:string/permgrouplab_sms");
+ // Storage
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_EXTERNAL_STORAGE,
+ "@android:string/permgrouplab_storage");
+ sPermissionToLabelResNameMap.put(Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ "@android:string/permgrouplab_storage");
+ // Location
+ sPermissionToLabelResNameMap.put(Manifest.permission.ACCESS_FINE_LOCATION,
+ "@android:string/permgrouplab_location");
+ sPermissionToLabelResNameMap.put(Manifest.permission.ACCESS_COARSE_LOCATION,
+ "@android:string/permgrouplab_location");
+ // Phone
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_PHONE_STATE,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.CALL_PHONE,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put("android.permission.ACCESS_IMS_CALL_SERVICE",
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.READ_CALL_LOG,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.WRITE_CALL_LOG,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.ADD_VOICEMAIL,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.USE_SIP,
+ "@android:string/permgrouplab_phone");
+ sPermissionToLabelResNameMap.put(Manifest.permission.PROCESS_OUTGOING_CALLS,
+ "@android:string/permgrouplab_phone");
+ // Microphone
+ sPermissionToLabelResNameMap.put(Manifest.permission.RECORD_AUDIO,
+ "@android:string/permgrouplab_microphone");
+ // Camera
+ sPermissionToLabelResNameMap.put(Manifest.permission.CAMERA,
+ "@android:string/permgrouplab_camera");
+ // Body sensors
+ sPermissionToLabelResNameMap.put(Manifest.permission.BODY_SENSORS,
+ "@android:string/permgrouplab_sensors");
+ }
+
+ private Context mContext;
+ private Resources mPlatformResources;
+
+ protected static Instrumentation getInstrumentation() {
+ return InstrumentationRegistry.getInstrumentation();
+ }
+
+ protected static void assertPermissionRequestResult(BasePermissionActivity.Result result,
+ int requestCode, String[] permissions, boolean[] granted) {
+ assertEquals(requestCode, result.requestCode);
+ for (int i = 0; i < permissions.length; i++) {
+ assertEquals(permissions[i], result.permissions[i]);
+ assertEquals(granted[i] ? PackageManager.PERMISSION_GRANTED
+ : PackageManager.PERMISSION_DENIED, result.grantResults[i]);
+
+ }
+ }
+
+ protected static UiDevice getUiDevice() {
+ return UiDevice.getInstance(getInstrumentation());
+ }
+
+ protected static Activity launchActivity(String packageName,
+ Class<?> clazz, Bundle extras) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClassName(packageName, clazz.getName());
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ Activity activity = getInstrumentation().startActivitySync(intent);
+ getInstrumentation().waitForIdleSync();
+
+ return activity;
+ }
+
+ @Before
+ public void beforeTest() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ try {
+ Context platformContext = mContext.createPackageContext(PLATFORM_PACKAGE_NAME, 0);
+ mPlatformResources = platformContext.getResources();
+ } catch (PackageManager.NameNotFoundException e) {
+ /* cannot happen */
+ }
+ }
+
+ protected BasePermissionActivity.Result requestPermissions(
+ String[] permissions, int requestCode, Class<?> clazz, Runnable postRequestAction)
+ throws Exception {
+ // Start an activity
+ BasePermissionActivity activity = (BasePermissionActivity) launchActivity(
+ getInstrumentation().getTargetContext().getPackageName(), clazz, null);
+
+ activity.waitForOnCreate();
+
+ // Request the permissions
+ activity.requestPermissions(permissions, requestCode);
+
+ // Define a more conservative idle criteria
+ getInstrumentation().getUiAutomation().waitForIdle(
+ IDLE_TIMEOUT_MILLIS, GLOBAL_TIMEOUT_MILLIS);
+
+ // Perform the post-request action
+ if (postRequestAction != null) {
+ postRequestAction.run();
+ }
+
+ BasePermissionActivity.Result result = activity.getResult();
+ activity.finish();
+ return result;
+ }
+
+ protected void clickAllowButton() throws Exception {
+ getUiDevice().findObject(new UiSelector().resourceId(
+ "com.android.packageinstaller:id/permission_allow_button")).click();
+ }
+
+ protected void clickDenyButton() throws Exception {
+ getUiDevice().findObject(new UiSelector().resourceId(
+ "com.android.packageinstaller:id/permission_deny_button")).click();
+ }
+
+ protected void clickDontAskAgainCheckbox() throws Exception {
+ getUiDevice().findObject(new UiSelector().resourceId(
+ "com.android.packageinstaller:id/do_not_ask_checkbox")).click();
+ }
+
+ protected void grantPermission(String permission) throws Exception {
+ grantPermissions(new String[]{permission});
+ }
+
+ protected void grantPermissions(String[] permissions) throws Exception {
+ setPermissionGrantState(permissions, true, false);
+ }
+
+ protected void revokePermission(String permission) throws Exception {
+ revokePermissions(new String[] {permission}, false);
+ }
+
+ protected void revokePermissions(String[] permissions, boolean legacyApp) throws Exception {
+ setPermissionGrantState(permissions, false, legacyApp);
+ }
+
+ private void setPermissionGrantState(String[] permissions, boolean granted,
+ boolean legacyApp) throws Exception {
+ getUiDevice().pressBack();
+ getUiDevice().waitForIdle();
+ getUiDevice().pressBack();
+ getUiDevice().waitForIdle();
+
+ // Open the app details settings
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setData(Uri.parse("package:" + mContext.getPackageName()));
+ mContext.startActivity(intent);
+
+ getUiDevice().waitForIdle();
+
+ // Open the permissions UI
+ UiObject permissionItem = getUiDevice().findObject(new UiSelector().text("Permissions"));
+ permissionItem.click();
+
+ getUiDevice().waitForIdle();
+
+ for (String permission : permissions) {
+ // Find the permission toggle
+ String permissionLabel = getPermissionLabel(permission);
+
+ UiObject2 toggleSwitch = null;
+ UiObject2 current = getUiDevice().findObject(By.text(permissionLabel));
+ Assert.assertNotNull("Permission should be present");
+
+ while (toggleSwitch == null) {
+ UiObject2 parent = current.getParent();
+ if (parent == null) {
+ fail("Cannot find permission list item");
+ }
+ toggleSwitch = current.findObject(By.clazz(Switch.class));
+ current = parent;
+ }
+
+ final boolean wasGranted = toggleSwitch.isChecked();
+ if (granted != wasGranted) {
+ // Toggle the permission
+ toggleSwitch.click();
+
+ getUiDevice().waitForIdle();
+
+ if (wasGranted && legacyApp) {
+ String packageName = getInstrumentation().getContext().getPackageManager()
+ .getPermissionControllerPackageName();
+ String resIdName = "com.android.packageinstaller"
+ + ":string/grant_dialog_button_deny_anyway";
+ Resources resources = getInstrumentation().getContext()
+ .createPackageContext(packageName, 0).getResources();
+ final int confirmResId = resources.getIdentifier(resIdName, null, null);
+ String confirmTitle = resources.getString(confirmResId);
+ UiObject denyAnyway = getUiDevice().findObject(new UiSelector()
+ .text(confirmTitle.toUpperCase()));
+ denyAnyway.click();
+
+ getUiDevice().waitForIdle();
+ }
+ }
+ }
+
+ getUiDevice().pressBack();
+ getUiDevice().waitForIdle();
+ getUiDevice().pressBack();
+ getUiDevice().waitForIdle();
+ }
+
+ private String getPermissionLabel(String permission) throws Exception {
+ String labelResName = sPermissionToLabelResNameMap.get(permission);
+ assertNotNull("Unknown permisison " + permission, labelResName);
+ final int resourceId = mPlatformResources.getIdentifier(labelResName, null, null);
+ return mPlatformResources.getString(resourceId);
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
new file mode 100644
index 0000000..9908a45
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -0,0 +1,561 @@
+/*
+ * 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.usepermission;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.logCommand;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import org.junit.Test;
+
+/**
+ * Runtime permission behavior tests for apps targeting API 23
+ */
+public class UsePermissionTest23 extends BasePermissionsTest {
+ private static final int REQUEST_CODE_PERMISSIONS = 42;
+
+ public void testFail() throws Exception {
+ fail("Expected");
+ }
+
+ @Test
+ public void testKill() throws Exception {
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+
+ // New permission model is denied by default
+ assertAllPermissionsRevoked();
+
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ assertDirNoAccess(Environment.getExternalStorageDirectory());
+ assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
+ assertMediaNoAccess(getInstrumentation().getContext().getContentResolver(), false);
+ }
+
+ @Test
+ public void testGranted() throws Exception {
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+ grantPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
+ assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
+ assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
+ }
+
+ @Test
+ public void testInteractiveGrant() throws Exception {
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+
+ // Start out without permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ assertDirNoAccess(Environment.getExternalStorageDirectory());
+ assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
+ assertMediaNoAccess(getInstrumentation().getContext().getContentResolver(), false);
+
+ // Go through normal grant flow
+ BasePermissionActivity.Result result = requestPermissions(new String[] {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE},
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class,
+ () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ assertEquals(REQUEST_CODE_PERMISSIONS, result.requestCode);
+ assertEquals(Manifest.permission.READ_EXTERNAL_STORAGE, result.permissions[0]);
+ assertEquals(Manifest.permission.WRITE_EXTERNAL_STORAGE, result.permissions[1]);
+ assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
+ assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[1]);
+
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+
+ // We should have permission now!
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
+ assertDirReadWriteAccess(getInstrumentation().getContext().getExternalCacheDir());
+ assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
+ }
+
+ @Test
+ public void testRuntimeGroupGrantSpecificity() throws Exception {
+ // Start out without permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CONTACTS));
+
+ String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
+
+ // request only one permission from the 'contacts' permission group
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class,
+ () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {true});
+
+ // Make sure no undeclared as used permissions are granted
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CONTACTS));
+ }
+
+ @Test
+ public void testRuntimeGroupGrantExpansion() throws Exception {
+ // Start out without permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+
+ String[] permissions = new String[] {Manifest.permission.RECEIVE_SMS};
+
+ // request only one permission from the 'SMS' permission group at runtime,
+ // but two from this group are <uses-permission> in the manifest
+ // request only one permission from the 'contacts' permission group
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class,
+ () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {true});
+
+ // We should now have been granted both of the permissions from this group.
+ // NOTE: This is undesired behavior which will be fixed for target API 24.
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+ }
+
+ @Test
+ public void testCancelledPermissionRequest() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+
+ String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
+
+ // Request the permission and cancel the request
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class,
+ () -> {
+ try {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {false});
+ }
+
+ @Test
+ public void testRequestGrantedPermission() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+
+ String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
+
+ // Request the permission and allow it
+ BasePermissionActivity.Result firstResult = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {true});
+
+ // Request the permission and do nothing
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
+ Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
+ BasePermissionActivity.class, null);
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
+ permissions, new boolean[] {true});
+ }
+
+ @Test
+ public void testDenialWithPrejudice() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+
+ String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
+
+ // Request the permission and deny it
+ BasePermissionActivity.Result firstResult = requestPermissions(
+ permissions, REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {false});
+
+ // Request the permission and choose don't ask again
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
+ Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickDontAskAgainCheckbox();
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
+ permissions, new boolean[] {false});
+
+ // Request the permission and do nothing
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
+ Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 2,
+ BasePermissionActivity.class, null);
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
+ permissions, new boolean[] {false});
+ }
+
+ @Test
+ public void testRevokeAffectsWholeGroup_part1() throws Exception {
+ // Grant the group
+ grantPermission(Manifest.permission.READ_CALENDAR);
+
+ // Make sure we have the permissions
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
+
+ // Revoke the group
+ revokePermission(Manifest.permission.READ_CALENDAR);
+
+ // We just committed a suicide by revoking the permission. See part2 below...
+ }
+
+ public void testRevokeAffectsWholeGroup_part2() throws Exception {
+ // Make sure we don't have the permissions
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
+ }
+
+ @Test
+ public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+
+ String[] permissions = new String[] {Manifest.permission.READ_CALENDAR};
+
+ // Request the permission and deny it
+ BasePermissionActivity.Result firstResult = requestPermissions(
+ permissions, REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {false});
+
+ // Request the permission and choose don't ask again
+ BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
+ Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 1,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickDontAskAgainCheckbox();
+ clickDenyButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
+ permissions, new boolean[] {false});
+
+ // Clear the denial with prejudice
+ grantPermission(Manifest.permission.READ_CALENDAR);
+ revokePermission(Manifest.permission.READ_CALENDAR);
+
+ // We just committed a suicide by revoking the permission. See part2 below...
+ }
+
+ @Test
+ public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part2() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+
+ // Request the permission and allow it
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
+ Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 2,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Make sure the permission is granted
+ assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
+ new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
+ }
+
+ @Test
+ public void testRequestNonRuntimePermission() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.BIND_PRINT_SERVICE));
+
+ String[] permissions = new String[] {Manifest.permission.BIND_PRINT_SERVICE};
+
+ // Request the permission and do nothing
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {false});
+ }
+
+ @Test
+ public void testRequestNonExistentPermission() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission("permission.does.not.exist"));
+
+ String[] permissions = new String[] {"permission.does.not.exist"};
+
+ // Request the permission and do nothing
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {false});
+ }
+
+ @Test
+ public void testRequestPermissionFromTwoGroups() throws Exception {
+ // Make sure we don't have the permissions
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
+
+ String[] permissions = new String[] {
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.WRITE_CALENDAR
+ };
+
+ // Request the permission and do nothing
+ BasePermissionActivity.Result result = requestPermissions(permissions,
+ REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is not granted
+ assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
+ permissions, new boolean[] {true, true});
+ }
+
+ @Test
+ public void testNoResidualPermissionsOnUninstall_part1() throws Exception {
+ // Grant all permissions
+ grantPermissions(new String[] {
+ Manifest.permission.WRITE_CALENDAR,
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_SMS,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.BODY_SENSORS,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.CAMERA
+ });
+ }
+
+ @Test
+ public void testNoResidualPermissionsOnUninstall_part2() throws Exception {
+ // Make no permissions are granted after uninstalling and installing the app
+ assertAllPermissionsRevoked();
+ }
+
+ @Test
+ public void testRevokePropagatedOnUpgradeOldToNewModel_part2() throws Exception {
+ assertPermissionsGrantState(new String[] {Manifest.permission.WRITE_CALENDAR},
+ PackageManager.PERMISSION_DENIED);
+ }
+
+
+ public void testRevokePropagatedOnUpgradeNewToNewModel_part1() throws Exception {
+ // Make sure we don't have the permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.READ_CALENDAR));
+
+ // Request the permission and allow it
+ BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
+ Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class, () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Make sure the permission is granted
+ assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS,
+ new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
+ }
+
+ public void testRevokePropagatedOnUpgradeNewToNewModel_part2() throws Exception {
+ // Make sure the permission is still granted after the upgrade
+ assertPermissionsGrantState(new String[] {Manifest.permission.READ_CALENDAR},
+ PackageManager.PERMISSION_GRANTED);
+ // Also make sure one of the not granted permissions is still not granted
+ assertPermissionsGrantState(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE},
+ PackageManager.PERMISSION_DENIED);
+ }
+
+ private void assertAllPermissionsRevoked() {
+ assertAllPermissionsGrantState(PackageManager.PERMISSION_DENIED);
+ }
+
+ private void assertAllPermissionsGrantState(int grantState) {
+ assertPermissionsGrantState(new String[] {
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.RECEIVE_SMS,
+ Manifest.permission.RECEIVE_WAP_PUSH,
+ Manifest.permission.RECEIVE_MMS,
+ Manifest.permission.READ_CALENDAR,
+ Manifest.permission.WRITE_CALENDAR,
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_SMS,
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.READ_CALL_LOG,
+ Manifest.permission.WRITE_CALL_LOG,
+ Manifest.permission.ADD_VOICEMAIL,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.USE_SIP,
+ Manifest.permission.PROCESS_OUTGOING_CALLS,
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.BODY_SENSORS,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.CAMERA,
+ Manifest.permission.BODY_SENSORS,
+ "android.permission.READ_CELL_BROADCASTS"
+ }, grantState);
+ }
+
+ private void assertPermissionsGrantState(String[] permissions, int grantState) {
+ for (String permission : permissions) {
+ assertEquals(grantState, getInstrumentation().getContext()
+ .checkSelfPermission(permission));
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
similarity index 79%
copy from hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
copy to hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
index 4630f1f..d280372 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2015 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.
@@ -19,13 +19,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+ ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionActivity.java \
+ ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp
+LOCAL_PACKAGE_NAME := CtsUsePermissionApp24
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml
similarity index 61%
copy from hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
copy to hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml
index 253d85d..64f3f34 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
@@ -16,12 +16,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.usepermission">
+
+ <!-- Request two different permissions within the same group -->
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+
<application>
- <uses-library android:name="android.test.runner" />
- <activity android:name=".MyActivity" />
+ <activity android:name="com.android.cts.usepermission.BasePermissionActivity" />
</application>
+
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.usepermission" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.usepermission" />
+
</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java
new file mode 100644
index 0000000..f87c67f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp24/src/com/android/cts/usepermission/UsePermissionTest24.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.android.cts.usepermission;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+/**
+ * Runtime permission behavior tests for apps targeting API 24
+ */
+public class UsePermissionTest24 extends BasePermissionsTest {
+ private static final int REQUEST_CODE_PERMISSIONS = 42;
+
+ @Test
+ public void testOnlyRequestedPermissionsGranted() throws Exception {
+ // Start out without permission
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+
+ String[] firstPermissions = new String[] {Manifest.permission.RECEIVE_SMS};
+
+ // Request only one permission and confirm
+ BasePermissionActivity.Result firstResult = requestPermissions(firstPermissions,
+ REQUEST_CODE_PERMISSIONS,
+ BasePermissionActivity.class,
+ () -> {
+ try {
+ clickAllowButton();
+ getUiDevice().waitForIdle();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
+ firstPermissions, new boolean[] {true});
+
+ // We should not have the other permission in the group
+ assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+
+ String[] secondPermissions = new String[] {Manifest.permission.SEND_SMS};
+
+ // Request the other permission which should be auto-granted
+ BasePermissionActivity.Result secondResult = requestPermissions(secondPermissions,
+ REQUEST_CODE_PERMISSIONS + 1, BasePermissionActivity.class, null);
+
+ // Expect the permission is granted
+ assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
+ secondPermissions, new boolean[] {true});
+
+ // We now should have both permissions
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
+ assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
+ .checkSelfPermission(Manifest.permission.SEND_SMS));
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
deleted file mode 100644
index 8727c43..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 21
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-
-LOCAL_PACKAGE_NAME := CtsUsePermissionAppCompat
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/src/com/android/cts/usepermission/UsePermissionCompatTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/src/com/android/cts/usepermission/UsePermissionCompatTest.java
deleted file mode 100644
index 7f21d3400..0000000
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/src/com/android/cts/usepermission/UsePermissionCompatTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.usepermission;
-
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaNoAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.logCommand;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.os.Process;
-import android.test.InstrumentationTestCase;
-
-import java.io.File;
-
-public class UsePermissionCompatTest extends InstrumentationTestCase {
- private static final String TAG = "UsePermissionTest";
-
- public void testCompatDefault() throws Exception {
- final Context context = getInstrumentation().getContext();
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- // Legacy permission model is granted by default
- assertEquals(PackageManager.PERMISSION_GRANTED,
- context.checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE,
- Process.myPid(), Process.myUid()));
- assertEquals(PackageManager.PERMISSION_GRANTED,
- context.checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Process.myPid(), Process.myUid()));
- assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
- assertDirReadWriteAccess(Environment.getExternalStorageDirectory());
- for (File path : getAllPackageSpecificPaths(context)) {
- if (path != null) {
- assertDirReadWriteAccess(path);
- }
- }
- assertMediaReadWriteAccess(getInstrumentation().getContext().getContentResolver());
- }
-
- public void testCompatRevoked() throws Exception {
- final Context context = getInstrumentation().getContext();
- logCommand("/system/bin/cat", "/proc/self/mountinfo");
-
- // Legacy permission model appears granted, but storage looks and
- // behaves like it's ejected
- assertEquals(PackageManager.PERMISSION_GRANTED,
- context.checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE,
- Process.myPid(), Process.myUid()));
- assertEquals(PackageManager.PERMISSION_GRANTED,
- context.checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Process.myPid(), Process.myUid()));
- assertEquals(Environment.MEDIA_UNMOUNTED, Environment.getExternalStorageState());
- assertDirNoAccess(Environment.getExternalStorageDirectory());
- for (File dir : getAllPackageSpecificPaths(context)) {
- if (dir != null) {
- assertDirNoAccess(dir);
- }
- }
- assertMediaNoAccess(getInstrumentation().getContext().getContentResolver());
-
- // Just to be sure, poke explicit path
- assertDirNoAccess(new File(Environment.getExternalStorageDirectory(),
- "/Android/data/" + getInstrumentation().getContext().getPackageName()));
- }
-}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
similarity index 96%
rename from hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
rename to hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
index 4630f1f..2d5dd4f 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
@@ -25,7 +25,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-LOCAL_PACKAGE_NAME := CtsUsePermissionApp
+LOCAL_PACKAGE_NAME := CtsUsesLibraryApp
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
similarity index 83%
rename from hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
rename to hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
index 253d85d..4557af0 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
@@ -15,13 +15,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.usepermission">
+ package="com.android.cts.useslibrary">
<application>
<uses-library android:name="android.test.runner" />
<activity android:name=".MyActivity" />
</application>
<instrumentation
android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.usepermission" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ android:targetPackage="com.android.cts.useslibrary" />
</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
new file mode 100644
index 0000000..0a1f012
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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 com.android.cts.useslibrary;
+
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+import android.test.InstrumentationTestCase;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.DexFile;
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class UsesLibraryTest extends InstrumentationTestCase {
+ private static final String TAG = "UsesLibraryTest";
+
+ public void testUsesLibrary() throws Exception {
+ ClassLoader loader = getClass().getClassLoader();
+ if (loader instanceof BaseDexClassLoader) {
+ Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
+ for (Object dexElement : dexElements) {
+ DexFile dexFile = getDexFileFromDexElement(dexElement);
+ assertTrue(isDexFileBackedByOatFile(dexFile));
+ }
+ }
+ }
+
+ public void testMissingLibrary() throws Exception {
+ ClassLoader loader = getClass().getClassLoader();
+ if (loader instanceof BaseDexClassLoader) {
+ Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
+ assertTrue(dexElements != null && dexElements.length > 1);
+
+ DexFile dexFile = getDexFileFromDexElement(dexElements[1]);
+ String testApkPath = dexFile.getName();
+ PathClassLoader testLoader = new PathClassLoader(testApkPath, null);
+ Object[] testDexElements = getDexElementsFromClassLoader(testLoader);
+ assertTrue(testDexElements != null && testDexElements.length == 1);
+
+ DexFile testDexFile = getDexFileFromDexElement(testDexElements[0]);
+ assertTrue(isDexFileBackedByOatFile(testDexFile));
+ }
+ }
+
+ public void testDuplicateLibrary() throws Exception {
+ ClassLoader loader = getClass().getClassLoader();
+ if (loader instanceof BaseDexClassLoader) {
+ Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
+ assertTrue(dexElements != null && dexElements.length > 1);
+
+ DexFile libDexFile = getDexFileFromDexElement(dexElements[0]);
+ String libPath = libDexFile.getName();
+ DexFile apkDexFile = getDexFileFromDexElement(dexElements[1]);
+ String apkPath = apkDexFile.getName();
+ String testPath = libPath + File.pathSeparator + apkPath + File.pathSeparator + apkPath;
+ PathClassLoader testLoader = new PathClassLoader(testPath, null);
+ Object[] testDexElements = getDexElementsFromClassLoader(testLoader);
+ assertTrue(testDexElements != null && testDexElements.length == 3);
+
+ DexFile testDexFile = getDexFileFromDexElement(testDexElements[2]);
+ assertFalse(isDexFileBackedByOatFile(testDexFile));
+ }
+ }
+
+ private Object[] getDexElementsFromClassLoader(BaseDexClassLoader loader) throws Exception {
+ Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList");
+ pathListField.setAccessible(true);
+ // This is a DexPathList, but that class is package private.
+ Object pathList = pathListField.get(loader);
+ Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
+ dexElementsField.setAccessible(true);
+ // The objects in this array are Elements, but that class is package private.
+ return (Object[]) dexElementsField.get(pathList);
+ }
+
+ // The argument must be a DexPathList.Element.
+ private DexFile getDexFileFromDexElement(Object dexElement) throws Exception {
+ Field dexFileField = dexElement.getClass().getDeclaredField("dexFile");
+ dexFileField.setAccessible(true);
+ return (DexFile) dexFileField.get(dexElement);
+ }
+
+ private boolean isDexFileBackedByOatFile(DexFile dexFile) throws Exception {
+ Method isBackedByOatFileMethod = DexFile.class.getDeclaredMethod("isBackedByOatFile");
+ isBackedByOatFileMethod.setAccessible(true);
+ return (boolean) isBackedByOatFileMethod.invoke(dexFile);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index 54c0716..18d1b8b 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util
LOCAL_SDK_VERSION := test_current
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
new file mode 100644
index 0000000..c27a473
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/ca.conf
@@ -0,0 +1,156 @@
+# OpenSSL root CA configuration file.
+# Copy to `/root/ca/openssl.cnf`.
+
+[ ca ]
+# `man ca`
+
+[ RootCA ]
+# Directory and file locations.
+dir = ./rootca
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+# The root key and root certificate.
+private_key = $dir/private/ca.key.pem
+certificate = $dir/certs/ca.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/ca.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_strict
+
+[ IntermediateCA ]
+# Directory and file locations.
+dir = ./intermediate
+certs = $dir/certs
+crl_dir = $dir/crl
+new_certs_dir = $dir/newcerts
+database = $dir/index.txt
+serial = $dir/serial
+RANDFILE = $dir/private/.rand
+
+# The root key and root certificate.
+private_key = $dir/private/intermediate.key.pem
+certificate = $dir/certs/intermediate.cert.pem
+
+# For certificate revocation lists.
+crlnumber = $dir/crlnumber
+crl = $dir/crl/ca.crl.pem
+crl_extensions = crl_ext
+default_crl_days = 30
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+name_opt = ca_default
+cert_opt = ca_default
+default_days = 375
+preserve = no
+policy = policy_strict
+
+[ policy_strict ]
+# The root CA should only sign intermediate certificates that match.
+# See the POLICY FORMAT section of `man ca`.
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+[ req ]
+# Options for the `req` tool (`man req`).
+default_bits = 4096
+distinguished_name = req_distinguished_name
+string_mask = utf8only
+
+# SHA-1 is deprecated, so use SHA-2 instead.
+default_md = sha256
+
+# Extension to add when the -x509 option is used.
+x509_extensions = v3_ca
+
+[ req_distinguished_name ]
+# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
+countryName = Country Name (2 letter code)
+stateOrProvinceName = State or Province Name
+0.organizationName = Organization Name
+organizationalUnitName = Organizational Unit Name
+commonName = Common Name
+
+# Optionally, specify some defaults.
+countryName_default = GB
+stateOrProvinceName_default = England
+0.organizationName_default = Google UK
+organizationalUnitName_default = AfW
+
+[ v3_ca ]
+# Extensions for a typical CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ v3_intermediate_ca ]
+# Extensions for a typical intermediate CA (`man x509v3_config`).
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical, CA:true, pathlen:0
+keyUsage = critical, digitalSignature, cRLSign, keyCertSign
+
+[ usr_cert ]
+# Extensions for client certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = client, email
+nsComment = "OpenSSL Generated Client Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
+extendedKeyUsage = clientAuth, emailProtection
+
+[ server_cert ]
+# Extensions for server certificates (`man x509v3_config`).
+basicConstraints = CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+keyUsage = critical, digitalSignature, keyEncipherment
+extendedKeyUsage = serverAuth
+
+[ crl_ext ]
+# Extension for CRLs (`man x509v3_config`).
+authorityKeyIdentifier=keyid:always
+
+[ ocsp ]
+# Extension for OCSP signing certificates (`man ocsp`).
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, OCSPSigning
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
new file mode 100755
index 0000000..8b0639f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/generate-client-cert-chain.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+#
+# Generates:
+# - user-cert-chain.crt
+# - user-cert-chain.key
+#
+
+set -e
+
+WORKDIR='temp'
+
+mkdir "$WORKDIR"
+cp ca.conf "$WORKDIR/"
+pushd "$WORKDIR"
+
+## Generate root CA
+mkdir -p rootca/{certs,crl,newcerts,private}
+pushd rootca
+touch index.txt
+echo '1000' > serial
+openssl req \
+ -config ../ca.conf \
+ -new \
+ -x509 \
+ -days 7300 \
+ -sha256 \
+ -extensions v3_ca \
+ -keyout private/ca.key.pem \
+ -out certs/ca.cert.pem
+popd
+
+## Generate Intermediate CA
+mkdir intermediate intermediate/{certs,crl,csr,newcerts,private}
+touch intermediate/index.txt
+
+echo '1000' > intermediate/serial
+echo '1000' > intermediate/crlnumber
+
+openssl req \
+ -config ca.conf \
+ -new \
+ -sha256 \
+ -keyout intermediate/private/intermediate.key.pem \
+ -out intermediate/csr/intermediate.csr.pem
+
+openssl ca \
+ -config ca.conf \
+ -name RootCA \
+ -extensions v3_intermediate_ca \
+ -days 3650 \
+ -notext \
+ -md sha256 \
+ -in intermediate/csr/intermediate.csr.pem \
+ -out intermediate/certs/intermediate.cert.pem
+
+## Generate client cert
+openssl req \
+ -config ca.conf \
+ -newkey rsa:1024 \
+ -keyout user.key.pem \
+ -nodes \
+ -days 3650 \
+ -out user.csr.pem
+
+openssl ca \
+ -config ca.conf \
+ -name IntermediateCA \
+ -extensions usr_cert \
+ -days 365 \
+ -notext \
+ -md sha256 \
+ -in user.csr.pem \
+ -out user.cert.pem
+
+popd # WORKDIR
+
+## Convert client cert to acceptable form
+cat \
+ "$WORKDIR"/user.cert.pem \
+ "$WORKDIR"/intermediate/certs/intermediate.cert.pem \
+ "$WORKDIR"/rootca/certs/ca.cert.pem \
+ > user-cert-chain.crt
+
+openssl pkcs8 \
+ -topk8 \
+ -nocrypt \
+ -inform PEM \
+ -outform DER \
+ -in "$WORKDIR"/user.key.pem \
+ -out user-cert-chain.key
+
+rm -r "$WORKDIR"
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
new file mode 100644
index 0000000..72a86e3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.crt
@@ -0,0 +1,96 @@
+-----BEGIN CERTIFICATE-----
+MIIFLzCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZ3MSEwHwYDVQQDDBhBZlcgVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMTYwMzE4
+MTcxMzA4WhcNMTcwMzI4MTcxMzA4WjCBiDELMAkGA1UEBhMCR0IxEDAOBgNVBAgM
+B0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSUwIwYD
+VQQDDBxVc2VyMDAgdW5kZXIgaW50ZXJtZWRpYXRlIENBMR4wHAYJKoZIhvcNAQkB
+Fg90ZXN0QGdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC8W+PUeNVDIy6GSeTVjN9JSkYxcsupFq9AOUma0R+7z9EGuZBURZprgbrN7c2q
+RQnlSBZTC9fRMkXZ6LImWoY5GqS3NcbkJbUlA+UeK2uJXQQfjTO7bYDslvudX+8y
+WfYrR71DLpIFgDkxQAWGywMzNTR6TEmPy1qBGIFYohGqZkQoTS//s/iEEKDSsbPr
+mkTrf4lDAc8cgnmUPFPkN1Lr4ITkvhmEHQjJTcS+Qjeotlt+ss5vrmlqopFkCbI9
+7uC6RQDI0PvP9achzBsTUi0vNsGg45luCJhNrDu6s4NpnusKIVAoJPSJdion2yoD
+3Dp8LX/ueGNbP64LY6qmDWDlAgMBAAGjgcUwgcIwCQYDVR0TBAIwADARBglghkgB
+hvhCAQEEBAMCBaAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJhdGVkIENs
+aWVudCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUSp7kS1On3b7MdMstDVPCNkHm/EUw
+HwYDVR0jBBgwFoAUdejD6Fb3X8ZHOCKMWe5XwukxBDswDgYDVR0PAQH/BAQDAgXg
+MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQsFAAOC
+AgEAXIOVhMjxbpO1uxe1MnyIsTrl0ajPlkn+4qWLwjXzUQ6TcE2Ow91AMcYs5siq
+UBplZyNYNBOhX8TZLNy7jJ/REwj65Qa/y0TcDucpGhtT9l1JIJCdEpPoymyiM18C
+NktXDyaw+DFkWC0a5oUhjk4UuzTfHkSVMKjZUnRPPiwL2gl9zEgS8qVI3ew4JjdP
+KCYGy/1B+61EE5vCP8GAByeKgtgnh4sVZnsKYQZzjwwUGL1uXQtazPs04qTUw3IK
+YvoOyNsXB4gcp2u4DXv2roVI36DQM5ZGenS9MViTeblg5vkZgy8xsktHyDGDlNe6
+cPw5OgyxDo4nr6TY4SX9eankantPMx7498n390B4lYAgBj4Cz4QaXM1IGN3JVF5J
+EEKqGkLpOYMRNZ4qPFhMknDZgHljjgFlcXGwtXtugCzQ5ldwkFb9qZeB5lQn1Aw0
+PthcDdGp/KCtHC5jF+BjlQITt0tVqJ4+SAdHyF53H+ScoINFul89m32pgvJjI/0k
+c0tidvXNPNodbJCqHmc917DryVJGXbxp+BqxTQ0a7e9K/WA4MnRKPfBTTeDq/j+w
+6B/rLd0bhMrPDi6a/1w97PqfAbS9TlkpnK8Gj4pN+ZOEEF0j0DtDRbb+CfJX14fR
+2R96mEfCeSbCuxLcbwdG1OUQM8GKlIcYfWIp0KjICxRKaDU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXDELMAkGA1UEBhMCR0Ix
+EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwD
+QWZXMRkwFwYDVQQDDBBBZncgVGVzdCBSb290IENBMB4XDTE2MDMxODE3MDQ1N1oX
+DTI2MDMxNjE3MDQ1N1owZDELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQx
+EjAQBgNVBAoMCUdvb2dsZSBVSzEMMAoGA1UECwwDQWZ3MSEwHwYDVQQDDBhBZlcg
+VGVzdCBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCZbYchy2Fry9nJuu2YEp2P13lIbyWu0FXF8qTus8Vp/25LyXDjBiDXZUlY
+PL32PY0PRbBQjm7tm/WNqXw8S7gw+5XXpY+XNCd/ygyIZhMdxPm7nqYsEtZDFViL
+ct/QJNAKILFejZQOfRSeyxeINprL+EjFHecA6KtruZULzJE0u0UGTgs5h9HbqhH7
+LbZ8iiE/TfG6kflUI2kAPxGiRpIyerYoVjp3Ta5026T+aoc6VyNnSYiZULgYLoL8
+P8x19G3Pplqf4U5bUyKtRtnPWOvM9iYphxsVuTc8rRpZGcMKhdL4gGLQpdruIZ43
+gvGMq4Kt2xVJExBOKMg3j3x52j1XtOcad/nz7ncak/6ElTd0gfhFgt9PwAfQZ32b
+BL3Zlcb+7Pvtv14xAWNHy5cMyn7UDzIsy/yqWLvJSfkZViU0vPuokXMKZIyzv73V
+4N9qXQAWXNz4HwgWy35rB1sirgMxLdWCpHrVeh/DzSrWZ/MtJIC9Ac1jTAuI6F1u
+b7dRRujWpcr57ReKDXXJzM83JQnENJQ3gAHrY8qTkGz7NLa7DsyzPdKOC7vZ0+Ed
+VMvn+c2AMWrwkRpn9JlU5bd2BN7D6UWGLTdzSN9QH7n7sXmQNAo/M7Lr9baxKZNY
+aU5DORVjnGvITZDHYiw9OuakWZUZATF+TTInKEasF131r9q9ZwIDAQABo2YwZDAd
+BgNVHQ4EFgQUdejD6Fb3X8ZHOCKMWe5XwukxBDswHwYDVR0jBBgwFoAUV4EHHOi0
+AqQIj4IMjPEFW3fVS8QwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC
+AYYwDQYJKoZIhvcNAQELBQADggIBACs0qS3EXymo1VgBInR9GrzvUq1gC/d3ohSG
+iB3x2zfqfQ4D0eiYADcCdXTPIwPtm8P8woK5QsRV/MCklqyvgVpRHFQe1uOAZJ7X
+Ud6hx9CCye0QkEoy+JDeVdPeFFf1b8S/daxLXUVbCKSTA+z8YLPRSEFi2d3cOwpx
+WPlkfLSwP6DfODicmPNd1V/qB/fevlmfRB6UKquT+v9xWyQqu4aa6F6xGWYWmc+1
+E/MB/oEOizJVv8VVETqMk8/xFPrMk28foI8ohrLkstSx8gH+oII1Ud1k1XoMMqqU
+Ge656Tr85Di5WfacMdKUommOEKQYRiic6ikcNEAVVNOHlOtw08ua7g1k1G/dwcj0
+DCF2WmWzdAMwST0AH/RPa+i9cX8f/yS15OUP7ncSaI7/ChGT3EBzP+bqxeXFOCNH
+0yNLk4tNLIzNwnKXGTfSbKMTYOZ3ngAiR4w3ro/LJhe2z03MOawxoiIosTc9UwKA
+YJ3nYHYw8/EJCKPth6yrUU3gU1V0vyaBy34y4xuha3oWnbc53vm1cv4BINwmuAms
+ASQpqCiGp2ZaalNu87xCnWE3HA4S3+0U3dsFJXdPdQt/cDzX+kDzojWeHmECp6mn
+GodmmPbEBqzDckMaM9CvSAp8NyZuO8hrOSoGTdxQtP1w3waOeM4zLYd7aBYUfefL
+36OoziEN
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFnjCCA4agAwIBAgIJANLdX1zcxUSUMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV
+BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAK
+BgNVBAsMA0FmVzEZMBcGA1UEAwwQQWZ3IFRlc3QgUm9vdCBDQTAeFw0xNjAzMTgx
+NzAxMDBaFw0zNjAzMTMxNzAxMDBaMFwxCzAJBgNVBAYTAkdCMRAwDgYDVQQIDAdF
+bmdsYW5kMRIwEAYDVQQKDAlHb29nbGUgVUsxDDAKBgNVBAsMA0FmVzEZMBcGA1UE
+AwwQQWZ3IFRlc3QgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBANFyOD/BIGV4iHSGDrp1ajvp+00098dn+p1cqlMHMrWUjnqzcMdOVmeqSaQ/
+EkOlAIsdcl1yb+oo3DhomIzX/B2lTQSOSLDmthIgmu0hfk/gAiqLdA8/L2F9m64N
+9x4+72xscN3MxzvjKGUBgPDmRfR9Tp347j42HUCjmF5sTa7DzGMrU7I3gCmi7B3D
+zbkgdTwpucH2JDqHQPv+7PLaNyuZNEmiXM76DPyMypxMrtGrq/FDVJ7JwF+cSwbY
+WVfzbmOfHG7g6hRw7Bap/NNjcdtP09hRPG/g2WDy4z0Ay8MTZVe95EHTsyeR+kpv
+0f60eUI0cV7EovbLmp10I3RdsxbWTjbeFmNjM7WmmmsFRzA1jMlFGil/po4mJvMF
+Bcqbi4kUhQ49F4tRUlHRG1b/up71tDuzToF0YmN9GHkf/kt7/noVTYdEsm4RwaeF
+mhoaTMFaNaHGTHSyqroqbBCqlkfTqB1Cqw1weGqV6bGfaYpCJGx5vXmr06mh5dwo
+zvpyHQKCQu96a0G81T526RtVeA4QR89ELa0JSBpWR9MqVZKBte9AgS5vlF0386uM
+vcKC3zJ4srv1YrTOmMkLktNJHsyfLQgb70RdHR38hDEwKaq6VDWiewKDhsWAI5SJ
+wRgjAYspsNUVahDWvpXq/bRGM3JTW+QxiR22vgEitvKeIysLAgMBAAGjYzBhMB0G
+A1UdDgQWBBRXgQcc6LQCpAiPggyM8QVbd9VLxDAfBgNVHSMEGDAWgBRXgQcc6LQC
+pAiPggyM8QVbd9VLxDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN
+BgkqhkiG9w0BAQsFAAOCAgEAjo/Fj7iTOr1/nTvZpeaon0/xY4D+Hf83FW/4yASZ
+Et0ITa510zIi8rIVvlaR1xdbXLYxHgdtm4vQtKZStwOBdwj+4VZrb9WgwQyBCYU5
+RqK387oMUeZdfsh9m2nqM8buYls3mldv34XUg8y1oytx6GDdC7NKz6PLNpIVkj5F
+aBnyfh43FsXHkzAy0nfkdE2mqfhQ4CD9Zkm9fJcX0inEmcspM5G8ba16uESZDqUS
+oJc1bgNtW64fL7pOtVfHDIJqKf/G/iIq1lk33gv5/4z6Z8e7fYVm1JabUUd9rZ6t
+cjXXFqkA7SkcXTs829/gaXQQv2FARt7g70UxJmNN0MCKfYnKM4dKddi934mTWrOI
+eLe0u3OAa1wZaHggJJXgRxMx/acWnGfersTpsAB1XG74XTSXHV7zHHnNWXjQ+gu0
+N4RAkQFMYWqp6KoHgQrdQfLPcaw0wc+ZMJj35z50b4ab+Bygthx3W+v/MiMFK9Wv
+/AsQCGslDcGWbFCYP7IvHDfownIFGefMnOm41NKWus9z6HoEUmfJiiSSVxECDT/2
+fE7M+sQovdrlHx7ru/fO6PP+6ocUE1afY6cHUzE0Dhv6xMcdvwL7COGd5ZU1bqAQ
+TqbePM5Kpk1ytkigdixzMDz/HFum0fdGfc/59Ll+f6+uHAX5NpOJZkBHBCWAoCeX
+bsg=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
new file mode 100644
index 0000000..8bb399e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/assets/user-cert-chain.key
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 5d6d7fb..219dfc2 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -27,21 +27,29 @@
import android.test.ActivityInstrumentationTestCase2;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.cert.Certificate;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.AssetManager;
public class KeyManagementTest extends ActivityInstrumentationTestCase2<KeyManagementActivity> {
@@ -126,6 +134,38 @@
assertGranted(withhold, false);
}
+ public void testCanInstallCertChain() throws Exception {
+ // Use assets/generate-client-cert-chain.sh to regenerate the client cert chain.
+ final PrivateKey privKey = loadPrivateKeyFromAsset("user-cert-chain.key");
+ final Collection<Certificate> certs = loadCertificatesFromAsset("user-cert-chain.crt");
+ final Certificate[] certChain = certs.toArray(new Certificate[certs.size()]);
+ final String alias = "com.android.test.clientkeychain";
+ // Some sanity check on the cert chain
+ assertTrue(certs.size() > 1);
+ for (int i = 1; i < certs.size(); i++) {
+ certChain[i - 1].verify(certChain[i].getPublicKey());
+ }
+
+ // Install keypairs.
+ assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, certChain, alias, true));
+ try {
+ // Verify only the requested key was actually granted.
+ assertGranted(alias, true);
+
+ // Verify the granted key is actually obtainable in PrivateKey form.
+ assertEquals(KeyChain.getPrivateKey(getActivity(), alias).getAlgorithm(), "RSA");
+
+ // Verify the certificate chain is correct
+ X509Certificate[] returnedCerts = KeyChain.getCertificateChain(getActivity(), alias);
+ assertTrue(Arrays.equals(certChain, returnedCerts));
+ } finally {
+ // Delete both keypairs.
+ assertTrue(mDevicePolicyManager.removeKeyPair(getWho(), alias));
+ }
+ // Verify they're actually gone.
+ assertGranted(alias, false);
+ }
+
public void testGrantsDoNotPersistBetweenInstallations() throws Exception {
final String alias = "com.android.test.persistent-key-1";
final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA");
@@ -200,6 +240,35 @@
new ByteArrayInputStream(cert));
}
+ private Collection<Certificate> loadCertificatesFromAsset(String assetName) {
+ try {
+ final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ AssetManager am = getActivity().getAssets();
+ InputStream is = am.open(assetName);
+ return (Collection<Certificate>) certFactory.generateCertificates(is);
+ } catch (IOException | CertificateException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private PrivateKey loadPrivateKeyFromAsset(String assetName) {
+ try {
+ AssetManager am = getActivity().getAssets();
+ InputStream is = am.open(assetName);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ int length;
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer, 0, buffer.length)) != -1) {
+ output.write(buffer, 0, length);
+ }
+ return getPrivateKey(output.toByteArray(), "RSA");
+ } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
private class KeyChainAliasFuture implements KeyChainAliasCallback {
private final CountDownLatch mLatch = new CountDownLatch(1);
private String mChosenAlias = null;
@@ -224,5 +293,5 @@
assertTrue("Chooser timeout", mLatch.await(KEYCHAIN_TIMEOUT_MINS, TimeUnit.MINUTES));
return mChosenAlias;
}
- };
+ }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
index efefde9..22dc38a 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
@@ -20,13 +20,6 @@
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
import android.test.InstrumentationTestCase;
/**
@@ -39,17 +32,12 @@
*/
public class RemoteBugreportTest extends InstrumentationTestCase {
- private static final int UI_TIMEOUT_MILLIS = 5000; //5 seconds
-
private static final String MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED =
"There should only be one user, managed by Device Owner";
- private static final String TAKING_BUG_REPORT = "Taking bug report";
- private static final String DECLINE = "DECLINE";
private DevicePolicyManager mDevicePolicyManager;
private Context mContext;
- private UiDevice mUiDevice;
private ComponentName mComponentName;
@Override
@@ -57,7 +45,6 @@
super.setUp();
Instrumentation instrumentation = getInstrumentation();
mContext = instrumentation.getTargetContext();
- mUiDevice = UiDevice.getInstance(instrumentation);
mDevicePolicyManager = (DevicePolicyManager)
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
BaseDeviceOwnerTest.assertDeviceOwner(mDevicePolicyManager);
@@ -65,20 +52,6 @@
}
/**
- * Test: only one remote bugreport flow can be running on the device at one time.
- */
- public void testSubsequentRemoteBugreportThrottled() {
- boolean startedSuccessfully = mDevicePolicyManager.requestBugreport(mComponentName);
- assertTrue(startedSuccessfully);
-
- // subsequent attempts should be throttled
- assertFalse(mDevicePolicyManager.requestBugreport(mComponentName));
- assertFalse(mDevicePolicyManager.requestBugreport(mComponentName));
-
- cancelRemoteBugreportFlowIfStartedSuccessfully(startedSuccessfully);
- }
-
- /**
* Test: remote bugreport flow can only be started if there's one user on the device.
*/
public void testRequestBugreportNotStartedIfMoreThanOneUserPresent() {
@@ -88,59 +61,7 @@
fail("did not throw expected SecurityException");
} catch (SecurityException e) {
assertEquals(e.getMessage(), MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED);
- } finally {
- cancelRemoteBugreportFlowIfStartedSuccessfully(startedSuccessfully);
}
}
- /**
- * Clicks on "Taking bugreport..." notification, and then DECLINE button on the consent dialog
- * to cancel the whole remote bugreport flow (including stopping the dumpstate service).
- */
- private void cancelRemoteBugreportFlowIfStartedSuccessfully(boolean startedSuccessfully) {
- if (!startedSuccessfully) {
- return;
- }
-
- UiObject2 bugreportNotification = findRemoteBugreportNotification();
- assertNotNull(bugreportNotification);
- bugreportNotification.click();
-
- // give it max 5 seconds to find the DECLINE button on the dialog
- boolean declineButtonPresent = mUiDevice.wait(
- Until.hasObject(By.text(DECLINE)), UI_TIMEOUT_MILLIS);
- assertTrue(declineButtonPresent);
-
- UiObject declineButton = mUiDevice.findObject(new UiSelector().text(DECLINE));
- assertNotNull(declineButton);
- try {
- declineButton.click();
- } catch (UiObjectNotFoundException e) {
- throw new IllegalStateException("Exception when clicking on 'DECLINE' button", e);
- }
- }
-
- /**
- * Attempts to find the remote bugreport notification scrolling down in the notification panel
- * in between 10 attempts.
- */
- private UiObject2 findRemoteBugreportNotification() {
- mUiDevice.openNotification();
- final int displayWidth = mUiDevice.getDisplayWidth();
- final int displayHeight = mUiDevice.getDisplayHeight();
- for (int i = 0; i < 10; i++) {
- UiObject2 notification = mUiDevice.wait(Until.findObject(
- By.textStartsWith(TAKING_BUG_REPORT)), UI_TIMEOUT_MILLIS);
- if (notification != null) {
- return notification;
- } else {
- /* makes a swipe from the middle of the screen upwards to the top of the screen
- (the motion is upwards, so it scrolls downwards) half a screen, so that the
- notification is always fully visible - never cut in two pieces) */
- mUiDevice.swipe(displayWidth / 2, displayHeight / 2, displayWidth / 2,
- /* endY= */ 0, /* steps= */ 30);
- }
- }
- return null;
- }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index afead29..e941b43 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -123,10 +123,6 @@
}
}
- public void testRemoteBugreportWithSingleUser() throws Exception {
- executeDeviceTestMethod(".RemoteBugreportTest", "testSubsequentRemoteBugreportThrottled");
- }
-
/** Tries to toggle the force-ephemeral-users on and checks it was really set. */
public void testSetForceEphemeralUsers() throws Exception {
if (!mHasEphemeralUserFeature) {
@@ -310,12 +306,18 @@
}
public void testSecurityLoggingWithSingleUser() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
executeDeviceTestMethod(".SecurityLoggingTest",
"testRetrievingSecurityLogsNotPossibleImmediatelyAfterPreviousSuccessfulRetrieval");
executeDeviceTestMethod(".SecurityLoggingTest", "testEnablingAndDisablingSecurityLogging");
}
public void testLockTask() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
try {
installAppAsUser(INTENT_RECEIVER_APK, mPrimaryUserId);
executeDeviceOwnerTest("LockTaskTest");
@@ -325,6 +327,9 @@
}
public void testSystemUpdatePolicy() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
executeDeviceOwnerTest("SystemUpdatePolicyTest");
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 27d4a2b..ce9d970 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -377,18 +377,24 @@
private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
final int maxTries = 5;
boolean actual = false;
+ final String expectedUid = Integer.toString(uid);
+ String uids = "";
for (int i = 1; i <= maxTries; i++) {
final String output =
executeShellCommand("cmd netpolicy list " + list);
- actual = output.contains(Integer.toString(uid));
- if (expected == actual) {
- return;
+ uids = output.split(":")[1];
+ for (String candidate : uids.split(" ")) {
+ actual = candidate.trim().equals(expectedUid);
+ if (expected == actual) {
+ return;
+ }
}
Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
+ expected + ", got " + actual + "); sleeping 1s before polling again");
Thread.sleep(SECOND_IN_MS);
}
- fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual);
+ fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
+ + ". Full list: " + uids);
}
protected void assertPowerSaveModeWhitelist(String packageName, boolean expected)
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index 62f670e..d760475 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -31,6 +31,10 @@
*/
public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
+ private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
+ "com.android.providers.downloads"
+ };
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -108,4 +112,24 @@
assertRestrictBackgroundChangedReceived(5);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
}
+
+ public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception {
+ final StringBuilder error = new StringBuilder();
+ for (String packageName : REQUIRED_WHITELISTED_PACKAGES) {
+ int uid = -1;
+ try {
+ uid = getUid(packageName);
+ assertRestrictBackgroundWhitelist(uid, true);
+ } catch (Throwable t) {
+ error.append("\nFailed for '").append(packageName).append("'");
+ if (uid > 0) {
+ error.append(" (uid ").append(uid).append(")");
+ }
+ error.append(": ").append(t).append("\n");
+ }
+ }
+ if (error.length() > 0) {
+ fail(error.toString());
+ }
+ }
}
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 15a4e0a..ca535bc 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -73,6 +73,11 @@
assertRestrictBackgroundWhitelist(newUid, false);
}
+ public void testDataSaverMode_requiredWhitelistedPackages() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ "testGetRestrictBackgroundStatus_requiredWhitelistedPackages");
+ }
+
public void testBatterySaverMode_disabled() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeTest",
"testBackgroundNetworkAccess_disabled");
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
index da346ac..f1f24c9 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/WindowManagerState.java
@@ -384,7 +384,6 @@
}
private void extract(LinkedList<String> dump, Pattern[] exitPatterns) {
-
while (!doneExtracting(dump, exitPatterns)) {
final String line = dump.pop().trim();
@@ -417,7 +416,7 @@
static abstract class WindowContainer {
protected static final Pattern sFullscreenPattern = Pattern.compile("mFullscreen=(\\S+)");
protected static final Pattern sBoundsPattern =
- Pattern.compile("mBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
+ Pattern.compile("mBounds=\\[(-?\\d+),(-?\\d+)\\]\\[(-?\\d+),(-?\\d+)\\]");
protected boolean mFullscreen;
protected Rectangle mBounds;
diff --git a/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
index 5325b29..3f91c20 100644
--- a/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/ActiveTileServiceTest.java
@@ -32,6 +32,7 @@
}
public void testNotListening() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -42,6 +43,7 @@
}
public void testRequestListening() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -52,6 +54,7 @@
}
public void testClick() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
diff --git a/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
index 50d25e8..0ae861b 100644
--- a/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/BaseTileServiceTest.java
@@ -63,6 +63,7 @@
protected void tearDown() throws Exception {
super.tearDown();
+ if (!supportedHardware()) return;
collapse();
remTile();
// Try to wait for a onTileRemoved.
@@ -122,4 +123,10 @@
private void clearLogcat() throws DeviceNotAvailableException {
getDevice().executeAdbCommand("logcat", "-c");
}
+
+ protected boolean supportedHardware() throws DeviceNotAvailableException {
+ String features = getDevice().executeShellCommand("pm list features");
+ return !features.contains("android.hardware.type.television") &&
+ !features.contains("android.hardware.type.watch");
+ }
}
diff --git a/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java b/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
index 3c92918..0c06935 100644
--- a/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
+++ b/hostsidetests/systemui/src/android/host/systemui/TileServiceTest.java
@@ -33,6 +33,7 @@
}
public void testAddTile() throws Exception {
+ if (!supportedHardware()) return;
addTile();
// Verify that the service starts up and gets a onTileAdded callback.
assertTrue(waitFor("onCreate"));
@@ -41,6 +42,7 @@
}
public void testRemoveTile() throws Exception {
+ if (!supportedHardware()) return;
addTile();
// Verify that the service starts up and gets a onTileAdded callback.
assertTrue(waitFor("onCreate"));
@@ -52,6 +54,7 @@
}
public void testListeningNotifications() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -64,6 +67,7 @@
}
public void testListeningSettings() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -76,6 +80,7 @@
}
public void testCantAddDialog() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -93,6 +98,7 @@
}
public void testClick() throws Exception {
+ if (!supportedHardware()) return;
addTile();
// Wait for the tile to be added.
assertTrue(waitFor("onTileAdded"));
@@ -114,6 +120,7 @@
}
public void testClickAndShowDialog() throws Exception {
+ if (!supportedHardware()) return;
addTile();
assertTrue(waitFor("onDestroy"));
@@ -132,6 +139,7 @@
}
public void testStartActivity() throws Exception {
+ if (!supportedHardware()) return;
addTile();
// Wait for the tile to be added.
assertTrue(waitFor("onTileAdded"));
diff --git a/libs/deviceutil/src/android/cts/util/BitmapUtils.java b/libs/deviceutil/src/android/cts/util/BitmapUtils.java
index 7234425..157ee27 100644
--- a/libs/deviceutil/src/android/cts/util/BitmapUtils.java
+++ b/libs/deviceutil/src/android/cts/util/BitmapUtils.java
@@ -36,6 +36,10 @@
return true;
}
+ if (bmp1 == null || bmp2 == null) {
+ return false;
+ }
+
if ((bmp1.getWidth() != bmp2.getWidth()) || (bmp1.getHeight() != bmp2.getHeight())) {
return false;
}
diff --git a/libs/deviceutil/src/android/cts/util/KeyEventUtil.java b/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
new file mode 100644
index 0000000..4031adf
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/KeyEventUtil.java
@@ -0,0 +1,202 @@
+/*
+ * 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.cts.util;
+
+import android.app.Instrumentation;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.reflect.Field;
+
+/**
+ * Utility class to send KeyEvents to TextView bypassing the IME. The code is similar to functions
+ * in {@link Instrumentation} and {@link android.test.InstrumentationTestCase} classes. It uses
+ * {@link InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)} to send the events.
+ * After sending the events waits for idle.
+ */
+public class KeyEventUtil {
+ private final Instrumentation mInstrumentation;
+
+ public KeyEventUtil(Instrumentation instrumentation) {
+ this.mInstrumentation = instrumentation;
+ }
+
+ /**
+ * Sends the key events corresponding to the text to the app being instrumented.
+ *
+ * @param targetView View to find the ViewRootImpl and dispatch.
+ * @param text The text to be sent. Null value returns immediately.
+ */
+ public final void sendString(final View targetView, final String text) {
+ if (text == null) {
+ return;
+ }
+
+ KeyEvent[] events = getKeyEvents(text);
+
+ if (events != null) {
+ for (int i = 0; i < events.length; i++) {
+ // We have to change the time of an event before injecting it because
+ // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
+ // time stamp and the system rejects too old events. Hence, it is
+ // possible for an event to become stale before it is injected if it
+ // takes too long to inject the preceding ones.
+ sendKey(targetView, KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(),
+ 0));
+ }
+ }
+ }
+
+ /**
+ * Sends a series of key events through instrumentation. For instance:
+ * sendKeys(view, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER).
+ *
+ * @param targetView View to find the ViewRootImpl and dispatch.
+ * @param keys The series of key codes.
+ */
+ public final void sendKeys(final View targetView, final int...keys) {
+ final int count = keys.length;
+
+ for (int i = 0; i < count; i++) {
+ try {
+ sendKeyDownUp(targetView, keys[i]);
+ } catch (SecurityException e) {
+ // Ignore security exceptions that are now thrown
+ // when trying to send to another app, to retain
+ // compatibility with existing tests.
+ }
+ }
+ }
+
+ /**
+ * Sends a series of key events through instrumentation. The sequence of keys is a string
+ * containing the key names as specified in KeyEvent, without the KEYCODE_ prefix. For
+ * instance: sendKeys(view, "DPAD_LEFT A B C DPAD_CENTER"). Each key can be repeated by using
+ * the N* prefix. For instance, to send two KEYCODE_DPAD_LEFT, use the following:
+ * sendKeys(view, "2*DPAD_LEFT").
+ *
+ * @param targetView View to find the ViewRootImpl and dispatch.
+ * @param keysSequence The sequence of keys.
+ */
+ public final void sendKeys(final View targetView, final String keysSequence) {
+ final String[] keys = keysSequence.split(" ");
+ final int count = keys.length;
+
+ for (int i = 0; i < count; i++) {
+ String key = keys[i];
+ int repeater = key.indexOf('*');
+
+ int keyCount;
+ try {
+ keyCount = repeater == -1 ? 1 : Integer.parseInt(key.substring(0, repeater));
+ } catch (NumberFormatException e) {
+ Log.w("ActivityTestCase", "Invalid repeat count: " + key);
+ continue;
+ }
+
+ if (repeater != -1) {
+ key = key.substring(repeater + 1);
+ }
+
+ for (int j = 0; j < keyCount; j++) {
+ try {
+ final Field keyCodeField = KeyEvent.class.getField("KEYCODE_" + key);
+ final int keyCode = keyCodeField.getInt(null);
+ try {
+ sendKeyDownUp(targetView, keyCode);
+ } catch (SecurityException e) {
+ // Ignore security exceptions that are now thrown
+ // when trying to send to another app, to retain
+ // compatibility with existing tests.
+ }
+ } catch (NoSuchFieldException e) {
+ Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+ break;
+ } catch (IllegalAccessException e) {
+ Log.w("ActivityTestCase", "Unknown keycode: KEYCODE_" + key);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends an up and down key events.
+ *
+ * @param targetView View to find the ViewRootImpl and dispatch.
+ * @param key The integer keycode for the event to be send.
+ */
+ public final void sendKeyDownUp(final View targetView, final int key) {
+ sendKey(targetView, new KeyEvent(KeyEvent.ACTION_DOWN, key));
+ sendKey(targetView, new KeyEvent(KeyEvent.ACTION_UP, key));
+ }
+
+ /**
+ * Sends a key event.
+ *
+ * @param targetView View to find the ViewRootImpl and dispatch.
+ * @param event KeyEvent to be send.
+ */
+ public final void sendKey(final View targetView, final KeyEvent event) {
+ validateNotAppThread();
+
+ long downTime = event.getDownTime();
+ long eventTime = event.getEventTime();
+ int action = event.getAction();
+ int code = event.getKeyCode();
+ int repeatCount = event.getRepeatCount();
+ int metaState = event.getMetaState();
+ int deviceId = event.getDeviceId();
+ int scancode = event.getScanCode();
+ int source = event.getSource();
+ int flags = event.getFlags();
+ if (source == InputDevice.SOURCE_UNKNOWN) {
+ source = InputDevice.SOURCE_KEYBOARD;
+ }
+ if (eventTime == 0) {
+ eventTime = SystemClock.uptimeMillis();
+ }
+ if (downTime == 0) {
+ downTime = eventTime;
+ }
+
+ final KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount,
+ metaState, deviceId, scancode, flags, source);
+
+ InputMethodManager imm = targetView.getContext().getSystemService(InputMethodManager.class);
+ imm.dispatchKeyEventFromInputMethod(targetView, newEvent);
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private KeyEvent[] getKeyEvents(final String text) {
+ KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ return keyCharacterMap.getEvents(text.toCharArray());
+ }
+
+ private void validateNotAppThread() {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ throw new RuntimeException(
+ "This method can not be called from the main application thread");
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 7da7d37..df48a61 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -84,12 +84,11 @@
GestureDescription click = createClick(clickX, clickY);
mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
- waitForMotionEvents(3);
+ waitForMotionEvents(2);
- assertEquals(3, mMotionEvents.size());
+ assertEquals(2, mMotionEvents.size());
MotionEvent clickDown = mMotionEvents.get(0);
- MotionEvent clickMove = mMotionEvents.get(1);
- MotionEvent clickUp = mMotionEvents.get(2);
+ MotionEvent clickUp = mMotionEvents.get(1);
assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
assertEquals(0, clickDown.getActionIndex());
@@ -103,23 +102,13 @@
assertEquals((float) clickYInsideView, clickDown.getY());
assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
- assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
- assertEquals(clickDown.getDownTime(), clickMove.getDownTime());
- assertEquals(ViewConfiguration.getTapTimeout(),
- clickMove.getEventTime() - clickMove.getDownTime());
- assertEquals(0, clickMove.getActionIndex());
- assertEquals(1, clickMove.getPointerCount());
- assertEquals((float) clickXInsideView + 1, clickMove.getX());
- assertEquals((float) clickYInsideView, clickMove.getY());
- assertEquals(clickDown.getPointerId(0),
- clickMove.getPointerId(0));
-
assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
- assertEquals(clickMove.getEventTime(), clickUp.getEventTime());
+ assertEquals(ViewConfiguration.getTapTimeout(),
+ clickUp.getEventTime() - clickUp.getDownTime());
assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
> clickUp.getEventTime());
- assertEquals((float) clickXInsideView + 1, clickUp.getX());
+ assertEquals((float) clickXInsideView, clickUp.getX());
assertEquals((float) clickYInsideView, clickUp.getY());
}
@@ -133,27 +122,20 @@
mCallback.assertGestureCompletes(
ViewConfiguration.getLongPressTimeout() + GESTURE_COMPLETION_TIMEOUT);
- waitForMotionEvents(3);
+ waitForMotionEvents(2);
MotionEvent clickDown = mMotionEvents.get(0);
- MotionEvent clickMove = mMotionEvents.get(1);
- MotionEvent clickUp = mMotionEvents.get(2);
+ MotionEvent clickUp = mMotionEvents.get(1);
assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
assertEquals((float) clickXInsideView, clickDown.getX());
assertEquals((float) clickYInsideView, clickDown.getY());
- assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
- assertEquals(clickDown.getDownTime(), clickMove.getDownTime());
- assertEquals((float) clickXInsideView + 1, clickMove.getX());
- assertEquals((float) clickYInsideView, clickMove.getY());
- assertEquals(clickDown.getPointerId(0), clickMove.getPointerId(0));
-
assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
assertTrue(clickDown.getEventTime() + ViewConfiguration.getLongPressTimeout()
<= clickUp.getEventTime());
assertEquals(clickDown.getDownTime(), clickUp.getDownTime());
- assertEquals((float) clickXInsideView + 1, clickUp.getX());
+ assertEquals((float) clickXInsideView, clickUp.getX());
assertEquals((float) clickYInsideView, clickUp.getY());
}
@@ -349,22 +331,17 @@
assertTrue("Failed to reset", result.get());
}
- assertEquals(3, mMotionEvents.size());
+ assertEquals(2, mMotionEvents.size());
MotionEvent clickDown = mMotionEvents.get(0);
- MotionEvent clickMove = mMotionEvents.get(1);
- MotionEvent clickUp = mMotionEvents.get(2);
+ MotionEvent clickUp = mMotionEvents.get(1);
assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
assertEquals((float) clickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
assertEquals((float) clickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
- assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
- assertEquals((float) clickXInsideView + 1, clickMove.getX(), TOUCH_TOLERANCE);
- assertEquals((float) clickYInsideView, clickMove.getY(), TOUCH_TOLERANCE);
-
assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
- assertEquals((float) clickXInsideView + 1, clickUp.getX(), TOUCH_TOLERANCE);
+ assertEquals((float) clickXInsideView, clickUp.getX(), TOUCH_TOLERANCE);
assertEquals((float) clickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
}
@@ -450,7 +427,6 @@
private GestureDescription createClick(int x, int y) {
Path clickPath = new Path();
clickPath.moveTo(x, y);
- clickPath.lineTo(x + 1, y);
GestureDescription.StrokeDescription clickStroke =
new GestureDescription.StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout());
GestureDescription.Builder clickBuilder = new GestureDescription.Builder();
@@ -461,7 +437,6 @@
private GestureDescription createLongClick(int x, int y) {
Path clickPath = new Path();
clickPath.moveTo(x, y);
- clickPath.lineTo(x + 1, y);
int longPressTime = ViewConfiguration.getLongPressTimeout();
GestureDescription.StrokeDescription longClickStroke =
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
index b3fa9d2..234f66a 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/GestureDescriptionTest.java
@@ -93,13 +93,11 @@
}
}
- public void testCreateStroke_pathWithZeroLength_shouldThrow() {
- Path zeroLengthPath = new Path();
- zeroLengthPath.moveTo(0, 0);
- zeroLengthPath.lineTo(0, 0);
+ public void testCreateStroke_withEmptyPath_shouldThrow() {
+ Path emptyPath = new Path();
try {
- new GestureDescription.StrokeDescription(zeroLengthPath, 0, NOMINAL_PATH_DURATION);
- fail("Missing exception for stroke with path of zero length.");
+ new GestureDescription.StrokeDescription(emptyPath, 0, NOMINAL_PATH_DURATION);
+ fail("Missing exception for empty path.");
} catch (IllegalArgumentException e) {
}
}
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index 5d7d99e..03cc150 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -27,14 +27,13 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.admin.cts" />
- <option name="exclude-filter" value="android.admin.app.DeactivationTest" />
+ <option name="runtime-hint" value="20s" />
</test>
<!-- Instrument the app to clear the device admins so the apk can be uninstalled -->
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstrumentationPreparer">
<option name="apk" value="CtsAdminApp.apk" />
<option name="package" value="android.admin.app" />
- <option name="include-filter" value="android.admin.app.DeactivationTest" />
<option name="when" value="after" />
</target_preparer>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index ea094ab..cc06ead 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -124,6 +124,9 @@
<meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
</service>
+ <service android:name="android.app.stubs.LocalForegroundService">
+ </service>
+
<service android:name="android.app.stubs.LocalGrantedService"
android:permission="android.app.stubs.permission.TEST_GRANTED">
<intent-filter>
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
new file mode 100644
index 0000000..119b9f8
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -0,0 +1,90 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Notification;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.cts.util.IBinderParcelable;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.app.stubs.R;
+
+public class LocalForegroundService extends LocalService {
+
+ private static final String TAG = "LocalForegroundService";
+ private static final String EXTRA_COMMAND = "LocalForegroundService.command";
+
+ public static final int COMMAND_START_FOREGROUND = 1;
+ public static final int COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION = 2;
+ public static final int COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION = 3;
+ public static final int COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION = 4;
+ public static final int COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS = 5;
+
+ private int mNotificationId = 0;
+
+ @Override
+ public void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+
+ Context context = getApplicationContext();
+ int command = intent.getIntExtra(EXTRA_COMMAND, -1);
+
+ switch (command) {
+ case COMMAND_START_FOREGROUND:
+ mNotificationId ++;
+ Log.d(TAG, "Starting foreground using notification " + mNotificationId);
+ Notification notification = new Notification.Builder(context)
+ .setContentTitle(getNotificationTitle(mNotificationId))
+ .setSmallIcon(R.drawable.black)
+ .build();
+ startForeground(mNotificationId, notification);
+ break;
+ case COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION:
+ Log.d(TAG, "Stopping foreground removing notification");
+ stopForeground(true);
+ break;
+ case COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION:
+ Log.d(TAG, "Stopping foreground without removing notification");
+ stopForeground(false);
+ break;
+ case COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS:
+ Log.d(TAG, "Stopping foreground removing notification using flags");
+ stopForeground(Service.STOP_FOREGROUND_REMOVE | Service.STOP_FOREGROUND_DETACH);
+ break;
+ case COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION:
+ Log.d(TAG, "Detaching foreground service notification");
+ stopForeground(Service.STOP_FOREGROUND_DETACH);
+ break;
+ default:
+ Log.e(TAG, "Unknown command: " + command);
+ }
+ }
+
+ public static Bundle newCommand(IBinder stateReceiver, int command) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(stateReceiver));
+ bundle.putInt(EXTRA_COMMAND, command);
+ return bundle;
+ }
+
+ public static String getNotificationTitle(int id) {
+ return "I AM FOREGROOT #" + id;
+ }
+}
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 4842bb1..1d6d23d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -16,8 +16,11 @@
package android.app.cts;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.stubs.ActivityTestsBase;
import android.app.stubs.LocalDeniedService;
+import android.app.stubs.LocalForegroundService;
import android.app.stubs.LocalGrantedService;
import android.app.stubs.LocalService;
import android.content.ComponentName;
@@ -30,15 +33,20 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.app.stubs.R;
public class ServiceTest extends ActivityTestsBase {
+ private static final String TAG = "ServiceTest";
private static final int STATE_START_1 = 0;
private static final int STATE_START_2 = 1;
- private static final int STATE_UNBIND = 2;
- private static final int STATE_DESTROY = 3;
- private static final int STATE_REBIND = 4;
- private static final int STATE_UNBIND_ONLY = 5;
+ private static final int STATE_START_3 = 2;
+ private static final int STATE_UNBIND = 3;
+ 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 DELAY = 5000;
private static final
String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
@@ -47,6 +55,7 @@
private Context mContext;
private Intent mLocalService;
private Intent mLocalDeniedService;
+ private Intent mLocalForegroundService;
private Intent mLocalGrantedService;
private Intent mLocalService_ApplicationHasPermission;
private Intent mLocalService_ApplicationDoesNotHavePermission;
@@ -157,6 +166,82 @@
waitForResultOrThrow(DELAY, "service to be destroyed");
}
+ private NotificationManager getNotificationManager() {
+ NotificationManager notificationManager =
+ (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+ return notificationManager;
+ }
+
+ private void sendNotififcation(int id, String title) {
+ Notification notification = new Notification.Builder(getContext())
+ .setContentTitle(title)
+ .setSmallIcon(R.drawable.black)
+ .build();
+ getNotificationManager().notify(id, notification);
+ }
+
+ private void cancelNotification(int id) {
+ getNotificationManager().cancel(id);
+ }
+
+ private void assertNotification(int id, String expectedTitle) {
+ String packageName = getContext().getPackageName();
+ String errorMessage = null;
+ for (int i = 1; i<=2; i++) {
+ errorMessage = null;
+ StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
+ for (StatusBarNotification sbn : sbns) {
+ if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
+ String actualTitle =
+ sbn.getNotification().extras.getString(Notification.EXTRA_TITLE);
+ if (expectedTitle.equals(actualTitle)) {
+ return;
+ }
+ // It's possible the notification hasn't been updated yet, so save the error
+ // message to only fail after retrying.
+ errorMessage = String.format("Wrong title for notification #%d: "
+ + "expected '%s', actual '%s'", id, expectedTitle, actualTitle);
+ Log.w(TAG, errorMessage);
+ }
+ }
+ // Notification might not be rendered yet, wait and try again...
+ try {
+ Thread.sleep(DELAY);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ if (errorMessage != null) {
+ fail(errorMessage);
+ }
+ fail("No notification with id " + id + " for package " + packageName);
+ }
+
+ private void assertNoNotification(int id) {
+ String packageName = getContext().getPackageName();
+ StatusBarNotification found = null;
+ for (int i = 1; i<=2; i++) {
+ found = null;
+ StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications();
+ for (StatusBarNotification sbn : sbns) {
+ if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) {
+ found = sbn;
+ break;
+ }
+ }
+ if (found != null) {
+ // Notification might not be canceled yet, wait and try again...
+ try {
+ Thread.sleep(DELAY);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ assertNull("Found notification with id " + id + " for package " + packageName + ": "
+ + found, found);
+ }
+
/**
* test the service lifecycle, a service can be used in two ways:
* 1 It can be started and allowed to run until someone stops it or it stops itself.
@@ -297,6 +382,7 @@
super.setUp();
mContext = getContext();
mLocalService = new Intent(mContext, LocalService.class);
+ mLocalForegroundService = new Intent(mContext, LocalForegroundService.class);
mLocalDeniedService = new Intent(mContext, LocalDeniedService.class);
mLocalGrantedService = new Intent(mContext, LocalGrantedService.class);
mLocalService_ApplicationHasPermission = new Intent(
@@ -327,6 +413,13 @@
finishBad("onStart() the first time on an object when it "
+ "should have been the second time");
}
+ } else if (mExpectedServiceState == STATE_START_3) {
+ if (count == 3) {
+ finishGood();
+ } else {
+ finishBad("onStart() the first time on an object when it "
+ + "should have been the third time");
+ }
} else {
finishBad("onStart() was called when not expected (state="
+ mExpectedServiceState + ")");
@@ -371,6 +464,7 @@
protected void tearDown() throws Exception {
super.tearDown();
mContext.stopService(mLocalService);
+ mContext.stopService(mLocalForegroundService);
mContext.stopService(mLocalGrantedService);
mContext.stopService(mLocalService_ApplicationHasPermission);
}
@@ -388,6 +482,155 @@
bindExpectResult(mLocalService);
}
+ private void startForegroundService(int command) {
+ mContext.startService(new Intent(mLocalForegroundService).putExtras(LocalForegroundService
+ .newCommand(mStateReceiver, command)));
+ }
+
+ @MediumTest
+ public void testForegroundService_dontRemoveNotificationOnStop() throws Exception {
+ boolean success = false;
+ try {
+ // Start service as foreground - it should show notification #1
+ mExpectedServiceState = STATE_START_1;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start first time");
+ assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+ // Stop foreground without removing notification - it should still show notification #1
+ mExpectedServiceState = STATE_START_2;
+ startForegroundService(
+ LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION);
+ waitForResultOrThrow(DELAY, "service to stop foreground");
+ assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+ // Sends another notification reusing the same notification id.
+ String newTitle = "YODA I AM";
+ sendNotififcation(1, newTitle);
+ assertNotification(1, newTitle);
+
+ // Start service as foreground again - it should kill notification #1 and show #2
+ mExpectedServiceState = STATE_START_3;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start foreground 2nd time");
+ assertNoNotification(1);
+ assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+
+ success = true;
+ } finally {
+ if (!success) {
+ mContext.stopService(mLocalForegroundService);
+ }
+ }
+ mExpectedServiceState = STATE_DESTROY;
+ mContext.stopService(mLocalForegroundService);
+ waitForResultOrThrow(DELAY, "service to be destroyed");
+ assertNoNotification(1);
+ assertNoNotification(2);
+ }
+
+ @MediumTest
+ public void testForegroundService_removeNotificationOnStop() throws Exception {
+ testForegroundServiceRemoveNotificationOnStop(false);
+ }
+
+ @MediumTest
+ public void testForegroundService_removeNotificationOnStopUsingFlags() throws Exception {
+ testForegroundServiceRemoveNotificationOnStop(true);
+ }
+
+ private void testForegroundServiceRemoveNotificationOnStop(boolean usingFlags)
+ throws Exception {
+ boolean success = false;
+ try {
+ // Start service as foreground - it should show notification #1
+ mExpectedServiceState = STATE_START_1;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start first time");
+ assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+ // Stop foreground removing notification
+ mExpectedServiceState = STATE_START_2;
+ if (usingFlags) {
+ startForegroundService(LocalForegroundService
+ .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS);
+ } else {
+ startForegroundService(LocalForegroundService
+ .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION);
+ }
+ waitForResultOrThrow(DELAY, "service to stop foreground");
+ assertNoNotification(1);
+
+ // Start service as foreground again - it should show notification #2
+ mExpectedServiceState = STATE_START_3;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
+ assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+
+ success = true;
+ } finally {
+ if (!success) {
+ mContext.stopService(mLocalForegroundService);
+ }
+ }
+ mExpectedServiceState = STATE_DESTROY;
+ mContext.stopService(mLocalForegroundService);
+ waitForResultOrThrow(DELAY, "service to be destroyed");
+ assertNoNotification(1);
+ assertNoNotification(2);
+ }
+
+ @MediumTest
+ public void testForegroundService_detachNotificationOnStop() throws Exception {
+ String newTitle = null;
+ boolean success = false;
+ try {
+
+ // Start service as foreground - it should show notification #1
+ mExpectedServiceState = STATE_START_1;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start first time");
+ assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+ // Detaching notification
+ mExpectedServiceState = STATE_START_2;
+ startForegroundService(
+ LocalForegroundService.COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION);
+ waitForResultOrThrow(DELAY, "service to stop foreground");
+ assertNotification(1, LocalForegroundService.getNotificationTitle(1));
+
+ // Sends another notification reusing the same notification id.
+ newTitle = "YODA I AM";
+ sendNotififcation(1, newTitle);
+ assertNotification(1, newTitle);
+
+ // Start service as foreground again - it should show notification #2..
+ mExpectedServiceState = STATE_START_3;
+ startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
+ waitForResultOrThrow(DELAY, "service to start as foreground 2nd time");
+ assertNotification(2, LocalForegroundService.getNotificationTitle(2));
+ //...but keeping notification #1
+ assertNotification(1, newTitle);
+
+ success = true;
+ } finally {
+ if (!success) {
+ mContext.stopService(mLocalForegroundService);
+ }
+ }
+ mExpectedServiceState = STATE_DESTROY;
+ mContext.stopService(mLocalForegroundService);
+ waitForResultOrThrow(DELAY, "service to be destroyed");
+ if (newTitle == null) {
+ assertNoNotification(1);
+ } else {
+ assertNotification(1, newTitle);
+ cancelNotification(1);
+ assertNoNotification(1);
+ }
+ assertNoNotification(2);
+ }
+
@MediumTest
public void testLocalBindAction() throws Exception {
bindExpectResult(new Intent(
diff --git a/tests/browser/AndroidTest.xml b/tests/browser/AndroidTest.xml
index 49c93fc..511e769 100644
--- a/tests/browser/AndroidTest.xml
+++ b/tests/browser/AndroidTest.xml
@@ -21,5 +21,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.browser.cts" />
<option name="runtime-hint" value="4m14s" />
+ <!-- test-timeout unit is ms, value = 60 min -->
+ <option name="test-timeout" value="3600000" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
index d8fae6d..5fbc682 100644
--- a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -99,18 +99,20 @@
final long minStillFrameDuration =
config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, stillSize);
- // Find suitable target FPS range - as high as possible
- List<Range<Integer> > fpsRanges = Arrays.asList(
- mStaticInfo.getAeAvailableTargetFpsRangesChecked());
- Range<Integer> targetRange = mStaticInfo.getAeMaxTargetFpsRange();
// Add 0.05 here so Fps like 29.99 evaluated to 30
int minBurstFps = (int) Math.floor(1e9 / minStillFrameDuration + 0.05f);
boolean foundConstantMaxYUVRange = false;
boolean foundYUVStreamingRange = false;
+ // Find suitable target FPS range - as high as possible that covers the max YUV rate
+ // Also verify that there's a good preview rate as well
+ List<Range<Integer> > fpsRanges = Arrays.asList(
+ mStaticInfo.getAeAvailableTargetFpsRangesChecked());
+ Range<Integer> targetRange = null;
for (Range<Integer> fpsRange : fpsRanges) {
if (fpsRange.getLower() == minBurstFps && fpsRange.getUpper() == minBurstFps) {
foundConstantMaxYUVRange = true;
+ targetRange = fpsRange;
}
if (fpsRange.getLower() <= 15 && fpsRange.getUpper() == minBurstFps) {
foundYUVStreamingRange = true;
@@ -122,10 +124,6 @@
assertTrue(String.format(
"Cam %s: Target FPS range of (x, %d) where x <= 15 must be supported",
cameraId, minBurstFps), foundYUVStreamingRange);
- assertTrue(String.format("Cam %s: No target FPS range found with minimum FPS above " +
- " 1/minFrameDuration (%d fps, duration %d ns) for full-resolution YUV",
- cameraId, minBurstFps, minStillFrameDuration),
- targetRange.getLower() >= minBurstFps);
Log.i(TAG, String.format("Selected frame rate range %d - %d for YUV burst",
targetRange.getLower(), targetRange.getUpper()));
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 4272f59..764df78 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -720,15 +720,15 @@
Image.Plane rawPlane = rawImage.getPlanes()[0];
ByteBuffer rawBuffer = rawPlane.getBuffer();
float[] avgBlackLevels = {0, 0, 0, 0};
- int rowSize = rawPlane.getRowStride() * rawPlane.getPixelStride();
- int bytePerPixel = rawPlane.getPixelStride();
+ final int rowSize = rawPlane.getRowStride();
+ final int bytePerPixel = rawPlane.getPixelStride();
if (VERBOSE) {
Log.v(TAG, "maxRegion: " + maxRegion + ", Row stride: " +
rawPlane.getRowStride());
}
- for (int row = maxRegion.left; row < maxRegion.right; row += 2) {
- for (int col = maxRegion.top; col < maxRegion.bottom; col += 2) {
- int startOffset = col * rawPlane.getRowStride() + row * bytePerPixel;
+ for (int row = maxRegion.top; row < maxRegion.bottom; row += 2) {
+ for (int col = maxRegion.left; col < maxRegion.right; col += 2) {
+ int startOffset = row * rowSize + col * bytePerPixel;
avgBlackLevels[0] += rawBuffer.getShort(startOffset);
avgBlackLevels[1] += rawBuffer.getShort(startOffset + bytePerPixel);
startOffset += rowSize;
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index a5aa2ac..8d0b084 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -779,6 +779,7 @@
"NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported",
!supportZslNoiseReductionMode);
}
+ counter++;
}
}
@@ -930,6 +931,7 @@
"All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed",
!hasFields);
}
+ counter++;
}
}
@@ -1137,9 +1139,8 @@
invalidSize.toString()),
config.isOutputSupportedFor(surf));
- counter++;
}
-
+ counter++;
} // mCharacteristics
}
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 3f84aa2..5ea4322 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -165,19 +165,6 @@
bug: 23238984
},
{
- description: "These tests fail on some devices.",
- names: [
- "android.uirendering.cts.testclasses.ExactCanvasTests#testBlueRect",
- "android.uirendering.cts.testclasses.ExactCanvasTests#testBluePaddedSquare",
- "android.uirendering.cts.testclasses.ViewClippingTests#testSimplePaddingClip",
- "android.uirendering.cts.testclasses.ViewClippingTests#testSimpleClipBoundsClip",
- "android.uirendering.cts.testclasses.ViewClippingTests#testSimpleOutlineClip",
- "android.uirendering.cts.testclasses.ViewClippingTests#testSimpleBoundsClip",
- "android.uirendering.cts.testclasses.InfrastructureTests#testViewInitializer"
- ],
- bug: 17511118
-},
-{
description: "This test failed on devices that use effect off loading. In addition it uses hidden apis",
names: [
"android.media.cts.AudioEffectTest#test1_1ConstructorFromUuid"
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
deleted file mode 100644
index 038b164..0000000
--- a/tests/inputmethod/AndroidManifest.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.inputmethod.cts">
-
- <application >
- <uses-library android:name="android.test.runner"/>
-
- <activity android:name="android.inputmethod.cts.TestActivity" />
- <service android:name="android.inputmethod.cts.MockInputMethodService"
- android:permission="android.permission.BIND_INPUT_METHOD">
- <intent-filter>
- <action android:name="android.view.InputMethod" />
- </intent-filter>
- <meta-data android:name="android.view.im" android:resource="@xml/method" />
- </service>
- </application>
-
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.inputmethod.cts"
- android:label="Tests for the InputMethod APIs."/>
-
-</manifest>
diff --git a/tests/inputmethod/res/xml/method.xml b/tests/inputmethod/res/xml/method.xml
deleted file mode 100644
index fc2ec95..0000000
--- a/tests/inputmethod/res/xml/method.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
--->
-
-<input-method xmlns:android="http://schemas.android.com/apk/res/android"
- android:isDefault="True">
- <subtype android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" />
-</input-method>
diff --git a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java
deleted file mode 100644
index c68d448..0000000
--- a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.inputmethod.cts;
-
-import android.annotation.NonNull;
-import android.content.pm.PackageManager;
-import android.os.IBinder;
-import android.inputmethodservice.InputMethodService;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.inputmethod.InputMethodManager;
-
-import java.util.List;
-
-public class InputMethodServiceTest extends InstrumentationTestCase {
- private String mTestImeId;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mTestImeId = getInstrumentation().getContext().getPackageName() +
- "/" + MockInputMethodService.class.getName();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- /**
- * Ensures that the IME with {@code imeId} is not enabled.
- *
- * This method ensures that no IME with {@code imeId} is enabled. If the given IME is currently
- * in use, switches to another IME first. Then, if the given IME is enabled, disables it.
- */
- private void ensureImeNotEnabled(@NonNull final String imeId) {
- final String currentImeId =
- InputMethodServiceTestUtil.getCurrentImeId(getInstrumentation());
- if (currentImeId.equals(imeId)) {
- // Requested IME is already used. This typically happens if the previous test case is
- // not finished gracefully. In this case, selects another IME.
- String otherImeCandidate = null;
- final List<String> enabledImes =
- InputMethodServiceTestUtil.getEnabledImeIds(getInstrumentation());
- for (final String enabledIme : enabledImes) {
- if (!enabledIme.equals(imeId)) {
- otherImeCandidate = imeId;
- break;
- }
- }
- if (otherImeCandidate == null) {
- // When PackageManager.hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS)
- // returns true, this case must not happen.
- throw new IllegalStateException(
- "No other IME is available. Unable to continue tests.");
- }
- assertTrue(InputMethodServiceTestUtil.setIme(getInstrumentation(), otherImeCandidate));
- }
-
- if (InputMethodServiceTestUtil.isImeEnabled(getInstrumentation(), imeId)) {
- assertTrue(InputMethodServiceTestUtil.disableIme(getInstrumentation(), imeId));
- }
- }
-
- /**
- * Asserts the given service is not running.
- */
- private void assertServiceNotRunning() {
- assertTrue(MockInputMethodService.getInstance() == null ||
- MockInputMethodService.getInstance().getCallCount("onCreate") == 0);
- }
-
- /**
- * This test checks the following APIs.
- * <ul>
- * <li>{@link InputMethodManager#getEnabledInputMethodList()}</li>
- * <li>{@link InputMethodManager#getInputMethodList()}</li>
- * <li>{@link InputMethodManager#setInputMethod(IBinder, String)}</li>
- * <li>{@link InputMethodService#onCreate()}</li>
- * <li>{@link InputMethodService#onDestroy()}</li>
- * </ul>
- */
- @MediumTest
- public void testCreateAndDestroy() {
- if (!getInstrumentation().getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_INPUT_METHODS)) {
- // The "input method" system feature is not supported on this device.
- return;
- }
-
- // Clear the counter in the mock service, since it might have been used in a previous test.
- MockInputMethodService.resetCounter();
-
- ensureImeNotEnabled(mTestImeId);
-
- final String ImeIdToRestore =
- InputMethodServiceTestUtil.getCurrentImeId(getInstrumentation());
- MockInputMethodService service = MockInputMethodService.getInstance();
- assertServiceNotRunning();
-
- try {
- // Enable test IME.
- assertTrue(InputMethodServiceTestUtil.enableIme(getInstrumentation(), mTestImeId));
- service = MockInputMethodService.getInstance();
- assertServiceNotRunning();
-
- // Select test IME.
- assertTrue(InputMethodServiceTestUtil.setIme(getInstrumentation(), mTestImeId));
- service = MockInputMethodService.getInstance();
- assertNotNull(service);
- assertEquals(1, MockInputMethodService.getCallCount("<init>"));
- assertEquals(1, MockInputMethodService.getCallCount("onCreate"));
- } finally {
- // Restores IMEs to original one.
- InputMethodServiceTestUtil.setIme(getInstrumentation(), ImeIdToRestore);
- InputMethodServiceTestUtil.disableIme(getInstrumentation(), mTestImeId);
- assertEquals(1, MockInputMethodService.getCallCount("onDestroy"));
- }
- }
-}
diff --git a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java b/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java
deleted file mode 100644
index aa46c38..0000000
--- a/tests/inputmethod/src/android/inputmethod/cts/InputMethodServiceTestUtil.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.inputmethod.cts;
-
-import android.annotation.NonNull;
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Utility functions for testing of input method stuff.
- */
-public final class InputMethodServiceTestUtil {
- private static final String TAG = InputMethodServiceTestUtil.class.getSimpleName();
-
- // Prevents this from being instantiated.
- private InputMethodServiceTestUtil() {}
-
- @NonNull
- private static String executeShellCommand(final UiAutomation uiAutomation, final String[] cmd) {
- final String flattenCmd = TextUtils.join(" ", cmd);
- List<String> output = new ArrayList<>();
-
- try (final ParcelFileDescriptor fd = uiAutomation.executeShellCommand(flattenCmd);
- final FileReader fr = new FileReader(fd.getFileDescriptor());
- final BufferedReader br = new BufferedReader(fr)) {
-
- String line;
- while ((line = br.readLine()) != null) {
- output.add(line);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- // The output from the "ime" command should be only one line.
- if (output.size() != 1) {
- throw new IllegalStateException(
- "The output from 'ime' command should be one line, but it outputs multiples: " +
- TextUtils.join("\n", output));
- }
- return output.get(0);
- }
-
- @NonNull
- public static String getCurrentImeId(final Instrumentation inst) {
- return Settings.Secure.getString(inst.getContext().getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD);
- }
-
- public static boolean isImeEnabled(final Instrumentation inst, final String imeId) {
- final List<String> enabledImes = getEnabledImeIds(inst);
- return enabledImes.contains(imeId);
- }
-
- @NonNull
- public static List<String> getEnabledImeIds(final Instrumentation inst) {
- InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- final List<InputMethodInfo> enabledImes = imm.getEnabledInputMethodList();
- List<String> result = new ArrayList<>();
- for (final InputMethodInfo enabledIme : enabledImes) {
- result.add(enabledIme.getId());
- }
- return result;
- }
-
- /**
- * Puts the specified IME into the available input method list.
- *
- * This operation will be done synchronously in "ime" command using
- * {@link com.android.server.InputMethodManagerService#setInputMethodEnabled(String, boolean)},
- * which is synchronous.
- *
- * @param imeId IME ID to be enabled.
- * @return {@code true} if the target IME gets enabled successfully. {@code false} if failed.
- */
- public static boolean enableIme(final Instrumentation inst, final String imeId) {
- // Needs to check the output message from the checking command, since executeShellCommand()
- // does not pass the exit status code back to the test.
- final String output = executeShellCommand(
- inst.getUiAutomation(), new String[]{"ime", "enable", imeId});
- final String expectedOutput = "Input method " + imeId + ": now enabled";
- if (!output.equals(expectedOutput)) {
- Log.e(TAG, "Unexpected output message. Expected: " + expectedOutput +
- ", Actual: " + output);
- return false;
- }
-
- final InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- final List<InputMethodInfo> enabledInputMethods = imm.getEnabledInputMethodList();
- for (final InputMethodInfo imi : enabledInputMethods) {
- if (imi.getId().equals(imeId))
- return true;
- }
-
- Log.e(TAG, "Failed to enable the given IME (IME ID: " + imeId + ").");
- return false;
- }
-
- /**
- * Removes the specified IME from the available input method list.
- *
- * This operation will {@code @NonNull} final be done synchronously in "ime" command using
- * {@link com.android.server.InputMethodManagerService#setInputMethodEnabled(String, boolean)},
- * which is synchronous.
- *
- * @param imeId IME ID to be disabled.
- * @return {@code true} if the target IME gets disabled successfully. {@code false} if failed.
- */
- public static boolean disableIme(final Instrumentation inst, final String imeId) {
- // Needs to check the output message from the checking command, since executeShellCommand()
- // does not pass the exit status code back to the test.
- final String output = executeShellCommand(
- inst.getUiAutomation(), new String[]{"ime", "disable", imeId});
- final String expectedOutput = "Input method " + imeId + ": now disabled";
- if (!output.equals(expectedOutput)) {
- Log.w(TAG, "Unexpected output message. Expected: " + expectedOutput +
- ", Actual: " + output);
- return false;
- }
-
- final InputMethodManager imm = (InputMethodManager) inst.getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- final List<InputMethodInfo> enabledInputMethods = imm.getEnabledInputMethodList();
- for (final InputMethodInfo imi : enabledInputMethods) {
- if (imi.getId().equals(imeId)) {
- Log.e(TAG, "Failed to disable the given IME (IME ID: " + imeId + ").");
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Switches to the specified IME.
- *
- * This operation will be done synchronously in the "ime" command using
- * {@link InputMethodManager#setInputMethod(IBinder, String)}, which is synchronous.
- *
- * @param imeId IME ID to be switched to.
- * @return {@code true} if the target IME gets active successfully. {@code false} if failed.
- */
- public static boolean setIme(final Instrumentation inst, final String imeId) {
- // Needs to check the output message from the checking command, since executeShellCommand()
- // does not pass the exit status code back to the test.
- final String output = executeShellCommand(
- inst.getUiAutomation(), new String[]{"ime", "set", imeId});
- final String expectedOutput = "Input method " + imeId + " selected";
- if (!output.equals(expectedOutput)) {
- Log.w(TAG, "Unexpected output message. Expected: " + expectedOutput + ", Actual: " +
- output);
- return false;
- }
-
- final String currentImeId = getCurrentImeId(inst);
- if (!TextUtils.equals(currentImeId, imeId)) {
- Log.e(TAG, "Failed to switch the current IME. Expected: " + imeId + ", Actual: " +
- currentImeId);
- return false;
- }
-
- return true;
- }
-}
diff --git a/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java b/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java
deleted file mode 100644
index 12b80a5..0000000
--- a/tests/inputmethod/src/android/inputmethod/cts/MockInputMethodService.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.inputmethod.cts;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.inputmethodservice.InputMethodService;
-
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A mock implementation of {@link InputMethodService} for testing purpose.
- */
-public class MockInputMethodService extends InputMethodService {
- private static AtomicReference<MockInputMethodService> sCurrentInstance =
- new AtomicReference<>();
- private static final HashMap<String, Integer> mCallCounter = new HashMap<>();
-
- /**
- * @return The instance of {@code MockInputMethodService}. If the service has not been created
- * yet or already been destroyed, returns {@code null}.
- */
- @Nullable
- public static MockInputMethodService getInstance() {
- return sCurrentInstance.get();
- }
-
- public static void resetCounter() {
- synchronized (mCallCounter) {
- mCallCounter.clear();
- }
- }
-
- private static void incrementCallCount(@NonNull final String methodName) {
- synchronized (mCallCounter) {
- if (!mCallCounter.containsKey(methodName)) {
- mCallCounter.put(methodName, 0);
- }
- mCallCounter.put(methodName, mCallCounter.get(methodName) + 1);
- }
- }
-
- public static int getCallCount(@NonNull final String methodName) {
- synchronized (mCallCounter) {
- if (!mCallCounter.containsKey(methodName)) {
- return 0;
- }
- return mCallCounter.get(methodName);
- }
- }
-
- public MockInputMethodService() {
- incrementCallCount("<init>");
- }
-
- @Override
- public void onCreate() {
- if (!sCurrentInstance.compareAndSet(null, this)) {
- throw new IllegalStateException("New MockInputMethodService instance is being created "
- + "before the existing instance is destroyed.");
- }
-
- super.onCreate();
- incrementCallCount("onCreate");
- }
-
- @Override
- public void onDestroy() {
- sCurrentInstance.lazySet(null);
- super.onDestroy();
- incrementCallCount("onDestroy");
- }
-}
-
diff --git a/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java b/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
index b2a90f2..5750963 100644
--- a/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
+++ b/tests/tests/content/src/android/content/cts/ImageCaptureUriExtraToClipDataTest.java
@@ -70,19 +70,19 @@
public void testUriExtraOutputMigratedToClipData_imageCaptureIntent() {
startActivityWithAction(MediaStore.ACTION_IMAGE_CAPTURE);
waitForFileReady();
- testFileContents();
+ assertFileContents();
}
public void testUriExtraOutputMigratedToClipData_imageCaptureSecureIntent() {
startActivityWithAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
waitForFileReady();
- testFileContents();
+ assertFileContents();
}
public void testUriExtraOutputMigratedToClipData_videoCaptureIntent() {
startActivityWithAction(MediaStore.ACTION_VIDEO_CAPTURE);
waitForFileReady();
- testFileContents();
+ assertFileContents();
}
private void startActivityWithAction(String action) {
@@ -102,7 +102,7 @@
}
}
- private void testFileContents() {
+ private void assertFileContents() {
char[] buffer = new char[TEST_INPUT.length()];
try {
FileReader reader = new FileReader(mTestFile);
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
index 4c59652..9dbf3f3 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
@@ -61,6 +61,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.text.DecimalFormatSymbols;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
@@ -1138,6 +1139,32 @@
.build());
}
+ // http://b/28384942
+ public void testGenerateWithFarsiLocale() throws Exception {
+ Locale defaultLocale = Locale.getDefault();
+ // Note that we use farsi here because its number formatter doesn't use
+ // arabic digits.
+ Locale fa_IR = Locale.forLanguageTag("fa-IR");
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(fa_IR);
+ assertFalse('0' == dfs.getZeroDigit());
+
+ Locale.setDefault(fa_IR);
+ try {
+ KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
+
+ keyGenerator.initialize(new KeyGenParameterSpec.Builder(
+ TEST_ALIAS_1, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
+ .build());
+
+ keyGenerator.generateKeyPair();
+ } finally {
+ Locale.setDefault(defaultLocale);
+ }
+ }
+
private void assertKeyGenInitSucceeds(String algorithm, AlgorithmParameterSpec params)
throws Exception {
KeyPairGenerator generator = getGenerator(algorithm);
diff --git a/tests/tests/libcoreoj/Android.mk b/tests/tests/libcoreoj/Android.mk
new file mode 100644
index 0000000..4e289b8
--- /dev/null
+++ b/tests/tests/libcoreoj/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(harmony_jdwp_test_src_files)
+LOCAL_STATIC_JAVA_LIBRARIES := core-ojtests-public
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := CtsLibcoreOj
+LOCAL_NO_EMMA_INSTRUMENT := true
+LOCAL_NO_EMMA_COMPILE := true
+LOCAL_CTS_TEST_PACKAGE := android.libcore.oj
+LOCAL_CTS_TARGET_RUNTIME_ARGS := cts_jdwp_test_runtime_target := dalvikvm|\#ABI\#|
+LOCAL_CTS_TESTCASE_XML_INPUT := $(LOCAL_PATH)/CtsTestPackage.xml
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+# Also include the source code as part of the jar. DO NOT REMOVE.
+# FIXME: build/core/java_library.mk:14: *** cts/tests/tests/libcoreoj: Target java libraries may not set LOCAL_ASSET_DIR.
+#LOCAL_ASSET_DIR := libcore/ojluni/src/test
+include $(BUILD_CTS_TARGET_TESTNG_PACKAGE)
diff --git a/tests/inputmethod/AndroidTest.xml b/tests/tests/libcoreoj/AndroidTest.xml
similarity index 60%
rename from tests/inputmethod/AndroidTest.xml
rename to tests/tests/libcoreoj/AndroidTest.xml
index 3a52042..7bb02ad 100644
--- a/tests/inputmethod/AndroidTest.xml
+++ b/tests/tests/libcoreoj/AndroidTest.xml
@@ -13,12 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for CTS Input test cases">
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsInputMethodTestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.inputmethod.cts" />
- </test>
-</configuration>
\ No newline at end of file
+<configuration description="Base config for libcore OJ testing in CTS">
+ <include name="common-config" />
+ <!-- Removes temporary dalvik-cache directory created by JDWP tests -->
+ <option name="run-command:teardown-command" value="rm -rf /data/local/tmp/dalvik-cache" />
+</configuration>
diff --git a/tests/tests/libcoreoj/CtsTestPackage.xml b/tests/tests/libcoreoj/CtsTestPackage.xml
new file mode 100644
index 0000000..2578fb9
--- /dev/null
+++ b/tests/tests/libcoreoj/CtsTestPackage.xml
@@ -0,0 +1,450 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TestPackage name="CtsLibcoreOj" appPackageName="android.libcore.oj" version="1.0" testType="testNGDeviceTest" jarPath="CtsLibcoreOj.jar">
+ <TestSuite name="org">
+ <TestSuite name="openjdk">
+ <TestSuite name="tests">
+ <TestSuite name="java">
+ <TestSuite name="util">
+ <TestSuite name="stream">
+ <TestCase name="CollectionAndMapModifyStreamTest">
+ <Test name="testCollectionSizeRemove" />
+ <Test name="testMapEntriesSizeRemove" />
+ <Test name="testMapKeysSizeRemove" />
+ <Test name="testMapValuesSizeRemove" />
+ </TestCase>
+ <TestCase name="ConcatOpTest">
+ <Test name="testDoubleSize" />
+ <Test name="testIntSize" />
+ <Test name="testLongSize" />
+ <Test name="testOps" />
+ <Test name="testSize" />
+ </TestCase>
+ <TestCase name="ConcatTest">
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ </TestCase>
+ <TestCase name="CountLargeTest">
+ <Test name="testDoubleLarge" />
+ <Test name="testIntLarge" />
+ <Test name="testLongLarge" />
+ <Test name="testRefLarge" />
+ </TestCase>
+ <TestCase name="CountTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="DistinctOpTest">
+ <Test name="testDistinctDistinct" />
+ <Test name="testDistinctSorted" />
+ <Test name="testOp" />
+ <Test name="testOpWithNull" />
+ <Test name="testOpWithNullSorted" />
+ <Test name="testSortedDistinct" />
+ <Test name="testStable" />
+ <Test name="testUniqOp" />
+ <Test name="testWithUnorderedInfiniteStream" />
+ </TestCase>
+ <TestCase name="DoublePrimitiveOpsTests">
+ <Test name="testLimit" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="ExplodeOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testFlatMap" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="FilterOpTest">
+ <Test name="testFilter" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="FindAnyOpTest">
+ <Test name="testDoubleStream" />
+ <Test name="testFindAny" />
+ <Test name="testFindAnyParallel" />
+ <Test name="testIntStream" />
+ <Test name="testLongStream" />
+ <Test name="testStream" />
+ </TestCase>
+ <TestCase name="FindFirstOpTest">
+ <Test name="testDoubleStream" />
+ <Test name="testFindFirst" />
+ <Test name="testIntStream" />
+ <Test name="testLongStream" />
+ <Test name="testStream" />
+ </TestCase>
+ <TestCase name="ForEachOpTest">
+ <Test name="testDoubleForEachOrdered" />
+ <Test name="testDoubleOps" />
+ <Test name="testForEach" />
+ <Test name="testForEach" />
+ <Test name="testForEachOrdered" />
+ <Test name="testIntForEach" />
+ <Test name="testIntForEachOrdered" />
+ <Test name="testLongForEachOrdered" />
+ <Test name="testLongOps" />
+ </TestCase>
+ <TestCase name="GroupByOpTest">
+ <Test name="testBypassCollect" />
+ <Test name="testGroupBy" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="InfiniteStreamWithLimitOpTest">
+ <Test name="testDoubleSubsizedWithRange" />
+ <Test name="testDoubleUnorderedFinite" />
+ <Test name="testDoubleUnorderedGenerator" />
+ <Test name="testDoubleUnorderedIteration" />
+ <Test name="testDoubleUnorderedSizedNotSubsizedFinite" />
+ <Test name="testIntSubsizedWithRange" />
+ <Test name="testIntUnorderedFinite" />
+ <Test name="testIntUnorderedGenerator" />
+ <Test name="testIntUnorderedIteration" />
+ <Test name="testIntUnorderedSizedNotSubsizedFinite" />
+ <Test name="testLongSubsizedWithRange" />
+ <Test name="testLongUnorderedFinite" />
+ <Test name="testLongUnorderedGenerator" />
+ <Test name="testLongUnorderedIteration" />
+ <Test name="testLongUnorderedSizedNotSubsizedFinite" />
+ <Test name="testSubsizedWithRange" />
+ <Test name="testUnorderedFinite" />
+ <Test name="testUnorderedGenerator" />
+ <Test name="testUnorderedIteration" />
+ <Test name="testUnorderedSizedNotSubsizedFinite" />
+ </TestCase>
+ <TestCase name="IntPrimitiveOpsTests">
+ <Test name="testBox" />
+ <Test name="testForEach" />
+ <Test name="testLimit" />
+ <Test name="testMap" />
+ <Test name="testParForEach" />
+ <Test name="testParSum" />
+ <Test name="testSequential" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testSum" />
+ <Test name="testTee" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="IntReduceTest">
+ <Test name="testOps" />
+ <Test name="testReduce" />
+ </TestCase>
+ <TestCase name="IntSliceOpTest">
+ <Test name="testLimit" />
+ <Test name="testLimitOps" />
+ <Test name="testLimitParallel" />
+ <Test name="testLimitShortCircuit" />
+ <Test name="testLimitSort" />
+ <Test name="testSkip" />
+ <Test name="testSkipLimit" />
+ <Test name="testSkipLimitOps" />
+ <Test name="testSkipOps" />
+ <Test name="testSkipParallel" />
+ </TestCase>
+ <TestCase name="IntUniqOpTest">
+ <Test name="testOp" />
+ <Test name="testOpSorted" />
+ <Test name="testUniqOp" />
+ </TestCase>
+ <TestCase name="LongPrimitiveOpsTests">
+ <Test name="testBox" />
+ <Test name="testForEach" />
+ <Test name="testLimit" />
+ <Test name="testMap" />
+ <Test name="testParForEach" />
+ <Test name="testParSum" />
+ <Test name="testSequential" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testSum" />
+ <Test name="testTee" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="MapOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testEveryMapShape" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testMap" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="MatchOpTest">
+ <Test name="testDoubleInfinite" />
+ <Test name="testDoubleStream" />
+ <Test name="testDoubleStreamMatches" />
+ <Test name="testInfinite" />
+ <Test name="testIntInfinite" />
+ <Test name="testIntStream" />
+ <Test name="testIntStreamMatches" />
+ <Test name="testLongInfinite" />
+ <Test name="testLongStream" />
+ <Test name="testLongStreamMatches" />
+ <Test name="testStream" />
+ <Test name="testStreamMatches" />
+ </TestCase>
+ <TestCase name="MinMaxTest">
+ <Test name="testDoubleMinMax" />
+ <Test name="testDoubleOps" />
+ <Test name="testIntMinMax" />
+ <Test name="testIntOps" />
+ <Test name="testLongMinMax" />
+ <Test name="testLongOps" />
+ <Test name="testMinMax" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="PrimitiveAverageOpTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="PrimitiveSumTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="RangeTest">
+ <Test name="tesIntRangeReduce" />
+ <Test name="testInfiniteRangeFindFirst" />
+ <Test name="testIntInfiniteRangeFindFirst" />
+ <Test name="testIntInfiniteRangeLimit" />
+ <Test name="testIntRange" />
+ <Test name="testLongInfiniteRangeFindFirst" />
+ <Test name="testLongInfiniteRangeLimit" />
+ <Test name="testLongLongRange" />
+ <Test name="testLongLongRangeClosed" />
+ <Test name="testLongRange" />
+ <Test name="testLongRangeReduce" />
+ </TestCase>
+ <TestCase name="ReduceByOpTest">
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="ReduceTest">
+ <Test name="testOps" />
+ <Test name="testReduce" />
+ </TestCase>
+ <TestCase name="SequentialOpTest">
+ <Test name="testLazy" />
+ <Test name="testMixedSeqPar" />
+ </TestCase>
+ <TestCase name="SliceOpTest">
+ <Test name="testLimit" />
+ <Test name="testLimitOps" />
+ <Test name="testLimitShortCircuit" />
+ <Test name="testLimitSort" />
+ <Test name="testSkip" />
+ <Test name="testSkipLimit" />
+ <Test name="testSkipLimitOps" />
+ <Test name="testSkipLimitOpsWithNonSplittingSpliterator" />
+ <Test name="testSkipOps" />
+ <Test name="testSlice" />
+ </TestCase>
+ <TestCase name="SortedOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testDoubleSequentialShortCircuitTerminal" />
+ <Test name="testDoubleSortSort" />
+ <Test name="testDoubleStreamTooLarge" />
+ <Test name="testIntOps" />
+ <Test name="testIntSequentialShortCircuitTerminal" />
+ <Test name="testIntSortSort" />
+ <Test name="testIntStreamTooLarge" />
+ <Test name="testLongOps" />
+ <Test name="testLongSequentialShortCircuitTerminal" />
+ <Test name="testLongSortSort" />
+ <Test name="testLongStreamTooLarge" />
+ <Test name="testOps" />
+ <Test name="testRefStreamTooLarge" />
+ <Test name="testSequentialShortCircuitTerminal" />
+ <Test name="testSortSort" />
+ <Test name="testSorted" />
+ </TestCase>
+ <TestCase name="SpliteratorTest">
+ <Test name="testDoubleSpliterator" />
+ <Test name="testIntSpliterator" />
+ <Test name="testLongSpliterator" />
+ <Test name="testSpliterator" />
+ </TestCase>
+ <TestCase name="StreamBuilderTest">
+ <Test name="testAfterBuilding" />
+ <Test name="testDoubleAfterBuilding" />
+ <Test name="testDoubleSingleton" />
+ <Test name="testDoubleStreamBuilder" />
+ <Test name="testIntAfterBuilding" />
+ <Test name="testIntSingleton" />
+ <Test name="testIntStreamBuilder" />
+ <Test name="testLongAfterBuilding" />
+ <Test name="testLongSingleton" />
+ <Test name="testLongStreamBuilder" />
+ <Test name="testSingleton" />
+ <Test name="testStreamBuilder" />
+ </TestCase>
+ <TestCase name="StreamCloseTest">
+ <Test name="testCascadedExceptions" />
+ <Test name="testEmptyCloseHandler" />
+ <Test name="testOneCloseHandler" />
+ <Test name="testTwoCloseHandlers" />
+ </TestCase>
+ <TestCase name="StreamLinkTest">
+ <Test name="testDoubleManyStreams" />
+ <Test name="testIntManyStreams" />
+ <Test name="testLongManyStreams" />
+ <Test name="testManyStreams" />
+ </TestCase>
+ <TestCase name="StreamParSeqTest">
+ <Test name="testParSeq" />
+ </TestCase>
+ <TestCase name="StreamSpliteratorTest">
+ <Test name="testDoubleParSpliterators" />
+ <Test name="testDoubleSpliterators" />
+ <Test name="testDoubleSplitting" />
+ <Test name="testDoubleStreamSpliterators" />
+ <Test name="testIntParSpliterators" />
+ <Test name="testIntSpliterators" />
+ <Test name="testIntSplitting" />
+ <Test name="testIntStreamSpliterators" />
+ <Test name="testLongParSpliterators" />
+ <Test name="testLongSpliterators" />
+ <Test name="testLongSplitting" />
+ <Test name="testLongStreamSpliterators" />
+ <Test name="testParSpliterators" />
+ <Test name="testSpliterators" />
+ <Test name="testSplitting" />
+ <Test name="testStreamSpliterators" />
+ </TestCase>
+ <TestCase name="SummaryStatisticsTest">
+ <Test name="testDoubleStatistics" />
+ <Test name="testIntStatistics" />
+ <Test name="testLongStatistics" />
+ </TestCase>
+ <TestCase name="TabulatorsTest">
+ <Test name="testComposeFinisher" />
+ <Test name="testGroupedReduce" />
+ <Test name="testJoin" />
+ <Test name="testReduce" />
+ <Test name="testSimpleGroupBy" />
+ <Test name="testSimplePartition" />
+ <Test name="testSimpleToMap" />
+ <Test name="testTwoLevelGroupBy" />
+ <Test name="testTwoLevelPartition" />
+ </TestCase>
+ <TestCase name="TeeOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testOps" />
+ <Test name="testTee" />
+ </TestCase>
+ <TestCase name="ToArrayOpTest">
+ <Test name="testAsArrayWithType" />
+ <Test name="testDistinctAndSortedPermutations" />
+ <Test name="testDoubleDistinctAndSortedPermutations" />
+ <Test name="testDoubleOps" />
+ <Test name="testDoubleOpsWithFilter" />
+ <Test name="testDoubleOpsWithFlatMap" />
+ <Test name="testDoubleOpsWithMap" />
+ <Test name="testDoubleOpsWithSorted" />
+ <Test name="testDoubleStatefulOpPermutations" />
+ <Test name="testIntDistinctAndSortedPermutations" />
+ <Test name="testIntOps" />
+ <Test name="testIntOpsWithFilter" />
+ <Test name="testIntOpsWithFlatMap" />
+ <Test name="testIntOpsWithMap" />
+ <Test name="testIntOpsWithSorted" />
+ <Test name="testIntStatefulOpPermutations" />
+ <Test name="testLongDistinctAndSortedPermutations" />
+ <Test name="testLongOps" />
+ <Test name="testLongOpsWithFilter" />
+ <Test name="testLongOpsWithFlatMap" />
+ <Test name="testLongOpsWithMap" />
+ <Test name="testLongOpsWithSorted" />
+ <Test name="testLongStatefulOpPermutations" />
+ <Test name="testOps" />
+ <Test name="testOpsWithFilter" />
+ <Test name="testOpsWithFlatMap" />
+ <Test name="testOpsWithMap" />
+ <Test name="testOpsWithSorted" />
+ <Test name="testStatefulOpPermutations" />
+ <Test name="testToArray" />
+ </TestCase>
+ </TestSuite>
+ <TestCase name="FillableStringTest">
+ <Test name="testStringBuffer" />
+ <Test name="testStringBuilder" />
+ <Test name="testStringJoiner" />
+ </TestCase>
+ <TestCase name="MapTest">
+ <Test name="testForEach" />
+ <Test name="testReplaceAll" />
+ </TestCase>
+ </TestSuite>
+ <TestSuite name="lang">
+ <TestSuite name="invoke">
+ <TestCase name="DeserializeMethodTest">
+ <Test name="testCapturingNonSerLambda" />
+ <Test name="testCapturingNonserIntersectionLambda" />
+ <Test name="testCapturingSerLambda" />
+ <Test name="testEmptyClass" />
+ </TestCase>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+</TestPackage>
diff --git a/tests/tests/location/src/android/location/cts/GpsStatusTest.java b/tests/tests/location/src/android/location/cts/GpsStatusTest.java
index 92ec137..8e2d421 100644
--- a/tests/tests/location/src/android/location/cts/GpsStatusTest.java
+++ b/tests/tests/location/src/android/location/cts/GpsStatusTest.java
@@ -48,9 +48,11 @@
int count = 0;
while (iterator.hasNext()) {
count++;
+ if (count > maxSatellites) {
+ // the real total could not be larger than maxSatellites
+ fail("Found more satellites than: " + maxSatellites);
+ }
}
- // the real total could not be larger than maxSatellites
- assertTrue(count <= maxSatellites);
}
public void testGetTimeToFirstFix() {
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index d7ec5f1..c32be5c 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -35,6 +35,7 @@
import static android.media.AudioManager.VIBRATE_TYPE_RINGER;
import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
@@ -52,6 +53,7 @@
private final static long TIME_TO_PLAY = 2000;
private final static String APPOPS_OP_STR = "android:write_settings";
private AudioManager mAudioManager;
+ private NotificationManager mNm;
private boolean mHasVibrator;
private boolean mUseFixedVolume;
private boolean mIsTelevision;
@@ -64,6 +66,7 @@
Utils.enableAppOps(mContext.getPackageName(), APPOPS_OP_STR, getInstrumentation());
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
mUseFixedVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
@@ -389,26 +392,28 @@
}
assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
- // Apps without policy access cannot change vibrate -> silent.
- Utils.toggleNotificationPolicyAccess(
- mContext.getPackageName(), getInstrumentation(), true);
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
- Utils.toggleNotificationPolicyAccess(
- mContext.getPackageName(), getInstrumentation(), false);
+ if (mHasVibrator) {
+ // Apps without policy access cannot change vibrate -> silent.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
- try {
- mAudioManager.setRingerMode(RINGER_MODE_SILENT);
- fail("Apps without notification policy access cannot change ringer mode");
- } catch (SecurityException e) {
+ try {
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ fail("Apps without notification policy access cannot change ringer mode");
+ } catch (SecurityException e) {
+ }
+
+ // Apps without policy access can change vibrate -> normal and vice versa.
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
+ assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
}
-
- // Apps without policy access can change vibrate -> normal and vice versa.
- assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
- mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
- assertEquals(RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
- mAudioManager.setRingerMode(RINGER_MODE_VIBRATE);
- assertEquals(RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
} finally {
Utils.toggleNotificationPolicyAccess(
mContext.getPackageName(), getInstrumentation(), false);
@@ -618,18 +623,94 @@
}
}
- public void testMute() throws Exception {
+ public void testMuteDndAffectedStreams() throws Exception {
if (mUseFixedVolume) {
return;
}
+ int[] streams = { AudioManager.STREAM_RING };
+ try {
+ // Mute streams
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_SILENT);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ // Verify streams cannot be unmuted without policy access.
+ for (int i = 0; i < streams.length; i++) {
+ try {
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+ try {
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE,
+ 0);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+
+ try {
+ mAudioManager.setStreamMute(streams[i], false);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+ }
+
+ // This ensures we're out of vibrate or silent modes.
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
+ for (int i = 0; i < streams.length; i++) {
+ // ensure each stream is on and turned up.
+ mAudioManager.setStreamVolume(streams[i],
+ mAudioManager.getStreamMaxVolume(streams[i]),
+ 0);
+
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ try {
+ mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+ try {
+ mAudioManager.adjustStreamVolume(
+ streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+
+ try {
+ mAudioManager.setStreamMute(streams[i], true);
+ assertEquals("Apps without Notification policy access can't change ringer mode",
+ RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+ } catch (SecurityException e) {
+ }
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ testStreamMuting(streams[i]);
+ }
+ } finally {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ public void testMuteDndUnaffectedStreams() throws Exception {
+ if (mUseFixedVolume) {
+ return;
+ }
int[] streams = {
AudioManager.STREAM_VOICE_CALL,
AudioManager.STREAM_MUSIC,
- AudioManager.STREAM_RING,
- AudioManager.STREAM_ALARM,
- AudioManager.STREAM_NOTIFICATION,
- AudioManager.STREAM_SYSTEM };
+ AudioManager.STREAM_ALARM
+ };
try {
int muteAffectedStreams = System.getInt(mContext.getContentResolver(),
@@ -664,34 +745,7 @@
mAudioManager.isStreamMute(streams[i]));
continue;
}
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_MUTE, 0);
- assertTrue("Muting stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_UNMUTE, 0);
- assertFalse("Unmuting stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
- assertTrue("Toggling mute on stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.adjustStreamVolume(streams[i], AudioManager.ADJUST_TOGGLE_MUTE, 0);
- assertFalse("Toggling mute on stream " + streams[i] + " failed.",
- mAudioManager.isStreamMute(streams[i]));
-
- mAudioManager.setStreamMute(streams[i], true);
- assertTrue("Muting stream " + streams[i] + " using setStreamMute failed",
- mAudioManager.isStreamMute(streams[i]));
-
- // mute it three more times to verify the ref counting is gone.
- mAudioManager.setStreamMute(streams[i], true);
- mAudioManager.setStreamMute(streams[i], true);
- mAudioManager.setStreamMute(streams[i], true);
-
- mAudioManager.setStreamMute(streams[i], false);
- assertFalse("Unmuting stream " + streams[i] + " using setStreamMute failed.",
- mAudioManager.isStreamMute(streams[i]));
+ testStreamMuting(streams[i]);
}
} finally {
Utils.toggleNotificationPolicyAccess(
@@ -699,6 +753,37 @@
}
}
+ private void testStreamMuting(int stream) {
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
+ assertTrue("Muting stream " + stream + " failed.",
+ mAudioManager.isStreamMute(stream));
+
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_UNMUTE, 0);
+ assertFalse("Unmuting stream " + stream + " failed.",
+ mAudioManager.isStreamMute(stream));
+
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ assertTrue("Toggling mute on stream " + stream + " failed.",
+ mAudioManager.isStreamMute(stream));
+
+ mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_TOGGLE_MUTE, 0);
+ assertFalse("Toggling mute on stream " + stream + " failed.",
+ mAudioManager.isStreamMute(stream));
+
+ mAudioManager.setStreamMute(stream, true);
+ assertTrue("Muting stream " + stream + " using setStreamMute failed",
+ mAudioManager.isStreamMute(stream));
+
+ // mute it three more times to verify the ref counting is gone.
+ mAudioManager.setStreamMute(stream, true);
+ mAudioManager.setStreamMute(stream, true);
+ mAudioManager.setStreamMute(stream, true);
+
+ mAudioManager.setStreamMute(stream, false);
+ assertFalse("Unmuting stream " + stream + " using setStreamMute failed.",
+ mAudioManager.isStreamMute(stream));
+ }
+
public void testSetInvalidRingerMode() {
int ringerMode = mAudioManager.getRingerMode();
mAudioManager.setRingerMode(-1337);
@@ -708,6 +793,110 @@
assertEquals(ringerMode, mAudioManager.getRingerMode());
}
+ public void testAdjustVolumeInTotalSilenceMode() throws Exception {
+ if (mUseFixedVolume || mIsTelevision) {
+ return;
+ }
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
+
+ int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioManager.adjustStreamVolume(
+ AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
+ assertEquals(musicVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+ } finally {
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ public void testAdjustVolumeInAlarmsOnlyMode() throws Exception {
+ if (mUseFixedVolume || mIsTelevision) {
+ return;
+ }
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
+
+ int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioManager.adjustStreamVolume(
+ AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
+ int volumeDelta =
+ getVolumeDelta(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+ assertEquals(musicVolume + volumeDelta,
+ mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+ } finally {
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ public void testSetStreamVolumeInTotalSilenceMode() throws Exception {
+ if (mUseFixedVolume || mIsTelevision) {
+ return;
+ }
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE);
+
+ int musicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 7, 0);
+ assertEquals(musicVolume, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+ mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 7, 0);
+ assertEquals(7, mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
+ } finally {
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ public void testSetStreamVolumeInAlarmsOnlyMode() throws Exception {
+ if (mUseFixedVolume || mIsTelevision) {
+ return;
+ }
+ try {
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), true);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 1, 0);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALARMS);
+
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 3, 0);
+ assertEquals(3, mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
+
+ mAudioManager.setStreamVolume(AudioManager.STREAM_RING, 7, 0);
+ assertEquals(7, mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
+ } finally {
+ setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_ALL);
+ Utils.toggleNotificationPolicyAccess(
+ mContext.getPackageName(), getInstrumentation(), false);
+ }
+ }
+
+ private void setInterruptionFilter(int filter) throws Exception {
+ mNm.setInterruptionFilter(filter);
+ for (int i = 0; i < 5; i++) {
+ if (mNm.getCurrentInterruptionFilter() == filter) {
+ break;
+ }
+ Thread.sleep(1000);
+ }
+ }
+
private int getVolumeDelta(int volume) {
return 1;
}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 4eaefc3..d63cbe8 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -22,6 +22,7 @@
import android.content.res.AssetFileDescriptor;
import android.cts.util.MediaUtils;
import android.graphics.Rect;
+import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaDataSource;
@@ -50,6 +51,7 @@
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.Vector;
@@ -887,15 +889,39 @@
return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
+ private Camera mCamera;
private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
- final int width = RECORDED_VIDEO_WIDTH;
- final int height = RECORDED_VIDEO_HEIGHT;
+ int width = RECORDED_VIDEO_WIDTH;
+ int height = RECORDED_VIDEO_HEIGHT;
final String file = RECORDED_FILE;
final long durationMs = RECORDED_DURATION_MS;
if (!hasCamera()) {
return;
}
+
+ boolean isSupported = false;
+ mCamera = Camera.open(0);
+ Camera.Parameters parameters = mCamera.getParameters();
+ List<Camera.Size> videoSizes = parameters.getSupportedVideoSizes();
+ // getSupportedVideoSizes returns null when separate video/preview size
+ // is not supported.
+ if (videoSizes == null) {
+ videoSizes = parameters.getSupportedPreviewSizes();
+ }
+ for (Camera.Size size : videoSizes)
+ {
+ if (size.width == width && size.height == height) {
+ isSupported = true;
+ break;
+ }
+ }
+ mCamera.release();
+ mCamera = null;
+ if (!isSupported) {
+ width = videoSizes.get(0).width;
+ height = videoSizes.get(0).height;
+ }
checkOrientation(angle);
recordVideo(width, height, angle, file, durationMs);
checkDisplayedVideoSize(width, height, angle, file);
diff --git a/tests/tests/media/src/android/media/cts/RoutingTest.java b/tests/tests/media/src/android/media/cts/RoutingTest.java
index c0e9a3e..22aaaa3 100644
--- a/tests/tests/media/src/android/media/cts/RoutingTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingTest.java
@@ -23,6 +23,7 @@
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
+import android.media.AudioRouting;
import android.media.AudioTrack;
import android.media.MediaRecorder;
@@ -36,7 +37,12 @@
import java.lang.Runnable;
/**
- * TODO: Insert description here. (generated by pmclean)
+ * AudioTrack / AudioRecord preferred device and routing listener tests.
+ * The routing tests are mostly here to exercise the routing code, as an actual test would require
+ * adding / removing an audio device for the listeners to be called.
+ * The routing listener code is designed to run for two versions of the routing code:
+ * - the deprecated AudioTrack.OnRoutingChangedListener and AudioRecord.OnRoutingChangedListener
+ * - the N AudioRouting.OnRoutingChangedListener
*/
public class RoutingTest extends AndroidTestCase {
private static final String TAG = "RoutingTest";
@@ -115,29 +121,75 @@
return myLooper;
}
- private class AudioTrackRoutingListener implements AudioTrack.OnRoutingChangedListener {
+ private class AudioTrackRoutingListener implements AudioTrack.OnRoutingChangedListener,
+ AudioRouting.OnRoutingChangedListener
+ {
public void onRoutingChanged(AudioTrack audioTrack) {}
+ public void onRoutingChanged(AudioRouting audioRouting) {}
}
+
public void test_audioTrack_RoutingListener() {
+ test_audioTrack_RoutingListener(false /*usesAudioRouting*/);
+ }
+
+ public void test_audioTrack_audioRouting_RoutingListener() {
+ test_audioTrack_RoutingListener(true /*usesAudioRouting*/);
+ }
+
+ private void test_audioTrack_RoutingListener(boolean usesAudioRouting) {
AudioTrack audioTrack = allocAudioTrack();
- audioTrack.addOnRoutingChangedListener(null, null);
+ // null listener
+ if (usesAudioRouting) {
+ audioTrack.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) null, null);
+ } else {
+ audioTrack.addOnRoutingChangedListener(
+ (AudioTrack.OnRoutingChangedListener) null, null);
+ }
AudioTrackRoutingListener listener = new AudioTrackRoutingListener();
AudioTrackRoutingListener someOtherListener = new AudioTrackRoutingListener();
- audioTrack.addOnRoutingChangedListener(listener, null);
+ // add a listener
+ if (usesAudioRouting) {
+ audioTrack.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener, null);
+ } else {
+ audioTrack.addOnRoutingChangedListener(listener, null);
+ }
- // remove a listener we didn't add
- audioTrack.removeOnRoutingChangedListener(someOtherListener);
-
- audioTrack.removeOnRoutingChangedListener(listener);
+ // remove listeners
+ if (usesAudioRouting) {
+ // remove a listener we didn't add
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) someOtherListener);
+ // remove a valid listener
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener);
+ } else {
+ // remove a listener we didn't add
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioTrack.OnRoutingChangedListener) someOtherListener);
+ // remove a valid listener
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioTrack.OnRoutingChangedListener) listener);
+ }
Looper myLooper = prepareIfNeededLooper();
- audioTrack.addOnRoutingChangedListener(listener, new Handler());
- audioTrack.removeOnRoutingChangedListener(listener);
+ if (usesAudioRouting) {
+ audioTrack.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener, new Handler());
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener);
+ } else {
+ audioTrack.addOnRoutingChangedListener(
+ (AudioTrack.OnRoutingChangedListener) listener, new Handler());
+ audioTrack.removeOnRoutingChangedListener(
+ (AudioTrack.OnRoutingChangedListener) listener);
+ }
audioTrack.release();
if (myLooper != null) {
@@ -160,33 +212,78 @@
return audioRecord;
}
- private class AudioRecordRoutingListener implements AudioRecord.OnRoutingChangedListener {
+ private class AudioRecordRoutingListener implements AudioRecord.OnRoutingChangedListener,
+ AudioRouting.OnRoutingChangedListener
+ {
public void onRoutingChanged(AudioRecord audioRecord) {}
+ public void onRoutingChanged(AudioRouting audioRouting) {}
}
public void test_audioRecord_RoutingListener() {
+ test_audioRecord_RoutingListener(false /*usesAudioRouting*/);
+ }
+
+ public void test_audioRecord_audioRouting_RoutingListener() {
+ test_audioRecord_RoutingListener(true /*usesAudioRouting*/);
+ }
+
+ private void test_audioRecord_RoutingListener(boolean usesAudioRouting) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
// Can't do it so skip this test
return;
}
AudioRecord audioRecord = allocAudioRecord();
- audioRecord.addOnRoutingChangedListener(null, null);
+ // null listener
+ if (usesAudioRouting) {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) null, null);
+ } else {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) null, null);
+ }
AudioRecordRoutingListener listener = new AudioRecordRoutingListener();
AudioRecordRoutingListener someOtherListener = new AudioRecordRoutingListener();
- audioRecord.addOnRoutingChangedListener(listener, null);
+ // add a listener
+ if (usesAudioRouting) {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener, null);
+ } else {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) listener, null);
+ }
- // remove a listener we didn't add
- audioRecord.removeOnRoutingChangedListener(someOtherListener);
-
- audioRecord.removeOnRoutingChangedListener(listener);
+ // remove listeners
+ if (usesAudioRouting) {
+ // remove a listener we didn't add
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) someOtherListener);
+ // remove a valid listener
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener);
+ } else {
+ // remove a listener we didn't add
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) someOtherListener);
+ // remove a valid listener
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) listener);
+ }
Looper myLooper = prepareIfNeededLooper();
- audioRecord.addOnRoutingChangedListener(listener, new Handler());
-
- audioRecord.removeOnRoutingChangedListener(listener);
+ if (usesAudioRouting) {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener, new Handler());
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRouting.OnRoutingChangedListener) listener);
+ } else {
+ audioRecord.addOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) listener, new Handler());
+ audioRecord.removeOnRoutingChangedListener(
+ (AudioRecord.OnRoutingChangedListener) listener);
+ }
audioRecord.release();
if (myLooper != null) {
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 4112466..231db97 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -38,9 +38,16 @@
import android.test.AndroidTestCase;
import android.util.Log;
import android.os.SystemProperties;
+import android.system.Os;
+import android.system.OsConstants;
import com.android.internal.telephony.PhoneConstants;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -57,7 +64,15 @@
public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
+
private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
+ private static final String TEST_HOST = "connectivitycheck.gstatic.com";
+ private static final int SOCKET_TIMEOUT_MS = 2000;
+ private static final int HTTP_PORT = 80;
+ private static final String HTTP_REQUEST =
+ "GET /generate_204 HTTP/1.0\r\n" +
+ "Host: " + TEST_HOST + "\r\n" +
+ "Connection: keep-alive\r\n\r\n";
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
private static final String NETWORK_CALLBACK_ACTION =
@@ -249,6 +264,12 @@
mCm.getBackgroundDataSetting();
}
+ private NetworkRequest makeWifiNetworkRequest() {
+ return new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ }
+
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
@@ -265,16 +286,14 @@
}
// We will register for a WIFI network being available or lost.
- final NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+ Network wifiNetwork = null;
try {
// Make sure WiFi is connected to an access point to start with.
@@ -285,10 +304,11 @@
// Now we should expect to get a network callback about availability of the wifi
// network even if it was already connected as a state-based action when the callback
// is registered.
- assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
- callback.waitForAvailable());
+ wifiNetwork = callback.waitForAvailable();
+ assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
+ wifiNetwork);
- assertTrue("Did not receive NetworkCallback.onAvailable for any default network",
+ assertNotNull("Did not receive NetworkCallback.onAvailable for any default network",
defaultTrackingCallback.waitForAvailable());
} catch (InterruptedException e) {
fail("Broadcast receiver or NetworkCallback wait was interrupted.");
@@ -298,7 +318,7 @@
// Return WiFi to its original enabled/disabled state.
if (!previousWifiEnabledState) {
- disconnectFromWifi();
+ disconnectFromWifi(wifiNetwork);
}
}
}
@@ -329,10 +349,7 @@
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// We will register for a WIFI network being available or lost.
- NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- mCm.registerNetworkCallback(request, pendingIntent);
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
@@ -356,7 +373,7 @@
// Return WiFi to its original enabled/disabled state.
if (!previousWifiEnabledState) {
- disconnectFromWifi();
+ disconnectFromWifi(null);
}
}
}
@@ -370,8 +387,10 @@
// We will toggle the state of wifi to generate a connectivity change.
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+
if (previousWifiEnabledState) {
- disconnectFromWifi();
+ Network wifiNetwork = getWifiNetwork();
+ disconnectFromWifi(wifiNetwork);
} else {
connectToWifi();
}
@@ -387,12 +406,16 @@
if (previousWifiEnabledState) {
connectToWifi();
} else {
- disconnectFromWifi();
+ disconnectFromWifi(null);
}
}
/** Enable WiFi and wait for it to become connected to a network. */
- private void connectToWifi() {
+ private Network connectToWifi() {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+ Network wifiNetwork = null;
+
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
IntentFilter filter = new IntentFilter();
@@ -402,36 +425,94 @@
boolean connected = false;
try {
assertTrue(mWifiManager.setWifiEnabled(true));
+ // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
+ wifiNetwork = callback.waitForAvailable();
+ assertNotNull(wifiNetwork);
connected = receiver.waitForState();
} catch (InterruptedException ex) {
fail("connectToWifi was interrupted");
} finally {
+ mCm.unregisterNetworkCallback(callback);
mContext.unregisterReceiver(receiver);
}
assertTrue("Wifi must be configured to connect to an access point for this test.",
connected);
+ return wifiNetwork;
+ }
+
+ private Socket getBoundSocket(Network network, String host, int port) throws IOException {
+ InetSocketAddress addr = new InetSocketAddress(host, port);
+ Socket s = network.getSocketFactory().createSocket();
+ try {
+ s.setSoTimeout(SOCKET_TIMEOUT_MS);
+ s.connect(addr, SOCKET_TIMEOUT_MS);
+ } catch (IOException e) {
+ s.close();
+ throw e;
+ }
+ return s;
+ }
+
+ private void testHttpRequest(Socket s) throws IOException {
+ OutputStream out = s.getOutputStream();
+ InputStream in = s.getInputStream();
+
+ final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
+ byte[] responseBytes = new byte[4096];
+ out.write(requestBytes);
+ in.read(responseBytes);
+ assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
}
/** Disable WiFi and wait for it to become disconnected from the network. */
- private void disconnectFromWifi() {
+ private void disconnectFromWifi(Network wifiNetworkToCheck) {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+ Network lostWifiNetwork = null;
+
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(receiver, filter);
+ // Assert that we can establish a TCP connection on wifi.
+ Socket wifiBoundSocket = null;
+ if (wifiNetworkToCheck != null) {
+ try {
+ wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
+ testHttpRequest(wifiBoundSocket);
+ } catch (IOException e) {
+ fail("HTTP request before wifi disconnected failed with: " + e);
+ }
+ }
+
boolean disconnected = false;
try {
assertTrue(mWifiManager.setWifiEnabled(false));
+ // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
+ lostWifiNetwork = callback.waitForLost();
+ assertNotNull(lostWifiNetwork);
disconnected = receiver.waitForState();
} catch (InterruptedException ex) {
fail("disconnectFromWifi was interrupted");
} finally {
+ mCm.unregisterNetworkCallback(callback);
mContext.unregisterReceiver(receiver);
}
assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
+
+ // Check that the socket is closed when wifi disconnects.
+ if (wifiBoundSocket != null) {
+ try {
+ testHttpRequest(wifiBoundSocket);
+ fail("HTTP request should not succeed after wifi disconnects");
+ } catch (IOException expected) {
+ assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
+ }
+ }
}
/**
@@ -498,15 +579,48 @@
*/
private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
+ private final CountDownLatch mLostLatch = new CountDownLatch(1);
- public boolean waitForAvailable() throws InterruptedException {
- return mAvailableLatch.await(30, TimeUnit.SECONDS);
+ public Network currentNetwork;
+ public Network lastLostNetwork;
+
+ public Network waitForAvailable() throws InterruptedException {
+ return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
+ }
+
+ public Network waitForLost() throws InterruptedException {
+ return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
}
@Override
public void onAvailable(Network network) {
+ currentNetwork = network;
mAvailableLatch.countDown();
}
+
+ @Override
+ public void onLost(Network network) {
+ lastLostNetwork = network;
+ if (network.equals(currentNetwork)) {
+ currentNetwork = null;
+ }
+ mLostLatch.countDown();
+ }
+ }
+
+ private Network getWifiNetwork() {
+ TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
+ Network network = null;
+ try {
+ network = callback.waitForAvailable();
+ } catch (InterruptedException e) {
+ fail("NetworkCallback wait was interrupted.");
+ } finally {
+ mCm.unregisterNetworkCallback(callback);
+ }
+ assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
+ return network;
}
/** Verify restricted networks cannot be requested. */
@@ -523,8 +637,6 @@
try {
mCm.requestNetwork(request, callback);
fail("No exception thrown when restricted network requested.");
- } catch (SecurityException e) {
- // Expected.
- }
+ } catch (SecurityException expected) {}
}
}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 9428695..22cf279 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -18,8 +18,8 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android" coreApp="true" android:sharedUserId="android.uid.system"
- android:sharedUserLabel="@string/android_system_label">
+ package="android" coreApp="true" android:sharedUserId="android.uid.system"
+ android:sharedUserLabel="@string/android_system_label">
<!-- ================================================ -->
<!-- Special broadcasts that only the system can send -->
@@ -141,43 +141,43 @@
<protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
<protected-broadcast
- android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+ android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
+ android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+ android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+ android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+ android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
- android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+ android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+ android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
<protected-broadcast
- android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
<protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
<protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
@@ -320,11 +320,11 @@
<protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
<protected-broadcast
- android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+ android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
<!-- Defined in RestrictionsManager -->
<protected-broadcast
- android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
+ android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
<!-- Defined in RestrictionsManager -->
<protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
@@ -347,9 +347,6 @@
<protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
- <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
- <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
-
<!-- Added in N -->
<protected-broadcast android:name="android.intent.action.ANR" />
<protected-broadcast android:name="android.intent.action.CALL" />
@@ -470,6 +467,9 @@
<protected-broadcast android:name="com.android.internal.location.ALARM_TIMEOUT" />
<protected-broadcast android:name="android.intent.action.GLOBAL_BUTTON" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+ <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -480,30 +480,31 @@
<!-- ====================================================================== -->
<eat-comment />
- <!-- Used for runtime permissions related to user's contacts and profile. -->
+ <!-- Used for runtime permissions related to contacts and profiles on this
+ device. -->
<permission-group android:name="android.permission-group.CONTACTS"
- android:icon="@drawable/perm_group_contacts"
- android:label="@string/permgrouplab_contacts"
- android:description="@string/permgroupdesc_contacts"
- android:priority="100" />
+ android:icon="@drawable/perm_group_contacts"
+ android:label="@string/permgrouplab_contacts"
+ android:description="@string/permgroupdesc_contacts"
+ android:priority="100" />
<!-- Allows an application to read the user's contacts data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CONTACTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:label="@string/permlab_readContacts"
- android:description="@string/permdesc_readContacts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:label="@string/permlab_readContacts"
+ android:description="@string/permdesc_readContacts"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write the user's contacts data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CONTACTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:label="@string/permlab_writeContacts"
- android:description="@string/permdesc_writeContacts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:label="@string/permlab_writeContacts"
+ android:description="@string/permdesc_writeContacts"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing user's calendar -->
@@ -512,28 +513,28 @@
<!-- Used for runtime permissions related to user's calendar. -->
<permission-group android:name="android.permission-group.CALENDAR"
- android:icon="@drawable/perm_group_calendar"
- android:label="@string/permgrouplab_calendar"
- android:description="@string/permgroupdesc_calendar"
- android:priority="200" />
+ android:icon="@drawable/perm_group_calendar"
+ android:label="@string/permgrouplab_calendar"
+ android:description="@string/permgroupdesc_calendar"
+ android:priority="200" />
<!-- Allows an application to read the user's calendar data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CALENDAR"
- android:permissionGroup="android.permission-group.CALENDAR"
- android:label="@string/permlab_readCalendar"
- android:description="@string/permdesc_readCalendar"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CALENDAR"
+ android:label="@string/permlab_readCalendar"
+ android:description="@string/permdesc_readCalendar"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write the user's calendar data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CALENDAR"
- android:permissionGroup="android.permission-group.CALENDAR"
- android:label="@string/permlab_writeCalendar"
- android:description="@string/permdesc_writeCalendar"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CALENDAR"
+ android:label="@string/permlab_writeCalendar"
+ android:description="@string/permdesc_writeCalendar"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing and modifying user's SMS messages -->
@@ -542,56 +543,56 @@
<!-- Used for runtime permissions related to user's SMS messages. -->
<permission-group android:name="android.permission-group.SMS"
- android:icon="@drawable/perm_group_sms"
- android:label="@string/permgrouplab_sms"
- android:description="@string/permgroupdesc_sms"
- android:priority="300" />
+ android:icon="@drawable/perm_group_sms"
+ android:label="@string/permgrouplab_sms"
+ android:description="@string/permgroupdesc_sms"
+ android:priority="300" />
<!-- Allows an application to send SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.SEND_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_sendSms"
- android:description="@string/permdesc_sendSms"
- android:permissionFlags="costsMoney"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_sendSms"
+ android:description="@string/permdesc_sendSms"
+ android:permissionFlags="costsMoney"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to receive SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveSms"
- android:description="@string/permdesc_receiveSms"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveSms"
+ android:description="@string/permdesc_receiveSms"
+ android:protectionLevel="dangerous"/>
<!-- Allows an application to read SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_readSms"
- android:description="@string/permdesc_readSms"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_readSms"
+ android:description="@string/permdesc_readSms"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to receive WAP push messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_WAP_PUSH"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveWapPush"
- android:description="@string/permdesc_receiveWapPush"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveWapPush"
+ android:description="@string/permdesc_receiveWapPush"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to monitor incoming MMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_MMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveMms"
- android:description="@string/permdesc_receiveMms"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveMms"
+ android:description="@string/permdesc_receiveMms"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to read previously received cell broadcast
messages and to register a content observer to get notifications when
@@ -606,10 +607,10 @@
<p>Protection level: dangerous
@hide Pending API council approval -->
<permission android:name="android.permission.READ_CELL_BROADCASTS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_readCellBroadcasts"
- android:description="@string/permdesc_readCellBroadcasts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_readCellBroadcasts"
+ android:description="@string/permdesc_readCellBroadcasts"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing external storage -->
@@ -618,10 +619,10 @@
<!-- Used for runtime permissions related to the shared external storage. -->
<permission-group android:name="android.permission-group.STORAGE"
- android:icon="@drawable/perm_group_storage"
- android:label="@string/permgrouplab_storage"
- android:description="@string/permgroupdesc_storage"
- android:priority="900" />
+ android:icon="@drawable/perm_group_storage"
+ android:label="@string/permgrouplab_storage"
+ android:description="@string/permgroupdesc_storage"
+ android:priority="900" />
<!-- Allows an application to read from external storage.
<p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
@@ -646,10 +647,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"
- android:permissionGroup="android.permission-group.STORAGE"
- android:label="@string/permlab_sdcardRead"
- android:description="@string/permdesc_sdcardRead"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardRead"
+ android:description="@string/permdesc_sdcardRead"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -667,10 +668,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
- android:permissionGroup="android.permission-group.STORAGE"
- android:label="@string/permlab_sdcardWrite"
- android:description="@string/permdesc_sdcardWrite"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardWrite"
+ android:description="@string/permdesc_sdcardWrite"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device location -->
@@ -679,28 +680,28 @@
<!-- Used for permissions that allow accessing the device location. -->
<permission-group android:name="android.permission-group.LOCATION"
- android:icon="@drawable/perm_group_location"
- android:label="@string/permgrouplab_location"
- android:description="@string/permgroupdesc_location"
- android:priority="400" />
+ android:icon="@drawable/perm_group_location"
+ android:label="@string/permgrouplab_location"
+ android:description="@string/permgroupdesc_location"
+ android:priority="400" />
<!-- Allows an app to access precise location.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_FINE_LOCATION"
- android:permissionGroup="android.permission-group.LOCATION"
- android:label="@string/permlab_accessFineLocation"
- android:description="@string/permdesc_accessFineLocation"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.LOCATION"
+ android:label="@string/permlab_accessFineLocation"
+ android:description="@string/permdesc_accessFineLocation"
+ android:protectionLevel="dangerous" />
<!-- Allows an app to access approximate location.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_COARSE_LOCATION"
- android:permissionGroup="android.permission-group.LOCATION"
- android:label="@string/permlab_accessCoarseLocation"
- android:description="@string/permdesc_accessCoarseLocation"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.LOCATION"
+ android:label="@string/permlab_accessCoarseLocation"
+ android:description="@string/permdesc_accessCoarseLocation"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device telephony -->
@@ -709,10 +710,10 @@
<!-- Used for permissions that are associated telephony features. -->
<permission-group android:name="android.permission-group.PHONE"
- android:icon="@drawable/perm_group_phone_calls"
- android:label="@string/permgrouplab_phone"
- android:description="@string/permgroupdesc_phone"
- android:priority="500" />
+ android:icon="@drawable/perm_group_phone_calls"
+ android:label="@string/permgrouplab_phone"
+ android:description="@string/permgroupdesc_phone"
+ android:priority="500" />
<!-- Allows read only access to phone state, including the phone number of the device,
current cellular network information, the status of any ongoing calls, and a list of any
@@ -728,21 +729,21 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_PHONE_STATE"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneState"
- android:description="@string/permdesc_readPhoneState"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readPhoneState"
+ android:description="@string/permdesc_readPhoneState"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to initiate a phone call without going through
the Dialer user interface for the user to confirm the call.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.CALL_PHONE"
- android:permissionGroup="android.permission-group.PHONE"
- android:permissionFlags="costsMoney"
- android:label="@string/permlab_callPhone"
- android:description="@string/permdesc_callPhone"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:permissionFlags="costsMoney"
+ android:label="@string/permlab_callPhone"
+ android:description="@string/permdesc_callPhone"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to access the IMS call service: making and
modifying a call
@@ -750,10 +751,10 @@
@hide
-->
<permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_accessImsCallService"
- android:description="@string/permdesc_accessImsCallService"
- android:protectionLevel="signature|privileged" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_accessImsCallService"
+ android:description="@string/permdesc_accessImsCallService"
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to read the user's call log.
<p class="note"><strong>Note:</strong> If your app uses the
@@ -768,10 +769,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readCallLog"
- android:description="@string/permdesc_readCallLog"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readCallLog"
+ android:description="@string/permdesc_readCallLog"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write (but not read) the user's
call log data.
@@ -787,28 +788,28 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_writeCallLog"
- android:description="@string/permdesc_writeCallLog"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_writeCallLog"
+ android:description="@string/permdesc_writeCallLog"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to add voicemails into the system.
<p>Protection level: dangerous
-->
<permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_addVoicemail"
- android:description="@string/permdesc_addVoicemail"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_addVoicemail"
+ android:description="@string/permdesc_addVoicemail"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to use SIP service.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.USE_SIP"
- android:permissionGroup="android.permission-group.PHONE"
- android:description="@string/permdesc_use_sip"
- android:label="@string/permlab_use_sip"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:description="@string/permdesc_use_sip"
+ android:label="@string/permlab_use_sip"
+ android:protectionLevel="dangerous"/>
<!-- Allows an application to see the number being dialed during an outgoing
call with the option to redirect the call to a different number or
@@ -816,10 +817,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_processOutgoingCalls"
- android:description="@string/permdesc_processOutgoingCalls"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_processOutgoingCalls"
+ android:description="@string/permdesc_processOutgoingCalls"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
@@ -830,19 +831,19 @@
microphone audio from the device. Note that phone calls also capture audio
but are in a separate (more visible) permission group. -->
<permission-group android:name="android.permission-group.MICROPHONE"
- android:icon="@drawable/perm_group_microphone"
- android:label="@string/permgrouplab_microphone"
- android:description="@string/permgroupdesc_microphone"
- android:priority="600" />
+ android:icon="@drawable/perm_group_microphone"
+ android:label="@string/permgrouplab_microphone"
+ android:description="@string/permgroupdesc_microphone"
+ android:priority="600" />
<!-- Allows an application to record audio.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECORD_AUDIO"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:label="@string/permlab_recordAudio"
- android:description="@string/permdesc_recordAudio"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:label="@string/permlab_recordAudio"
+ android:description="@string/permdesc_recordAudio"
+ android:protectionLevel="dangerous"/>
<!-- ====================================================================== -->
<!-- Permissions for accessing the UCE Service -->
@@ -852,15 +853,15 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="signatureOrSystem"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signatureOrSystem"/>
<!-- @hide Allows an application to Access UCE-OPTIONS.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="signatureOrSystem"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signatureOrSystem"/>
@@ -872,10 +873,10 @@
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.CAMERA"
- android:icon="@drawable/perm_group_camera"
- android:label="@string/permgrouplab_camera"
- android:description="@string/permgroupdesc_camera"
- android:priority="700" />
+ android:icon="@drawable/perm_group_camera"
+ android:label="@string/permgrouplab_camera"
+ android:description="@string/permgroupdesc_camera"
+ android:priority="700" />
<!-- Required to be able to access the camera device.
<p>This will automatically enforce the <a
@@ -887,10 +888,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.CAMERA"
- android:permissionGroup="android.permission-group.CAMERA"
- android:label="@string/permlab_camera"
- android:description="@string/permdesc_camera"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CAMERA"
+ android:label="@string/permlab_camera"
+ android:description="@string/permdesc_camera"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
@@ -901,28 +902,28 @@
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.SENSORS"
- android:icon="@drawable/perm_group_sensors"
- android:label="@string/permgrouplab_sensors"
- android:description="@string/permgroupdesc_sensors"
- android:priority="800" />
+ android:icon="@drawable/perm_group_sensors"
+ android:label="@string/permgrouplab_sensors"
+ android:description="@string/permgroupdesc_sensors"
+ android:priority="800" />
<!-- Allows an application to access data from sensors that the user uses to
measure what is happening inside his/her body, such as heart rate.
<p>Protection level: dangerous -->
<permission android:name="android.permission.BODY_SENSORS"
- android:permissionGroup="android.permission-group.SENSORS"
- android:label="@string/permlab_bodySensors"
- android:description="@string/permdesc_bodySensors"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_bodySensors"
+ android:description="@string/permdesc_bodySensors"
+ android:protectionLevel="dangerous" />
<!-- Allows an app to use fingerprint hardware.
<p>Protection level: normal
-->
<permission android:name="android.permission.USE_FINGERPRINT"
- android:permissionGroup="android.permission-group.SENSORS"
- android:label="@string/permlab_useFingerprint"
- android:description="@string/permdesc_useFingerprint"
- android:protectionLevel="normal" />
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_useFingerprint"
+ android:description="@string/permdesc_useFingerprint"
+ android:protectionLevel="normal" />
<!-- ====================================================================== -->
<!-- REMOVED PERMISSIONS -->
@@ -930,78 +931,78 @@
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_PROFILE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_PROFILE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_SOCIAL_STREAM"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SOCIAL_STREAM"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_USER_DICTIONARY"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_USER_DICTIONARY"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SMS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.MANAGE_ACCOUNTS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.USE_CREDENTIALS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.FLASHLIGHT"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
@@ -1016,35 +1017,35 @@
to handle the respond-via-message action during incoming calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to filter carrier specific sms.
@hide -->
<permission android:name="android.permission.CARRIER_FILTER_SMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
to record or display them to the user.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
or perform processing on them. -->
<!-- @hide -->
<permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to execute contacts directory search.
This should only be used by ContactsProvider.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to modify cell broadcasts through the content provider.
<p>Not for use by third-party applications. -->
@@ -1060,56 +1061,56 @@
<p>Protection level: normal
-->
<permission android:name="com.android.alarm.permission.SET_ALARM"
- android:label="@string/permlab_setAlarm"
- android:description="@string/permdesc_setAlarm"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setAlarm"
+ android:description="@string/permdesc_setAlarm"
+ android:protectionLevel="normal" />
<!-- =============================================================== -->
<!-- Permissions for accessing the user voicemail -->
<!-- =============================================================== -->
<eat-comment />
- <!-- Allows an application to modify and remove existing voicemails in the system
+ <!-- Allows an application to modify and remove existing voicemails in the system.
<p>Protection level: signature|privileged
-->
<permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to read voicemails in the system.
<p>Protection level: signature|privileged
-->
<permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ======================================= -->
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
<eat-comment />
- <!-- Allows an application to access extra location provider commands
+ <!-- Allows an application to access extra location provider commands.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
- android:label="@string/permlab_accessLocationExtraCommands"
- android:description="@string/permdesc_accessLocationExtraCommands"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_accessLocationExtraCommands"
+ android:description="@string/permdesc_accessLocationExtraCommands"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to install a location provider into the Location Manager.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
This should only be used by HDMI-CEC service.
-->
<permission android:name="android.permission.HDMI_CEC"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use location features in hardware,
such as the geofencing api.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.LOCATION_HARDWARE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
<!-- @SystemApi Allows an application to create mock location providers for testing.
@@ -1117,7 +1118,7 @@
@hide
-->
<permission android:name="android.permission.ACCESS_MOCK_LOCATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ======================================= -->
<!-- Permissions for accessing networks -->
@@ -1128,73 +1129,73 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.INTERNET"
- android:description="@string/permdesc_createNetworkSockets"
- android:label="@string/permlab_createNetworkSockets"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_createNetworkSockets"
+ android:label="@string/permlab_createNetworkSockets"
+ android:protectionLevel="normal" />
- <!-- Allows applications to access information about networks
+ <!-- Allows applications to access information about networks.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_NETWORK_STATE"
- android:description="@string/permdesc_accessNetworkState"
- android:label="@string/permlab_accessNetworkState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessNetworkState"
+ android:label="@string/permlab_accessNetworkState"
+ android:protectionLevel="normal" />
<!-- Allows applications to access information about Wi-Fi networks.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_WIFI_STATE"
- android:description="@string/permdesc_accessWifiState"
- android:label="@string/permlab_accessWifiState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessWifiState"
+ android:label="@string/permlab_accessWifiState"
+ android:protectionLevel="normal" />
<!-- Allows applications to change Wi-Fi connectivity state.
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_WIFI_STATE"
- android:description="@string/permdesc_changeWifiState"
- android:label="@string/permlab_changeWifiState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWifiState"
+ android:label="@string/permlab_changeWifiState"
+ android:protectionLevel="normal" />
<!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_WIFI_CREDENTIAL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows applications to change tether state and run
tether carrier provisioning.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.TETHER_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allow system apps to receive broadcast
when a wifi network credential is changed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
by another application. Once reconfigured the original creator cannot make any further
modifications.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide -->
<permission android:name="android.permission.ACCESS_WIMAX_STATE"
- android:description="@string/permdesc_accessWimaxState"
- android:label="@string/permlab_accessWimaxState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessWimaxState"
+ android:label="@string/permlab_accessWimaxState"
+ android:protectionLevel="normal" />
<!-- @hide -->
<permission android:name="android.permission.CHANGE_WIMAX_STATE"
- android:description="@string/permdesc_changeWimaxState"
- android:label="@string/permlab_changeWimaxState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWimaxState"
+ android:label="@string/permlab_changeWimaxState"
+ android:protectionLevel="normal" />
<!-- Allows applications to act as network scorers. @hide @SystemApi-->
<permission android:name="android.permission.SCORE_NETWORKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
@@ -1205,68 +1206,68 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.BLUETOOTH"
- android:description="@string/permdesc_bluetooth"
- android:label="@string/permlab_bluetooth"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_bluetooth"
+ android:label="@string/permlab_bluetooth"
+ android:protectionLevel="normal" />
<!-- Allows applications to discover and pair bluetooth devices.
<p>Protection level: normal
-->
<permission android:name="android.permission.BLUETOOTH_ADMIN"
- android:description="@string/permdesc_bluetoothAdmin"
- android:label="@string/permlab_bluetoothAdmin"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_bluetoothAdmin"
+ android:label="@string/permlab_bluetoothAdmin"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
allow or disallow phonebook access or message access.
This is not available to third party applications. -->
<permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Control access to email providers exclusively for Bluetooth
@hide
-->
<permission android:name="android.permission.BLUETOOTH_MAP"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows bluetooth stack to access files
@hide This should only be used by Bluetooth apk.
-->
<permission android:name="android.permission.BLUETOOTH_STACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows applications to perform I/O operations over NFC.
<p>Protection level: normal
-->
<permission android:name="android.permission.NFC"
- android:description="@string/permdesc_nfc"
- android:label="@string/permlab_nfc"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_nfc"
+ android:label="@string/permlab_nfc"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows a system application to access hardware packet offload capabilities.
@hide -->
<permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi
@hide -->
<permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
@hide -->
<permission android:name="android.permission.LOOP_RADIO"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
@hide -->
<permission android:name="android.permission.NFC_HANDOVER_STATUS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ================================== -->
<!-- Permissions for accessing accounts -->
@@ -1274,18 +1275,26 @@
<eat-comment />
<!-- Allows access to the list of accounts in the Accounts Service.
- <p>Protection level: normal
+
+ <p class="note"><strong>Note:</strong> Beginning with Android 6.0 (API level
+ 23), if an app shares the signature of the authenticator that manages an
+ account, it does not need <code>"GET_ACCOUNTS"</code> permission to read
+ information about that account. On Android 5.1 and lower, all apps need
+ <code>"GET_ACCOUNTS"</code> permission to read information about any
+ account.</p>
+
+ <p>Protection level: dangerous
-->
<permission android:name="android.permission.GET_ACCOUNTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:protectionLevel="dangerous"
- android:description="@string/permdesc_getAccounts"
- android:label="@string/permlab_getAccounts" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_getAccounts"
+ android:label="@string/permlab_getAccounts" />
<!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for accessing hardware that may effect battery life-->
@@ -1296,34 +1305,34 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
- android:description="@string/permdesc_changeWifiMulticastState"
- android:label="@string/permlab_changeWifiMulticastState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWifiMulticastState"
+ android:label="@string/permlab_changeWifiMulticastState"
+ android:protectionLevel="normal" />
<!-- Allows access to the vibrator.
<p>Protection level: normal
-->
<permission android:name="android.permission.VIBRATE"
- android:label="@string/permlab_vibrate"
- android:description="@string/permdesc_vibrate"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_vibrate"
+ android:description="@string/permdesc_vibrate"
+ android:protectionLevel="normal" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
-->
<permission android:name="android.permission.WAKE_LOCK"
- android:label="@string/permlab_wakeLock"
- android:description="@string/permdesc_wakeLock"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_wakeLock"
+ android:description="@string/permdesc_wakeLock"
+ android:protectionLevel="normal" />
<!-- Allows using the device's IR transmitter, if available.
<p>Protection level: normal
-->
<permission android:name="android.permission.TRANSMIT_IR"
- android:label="@string/permlab_transmitIr"
- android:description="@string/permdesc_transmitIr"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_transmitIr"
+ android:description="@string/permdesc_transmitIr"
+ android:protectionLevel="normal" />
<!-- ==================================================== -->
<!-- Permissions related to changing audio settings -->
@@ -1334,9 +1343,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
- android:label="@string/permlab_modifyAudioSettings"
- android:description="@string/permdesc_modifyAudioSettings"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_modifyAudioSettings"
+ android:description="@string/permdesc_modifyAudioSettings"
+ android:protectionLevel="normal" />
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
@@ -1346,68 +1355,68 @@
<!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
@hide -->
<permission android:name="android.permission.MANAGE_USB"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to access the MTP USB kernel driver.
For use only by the device side MTP implementation.
@hide -->
<permission android:name="android.permission.ACCESS_MTP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows access to hardware peripherals. Intended only for hardware testing.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.HARDWARE_TEST"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows access to FM
@hide This is not a third-party API (intended for system apps).-->
<permission android:name="android.permission.ACCESS_FM_RADIO"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows access to configure network interfaces, configure/use IPSec, etc.
@hide -->
<permission android:name="android.permission.NET_ADMIN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows registration for remote audio playback. @hide -->
<permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
built-in tuners and HDMI-in's.
@hide This should only be used by OEM's TvInputService's.
-->
<permission android:name="android.permission.TV_INPUT_HARDWARE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows to capture a frame of TV input hardware such as
built-in tuners and HDMI-in's.
@hide <p>Not for use by third-party applications.
-->
<permission android:name="android.permission.CAPTURE_TV_INPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows TvInputService to access DVB device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DVB_DEVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows enabling/disabling OEM unlock
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.OEM_UNLOCK_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows querying state of PersistentDataBlock
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_PDB_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows system update service to notify device owner about pending updates.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- =========================================== -->
<!-- Permissions associated with camera and image capture -->
@@ -1418,12 +1427,12 @@
a camera is in use by an application.
@hide -->
<permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows sending the camera service notifications about system-wide events.
@hide -->
<permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
@@ -1434,50 +1443,50 @@
Does not include placing calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MODIFY_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows read only access to precise phone state.
@hide Pending API council approval -->
<permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows read access to privileged phone state.
@hide Used internally. -->
<permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
corresponds to a device SIM.
@hide -->
<permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_CALL_PROVIDER.
@hide -->
<permission android:name="android.permission.REGISTER_CALL_PROVIDER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_CONNECTION_MANAGER
@hide -->
<permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.InCallService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_INCALL_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.CallScreeningService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_SCREENING_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
@@ -1486,24 +1495,24 @@
@SystemApi
@hide -->
<permission android:name="android.permission.BIND_CONNECTION_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to control the in-call experience.
@hide -->
<permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to receive STK related commands.
@hide -->
<permission android:name="android.permission.RECEIVE_STK_COMMANDS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
@@ -1513,7 +1522,7 @@
<!-- @SystemApi Allows an application to write to internal media storage
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to manage access to documents, usually as part
of a document picker.
@@ -1523,14 +1532,14 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.MANAGE_DOCUMENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to cache content.
<p>Not for use by third-party applications.
<p>Protection level: signature
-->
<permission android:name="android.permission.CACHE_CONTENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for screenlock -->
@@ -1541,9 +1550,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.DISABLE_KEYGUARD"
- android:description="@string/permdesc_disableKeyguard"
- android:label="@string/permlab_disableKeyguard"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_disableKeyguard"
+ android:label="@string/permlab_disableKeyguard"
+ android:protectionLevel="normal" />
<!-- ================================== -->
<!-- Permissions to access other installed applications -->
@@ -1552,9 +1561,9 @@
<!-- @deprecated No longer enforced. -->
<permission android:name="android.permission.GET_TASKS"
- android:label="@string/permlab_getTasks"
- android:description="@string/permdesc_getTasks"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_getTasks"
+ android:description="@string/permdesc_getTasks"
+ android:protectionLevel="normal" />
<!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
give access to task information. We need this new one because there are
@@ -1567,113 +1576,124 @@
@hide
@SystemApi -->
<permission android:name="android.permission.REAL_GET_TASKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to start a task from a ActivityManager#RecentTaskInfo.
@hide -->
<permission android:name="android.permission.START_TASKS_FROM_RECENTS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
across the users on the device, using singleton services and
user-targeted broadcasts. This permission is not available to
third party applications. -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
- <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+ <!-- @SystemApi Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
that removes restrictions on where broadcasts can be sent and allows other
- types of interactions. -->
+ types of interactions
+ @hide -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
users on the device. This permission is not available to
third party applications. -->
<permission android:name="android.permission.MANAGE_USERS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
- android:protectionLevel="signature"
- android:label="@string/permlab_manageProfileAndDeviceOwners"
- android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ android:protectionLevel="signature"
+ android:label="@string/permlab_manageProfileAndDeviceOwners"
+ android:description="@string/permdesc_manageProfileAndDeviceOwners" />
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
<permission android:name="android.permission.GET_DETAILED_TASKS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to change the Z-order of tasks.
<p>Protection level: normal
-->
<permission android:name="android.permission.REORDER_TASKS"
- android:label="@string/permlab_reorderTasks"
- android:description="@string/permdesc_reorderTasks"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_reorderTasks"
+ android:description="@string/permdesc_reorderTasks"
+ android:protectionLevel="normal" />
<!-- @hide Allows an application to change to remove/kill tasks -->
<permission android:name="android.permission.REMOVE_TASKS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
<permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to start any activity, regardless of permission
protection or exported state.
@hide -->
<permission android:name="android.permission.START_ANY_ACTIVITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
API is no longer supported. -->
<permission android:name="android.permission.RESTART_PACKAGES"
- android:label="@string/permlab_killBackgroundProcesses"
- android:description="@string/permdesc_killBackgroundProcesses"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
<!-- Allows an application to call
{@link android.app.ActivityManager#killBackgroundProcesses}.
<p>Protection level: normal
-->
<permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
- android:label="@string/permlab_killBackgroundProcesses"
- android:description="@string/permdesc_killBackgroundProcesses"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
<!-- @SystemApi @hide Allows an application to query process states and current
OOM adjustment scores.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi @hide Allows an application to retrieve a package's importance.
This permission is not available to third party applications. -->
<permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows use of PendingIntent.getIntent().
@hide -->
<permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions affecting the display of other applications -->
<!-- ================================== -->
<eat-comment />
- <!-- Allows an application to open windows using the type
+ <!-- Allows an app to create windows using the type
{@link android.view.WindowManager.LayoutParams#TYPE_SYSTEM_ALERT},
- shown on top of all other applications. Very few applications
+ shown on top of all other apps. Very few apps
should use this permission; these windows are intended for
- system-level interaction with the user. -->
+ system-level interaction with the user.
+
+ <p class="note"><strong>Note:</strong> If the app
+ targets API level 23 or higher, the app user must explicitly grant
+ this permission to the app through a permission management screen. The app requests
+ the user's approval by sending an intent with action
+ {@link android.provider.Settings#ACTION_MANAGE_OVERLAY_PERMISSION}.
+ The app can check whether it has this authorization by calling
+ {@link android.provider.Settings#canDrawOverlays
+ Settings.canDrawOverlays()}.
+ <p>Protection level: signature -->
<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
- android:label="@string/permlab_systemAlertWindow"
- android:description="@string/permdesc_systemAlertWindow"
- android:protectionLevel="signature|preinstalled|appop|pre23|development" />
+ android:label="@string/permlab_systemAlertWindow"
+ android:description="@string/permdesc_systemAlertWindow"
+ android:protectionLevel="signature|preinstalled|appop|pre23|development" />
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
@@ -1684,17 +1704,17 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_WALLPAPER"
- android:label="@string/permlab_setWallpaper"
- android:description="@string/permdesc_setWallpaper"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setWallpaper"
+ android:description="@string/permdesc_setWallpaper"
+ android:protectionLevel="normal" />
<!-- Allows applications to set the wallpaper hints.
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_WALLPAPER_HINTS"
- android:label="@string/permlab_setWallpaperHints"
- android:description="@string/permdesc_setWallpaperHints"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setWallpaperHints"
+ android:description="@string/permdesc_setWallpaperHints"
+ android:protectionLevel="normal" />
<!-- ============================================ -->
<!-- Permissions for changing the system clock -->
@@ -1704,15 +1724,15 @@
<!-- @SystemApi Allows applications to set the system time.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to set the system time zone.
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_TIME_ZONE"
- android:label="@string/permlab_setTimeZone"
- android:description="@string/permdesc_setTimeZone"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setTimeZone"
+ android:description="@string/permdesc_setTimeZone"
+ android:protectionLevel="normal" />
<!-- ==================================================== -->
<!-- Permissions related to changing status bar -->
@@ -1723,9 +1743,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.EXPAND_STATUS_BAR"
- android:label="@string/permlab_expandStatusBar"
- android:description="@string/permdesc_expandStatusBar"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_expandStatusBar"
+ android:description="@string/permdesc_expandStatusBar"
+ android:protectionLevel="normal" />
<!-- ============================================================== -->
<!-- Permissions related to adding/removing shortcuts from Launcher -->
@@ -1736,17 +1756,17 @@
<p>Protection level: normal
-->
<permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
- android:label="@string/permlab_install_shortcut"
- android:description="@string/permdesc_install_shortcut"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_install_shortcut"
+ android:description="@string/permdesc_install_shortcut"
+ android:protectionLevel="normal"/>
<!-- Allows an application to uninstall a shortcut in Launcher.
<p>Protection level: normal
-->
<permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
- android:label="@string/permlab_uninstall_shortcut"
- android:description="@string/permdesc_uninstall_shortcut"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_uninstall_shortcut"
+ android:description="@string/permdesc_uninstall_shortcut"
+ android:protectionLevel="normal"/>
<!-- ==================================================== -->
<!-- Permissions related to accessing sync settings -->
@@ -1757,25 +1777,25 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.READ_SYNC_SETTINGS"
- android:description="@string/permdesc_readSyncSettings"
- android:label="@string/permlab_readSyncSettings"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_readSyncSettings"
+ android:label="@string/permlab_readSyncSettings"
+ android:protectionLevel="normal" />
<!-- Allows applications to write the sync settings.
<p>Protection level: normal
-->
<permission android:name="android.permission.WRITE_SYNC_SETTINGS"
- android:description="@string/permdesc_writeSyncSettings"
- android:label="@string/permlab_writeSyncSettings"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_writeSyncSettings"
+ android:label="@string/permlab_writeSyncSettings"
+ android:protectionLevel="normal" />
<!-- Allows applications to read the sync stats.
<p>Protection level: normal
-->
<permission android:name="android.permission.READ_SYNC_STATS"
- android:description="@string/permdesc_readSyncStats"
- android:label="@string/permlab_readSyncStats"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_readSyncStats"
+ android:label="@string/permlab_readSyncStats"
+ android:protectionLevel="normal" />
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->
@@ -1784,62 +1804,71 @@
<!-- @SystemApi @hide Change the screen compatibility mode of applications -->
<permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- Allows an application to read or write the system settings.
- <p>Protection level: signature
+
+ <p class="note"><strong>Note:</strong> If the app targets API level 23
+ or higher, the app user
+ must explicitly grant this permission to the app through a permission management screen.
+ The app requests the user's approval by sending an intent with action
+ {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}. The app
+ can check whether it has this authorization by calling {@link
+ android.provider.Settings.System#canWrite Settings.System.canWrite()}.
+
+ <p>Protection level: signature
-->
<permission android:name="android.permission.WRITE_SETTINGS"
- android:label="@string/permlab_writeSettings"
- android:description="@string/permdesc_writeSettings"
- android:protectionLevel="signature|preinstalled|appop|pre23" />
+ android:label="@string/permlab_writeSettings"
+ android:description="@string/permdesc_writeSettings"
+ android:protectionLevel="signature|preinstalled|appop|pre23" />
<!-- @SystemApi Allows an application to modify the Google service map.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_GSERVICES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
<permission android:name="android.permission.FORCE_STOP_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to retrieve the content of the active window
An active window is the window that has fired an accessibility event. -->
<permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Modify the global animation scaling factor.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ANIMATION_SCALE"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @deprecated This functionality will be removed in the future; please do
not use. Allow an application to make its activities persistent. -->
<permission android:name="android.permission.PERSISTENT_ACTIVITY"
- android:label="@string/permlab_persistentActivity"
- android:description="@string/permdesc_persistentActivity"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_persistentActivity"
+ android:description="@string/permdesc_persistentActivity"
+ android:protectionLevel="normal" />
<!-- Allows an application to find out the space used by any package.
<p>Protection level: normal
-->
<permission android:name="android.permission.GET_PACKAGE_SIZE"
- android:label="@string/permlab_getPackageSize"
- android:description="@string/permdesc_getPackageSize"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_getPackageSize"
+ android:description="@string/permdesc_getPackageSize"
+ android:protectionLevel="normal" />
<!-- @deprecated No longer useful, see
{@link android.content.pm.PackageManager#addPackageToPreferred}
for details. -->
<permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to receive the
{@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -1855,9 +1884,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
- android:label="@string/permlab_receiveBootCompleted"
- android:description="@string/permdesc_receiveBootCompleted"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_receiveBootCompleted"
+ android:description="@string/permdesc_receiveBootCompleted"
+ android:protectionLevel="normal" />
<!-- Allows an application to broadcast sticky intents. These are
broadcasts whose data is held by the system after being finished,
@@ -1866,90 +1895,90 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.BROADCAST_STICKY"
- android:label="@string/permlab_broadcastSticky"
- android:description="@string/permdesc_broadcastSticky"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_broadcastSticky"
+ android:description="@string/permdesc_broadcastSticky"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
<p>Not for use by third-party applications.-->
<permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows formatting file systems for removable storage.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide -->
<permission android:name="android.permission.STORAGE_INTERNAL"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows access to ASEC non-destructive API calls
@hide -->
<permission android:name="android.permission.ASEC_ACCESS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows creation of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_CREATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows destruction of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_DESTROY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows mount / unmount of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows rename of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_RENAME"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to write the apn settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_APN_SETTINGS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to change network connectivity state.
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
- android:description="@string/permdesc_changeNetworkState"
- android:label="@string/permlab_changeNetworkState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeNetworkState"
+ android:label="@string/permlab_changeNetworkState"
+ android:protectionLevel="normal" />
<!-- Allows an application to clear the caches of all installed
applications on the device.
<p>Protection level: system|signature
-->
<permission android:name="android.permission.CLEAR_APP_CACHE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use any media decoder when decoding for playback
@hide -->
<permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
behalf of the user.
@hide -->
<permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to do certain operations needed for
interacting with the recovery (system update) system.
@hide -->
<permission android:name="android.permission.RECOVERY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows the system to bind to an application's task services
@hide -->
<permission android:name="android.permission.BIND_JOB_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
<!-- Allows an application to initiate configuration updates
@@ -1958,7 +1987,7 @@
it off to the various individual installer components
@hide -->
<permission android:name="android.permission.UPDATE_CONFIG"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -1968,40 +1997,40 @@
<!-- @SystemApi Allows an application to read or write the secure system settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_SECURE_SETTINGS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to retrieve state dump information from system services.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DUMP"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->
<permission android:name="android.permission.READ_LOGS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Configure an application for debugging.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_DEBUG_APP"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to set the maximum number of (not needed)
application processes that can be running.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_PROCESS_LIMIT"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to control whether activities are immediately
finished when put in the background.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ALWAYS_FINISH"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- ==================================== -->
<!-- Private permissions -->
@@ -2010,34 +2039,34 @@
<!-- @SystemApi Allows access to the list of accounts in the Accounts Service. -->
<permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
- account -->
- <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ <!-- Allows but does not guarantee access to user passwords at the conclusion of add account
+ @hide -->
+ <permission android:name="android.permission.GET_PASSWORD"
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to open, close, or disable the status bar
and its icons.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.STATUS_BAR"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
@hide -->
<permission android:name="android.permission.STATUS_BAR_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
TileService declarations.-->
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to force a BACK operation on whatever is the
top activity.
@@ -2045,27 +2074,28 @@
@hide
-->
<permission android:name="android.permission.FORCE_BACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to update device statistics.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.UPDATE_DEVICE_STATS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to collect battery statistics -->
<permission android:name="android.permission.GET_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to update application operation statistics. Not for
- use by third party apps. @hide -->
+ use by third party apps.
+ @hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|installer" />
+ android:protectionLevel="signature|privileged|installer" />
- <!-- Allows an application to update the user app op restrictions.
+ <!-- @SystemApi Allows an application to update the user app op restrictions.
Not for use by third party apps.
@hide -->
<permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi Allows an application to open windows that are for use by parts
of the system user interface.
@@ -2073,7 +2103,7 @@
@hide
-->
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to manage (create, destroy,
Z-order) application tokens in the window manager.
@@ -2081,17 +2111,17 @@
@hide
-->
<permission android:name="android.permission.MANAGE_APP_TOKENS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows System UI to register listeners for events from Window Manager.
@hide -->
<permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows the application to temporarily freeze the screen for a
full-screen transition. -->
<permission android:name="android.permission.FREEZE_SCREEN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to inject user events (keys, touch, trackball)
into the event stream and deliver them to ANY window. Without this
@@ -2100,24 +2130,24 @@
@hide
-->
<permission android:name="android.permission.INJECT_EVENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to register an input filter which filters the stream
of user events (keys, touch, trackball) before they are dispatched to any window. -->
<permission android:name="android.permission.FILTER_EVENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
<permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to collect frame statistics -->
<permission android:name="android.permission.FRAME_STATS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to temporary enable accessibility on the device. -->
<permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to watch and control how activities are
started globally in the system. Only for is in debugging
@@ -2126,13 +2156,13 @@
@hide
-->
<permission android:name="android.permission.SET_ACTIVITY_WATCHER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to call the activity manager shutdown() API
to put the higher-level system there into a shutdown state.
@hide -->
<permission android:name="android.permission.SHUTDOWN"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
@@ -2140,7 +2170,7 @@
critical UI such as the home screen.
@hide -->
<permission android:name="android.permission.STOP_APP_SWITCHES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to retrieve private information about
the current top activity, such as any assist context it can provide.
@@ -2148,42 +2178,42 @@
@hide
-->
<permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to retrieve the current state of keys and
switches.
<p>Not for use by third-party applications.
@deprecated The API that used this permission has been removed. -->
<permission android:name="android.permission.READ_INPUT_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_INPUT_METHOD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.media.midi.MidiDeviceService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.printservice.PrintService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_PRINT_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
to ensure that only the system can bind to it.
@@ -2192,7 +2222,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
@@ -2200,84 +2230,107 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_NFC_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
+ that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"
+ android:protectionLevel="signature" />
<!-- Must be required by a TextService (e.g. SpellCheckerService)
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_TEXT_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.net.VpnService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_VPN_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
to ensure that only the system can bind to it.
<p>Protection level: system|signature
-->
<permission android:name="android.permission.BIND_WALLPAPER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_VOICE_INTERACTION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by hotword enrollment application,
to ensure that only the system can interact with it.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_REMOTE_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.media.tv.TvInputService}
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_TV_INPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi
+ Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications. </p>
+ @hide -->
+ <permission android:name="android.permission.BIND_TV_REMOTE_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @SystemApi
+ Must be required for a virtual remote controller for TV.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications. </p>
+ @hide -->
+ <permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to modify parental controls
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
<permission android:name="android.permission.BIND_ROUTE_PROVIDER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by device administration receiver, to ensure that only the
system can interact with it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Required to add or remove another application as a device admin.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows low-level access to setting the orientation (actually
rotation) of the screen.
@@ -2285,33 +2338,33 @@
@hide
-->
<permission android:name="android.permission.SET_ORIENTATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows low-level access to setting the pointer speed.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.SET_POINTER_SPEED"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows low-level access to setting input device calibration.
<p>Not for use by normal applications.
@hide -->
<permission android:name="android.permission.SET_INPUT_CALIBRATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows low-level access to setting the keyboard layout.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to query tablet mode state and monitor changes
in it.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.TABLET_MODE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to request installing packages. Apps
targeting APIs greater than 22 must hold this permission in
@@ -2319,292 +2372,290 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
- android:label="@string/permlab_requestInstallPackages"
- android:description="@string/permdesc_requestInstallPackages"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_requestInstallPackages"
+ android:description="@string/permdesc_requestInstallPackages"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to install packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
-->
<permission android:name="android.permission.CLEAR_APP_USER_DATA"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @hide Allows an application to get the URI permissions
granted to another application.
<p>Not for use by third-party applications
-->
<permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to clear the URI permissions
granted to another application.
<p>Not for use by third-party applications
-->
<permission
- android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
- android:protectionLevel="signature" />
+ android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to delete cache files.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_CACHE_FILES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to delete packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to move location of installed package.
@hide -->
<permission android:name="android.permission.MOVE_PACKAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to change whether an application component (other than its own) is
enabled or not.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- Allows an application to grant specific permissions.
+ <!-- @SystemApi Allows an application to grant specific permissions.
@hide -->
<permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
- <!-- Allows an app that has this permission and the permissions to install packages
+ <!-- @SystemApi Allows an app that has this permission and the permissions to install packages
to request certain runtime permissions to be granted at installation.
- @hide
- @SystemApi -->
+ @hide -->
<permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
- <!-- Allows an application to revoke specific permissions.
- @hide
- @SystemApi -->
+ <!-- @SystemApi Allows an application to revoke specific permissions.
+ @hide -->
<permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
<!-- @hide Allows an application to observe permission changes. -->
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to take screen shots and more generally
get access to the frame buffer data.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to use InputFlinger's low level features.
@hide -->
<permission android:name="android.permission.ACCESS_INPUT_FLINGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to configure and connect to Wifi displays
@hide -->
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control low-level features of Wifi displays
such as opening an RTSP socket. This permission should only be used
by the display manager.
@hide -->
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control the color transforms applied to
displays system-wide.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CONTROL_VPN"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.CONTROL_VPN" />
<!-- @SystemApi Allows an application to capture audio output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture audio for hotword detection.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture secure video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to know what content is playing and control its playback.
<p>Not for use by third-party applications due to privacy of media consumption</p> -->
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Required to be able to disable the device (very dangerous!).
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.BRICK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows low-level access to power management.
- <p>Not for use by third-party applications.
- @hide
- -->
- <permission android:name="android.permission.DEVICE_POWER"
- android:protectionLevel="signature" />
+ <!-- @SystemApi Allows low-level access to power management.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.DEVICE_POWER"
+ android:protectionLevel="signature" />
- <!-- Allows access to the PowerManager.userActivity function.
- <p>Not for use by third-party applications. @hide @SystemApi -->
+ <!-- Allows access to the PowerManager.userActivity function.
+ <p>Not for use by third-party applications. @hide @SystemApi -->
<permission android:name="android.permission.USER_ACTIVITY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- @hide Allows low-level access to tun tap driver -->
+ <!-- @hide Allows low-level access to tun tap driver -->
<permission android:name="android.permission.NET_TUNNELING"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Run as a manufacturer test application, running as the root user.
Only available when the device is running in manufacturer test mode.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.FACTORY_TEST"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast a notification that an application
package has been removed.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast an SMS receipt notification.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_SMS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast a WAP PUSH receipt notification.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_WAP_PUSH"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to broadcast privileged networking requests.
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Not for use by third-party applications. -->
<permission android:name="android.permission.MASTER_CLEAR"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to call any phone number, including emergency
numbers, without going through the Dialer user interface for the user
to confirm the call being placed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CALL_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
<permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to perform SIM Activation @hide -->
<permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows enabling/disabling location update notifications from
the radio.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows read/write access to the "properties" table in the checkin
database, to change values that get uploaded.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to collect component usage
statistics
<p>Declaring the permission implies intention to use the API and the user of the
device can grant permission through the Settings application. -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
- android:protectionLevel="signature|privileged|development|appop" />
+ android:protectionLevel="signature|privileged|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- @hide Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
access the network and acquire wakelocks.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Permission an application must hold in order to use
{@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
This is a normal permission: an app requesting it will always be granted the
permission, without the user needing to approve or see it. -->
<permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
- android:protectionLevel="normal" />
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to collect battery statistics -->
<permission android:name="android.permission.BATTERY_STATS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.BACKUP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows a package to launch the secure full-backup confirmation UI.
ONLY the system process may hold this permission.
@hide -->
<permission android:name="android.permission.CONFIRM_FULL_BACKUP"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_REMOTEVIEWS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
@@ -2613,25 +2664,25 @@
An application that has this permission should honor that contract.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_APPWIDGET"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
keyguard widget
@hide -->
<permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Internal permission allowing an application to query/set which
applications can bind AppWidgets.
@hide -->
<permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to change the background data setting.
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi This permission can be used on content providers to allow the global
search system to access their data. Typically it used when the
@@ -2642,7 +2693,7 @@
it is used by applications to protect themselves from everyone else
besides global search. -->
<permission android:name="android.permission.GLOBAL_SEARCH"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Internal permission protecting access to the global search
system: ensures that only the system can access the provider
@@ -2652,33 +2703,33 @@
ranking).
@hide -->
<permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Internal permission to allows an application to read indexable data.
@hide -->
<permission android:name="android.permission.READ_SEARCH_INDEXABLES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to set a live wallpaper.
@hide XXX Change to signature once the picker is moved to its
own apk as Ghod Intended. -->
<permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to read dream settings and dream state.
@hide -->
<permission android:name="android.permission.READ_DREAM_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
@hide -->
<permission android:name="android.permission.WRITE_DREAM_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by default container service so that only
the system can bind to it and use it to copy
@@ -2686,67 +2737,67 @@
accessible to the system.
@hide -->
<permission android:name="android.permission.COPY_PROTECTED_DATA"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Internal permission protecting access to the encryption methods
@hide
-->
<permission android:name="android.permission.CRYPT_KEEPER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to read historical network usage for
specific networks and applications. @hide -->
<permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to manage network policies (such as warning and disable
limits) and to define application-specific rules. @hide -->
<permission android:name="android.permission.MANAGE_NETWORK_POLICY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
by system services like download manager and media server. Not for use by
third party apps. @hide -->
<permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- C2DM permission.
@hide Used internally.
-->
<permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
<!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
trust it to verify packages.
-->
<permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by package verifier receiver, to ensure that only the
system can interact with it.
@hide
-->
<permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
PackageManager will trust it to verify intent filters.
-->
<permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by intent filter verifier receiver, to ensure that only the
system can interact with it.
@hide
-->
<permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to access serial ports via the SerialManager.
@hide -->
<permission android:name="android.permission.SERIAL_PORT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows the holder to access content providers from outside an ApplicationThread.
This permission is enforced by the ActivityManagerService on the corresponding APIs,
@@ -2755,27 +2806,27 @@
@hide
-->
<permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
OTA reboot *not* occur while the lock is held.
@hide -->
<permission android:name="android.permission.UPDATE_LOCK"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to read the current set of notifications, including
any metadata and intents attached.
@hide -->
<permission android:name="android.permission.ACCESS_NOTIFICATIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Marker permission for applications that wish to access notification policy.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
- android:description="@string/permdesc_access_notification_policy"
- android:label="@string/permlab_access_notification_policy"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_access_notification_policy"
+ android:label="@string/permlab_access_notification_policy"
+ android:protectionLevel="normal" />
<!-- Allows modification of do not disturb rules and policies. Only allowed for system
processes.
@@ -2786,42 +2837,42 @@
<!-- Allows access to keyguard secure storage. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control keyguard. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.CONTROL_KEYGUARD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.TRUST_LISTENER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to provide a trust agent.
@hide For security reasons, this is a platform-only permission. -->
<permission android:name="android.permission.PROVIDE_TRUST_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to launch the trust agent settings activity.
@hide -->
<permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Must be required by an {@link
android.service.trust.TrustAgentService},
to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_TRUST_AGENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link
android.service.notification.NotificationListenerService},
@@ -2829,7 +2880,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link
android.service.notification.NotificationRankerService to ensure that only the system can bind to it.
@@ -2837,7 +2888,7 @@
@hide This is not a third-party API (intended for system apps). -->
-->
<permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link
android.service.chooser.ChooserTargetService}, to ensure that
@@ -2845,7 +2896,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link
android.service.notification.ConditionProviderService},
@@ -2853,57 +2904,57 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.service.dreams.DreamService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_DREAM_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
carrier setup application to enforce that this permission is required
@hide This is not a third-party API (intended for OEMs and system apps). -->
<permission android:name="android.permission.INVOKE_CARRIER_SETUP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to listen for network condition observations.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to provision and access DRM certificates
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Api Allows an application to manage media projection sessions.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to read install sessions
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.READ_INSTALL_SESSIONS"
- android:label="@string/permlab_readInstallSessions"
- android:description="@string/permdesc_readInstallSessions"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_readInstallSessions"
+ android:description="@string/permdesc_readInstallSessions"
+ android:protectionLevel="normal"/>
<!-- @SystemApi Allows an application to remove DRM certificates
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @deprecated Use {@link android.Manifest.permission#BIND_CARRIER_SERVICES} instead -->
<permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to interact with the currently active
{@link android.service.voice.VoiceInteractionService}.
@hide -->
<permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- The system process that is allowed to bind to services in carrier apps will
have this permission. Carrier apps should use this permission to protect
@@ -2911,9 +2962,9 @@
<p>Protection level: system|signature
-->
<permission android:name="android.permission.BIND_CARRIER_SERVICES"
- android:label="@string/permlab_bindCarrierServices"
- android:description="@string/permdesc_bindCarrierServices"
- android:protectionLevel="signature|privileged" />
+ android:label="@string/permlab_bindCarrierServices"
+ android:description="@string/permdesc_bindCarrierServices"
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
flag is set.
@@ -2921,7 +2972,7 @@
<permission android:name="android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT"
android:protectionLevel="signature" />
- <!-- Allows applications to kill UIDs.
+ <!-- @SystemApi Allows applications to kill UIDs.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.KILL_UID"
@@ -2959,7 +3010,7 @@
<!-- Allows the holder to access the ephemeral applications on the device.
@hide -->
<permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows receiving the usage of media resource e.g. video/audio codec and
graphic memory.
@@ -2971,7 +3022,7 @@
APIs given by {@link SoundTriggerManager}.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows trusted applications to dispatch managed provisioning message to Managed
Provisioning app. If requesting app does not have permission, it will be ignored.
@@ -2995,17 +3046,17 @@
the system can bind to it.
<p>Protection level: signature -->
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Required to make calls to {@link android.service.vr.IVrManager}.
@hide -->
<permission android:name="android.permission.ACCESS_VR_MANAGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to whitelist tasks during lock task mode
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
- android:protectionLevel="signature|setup" />
+ android:protectionLevel="signature|setup" />
<!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
in the N-release and later.
@@ -3026,12 +3077,12 @@
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
- android:theme="@style/Theme.DeviceDefault.Resolver"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true"
- android:documentLaunchMode="never"
- android:relinquishTaskIdentity="true"
- android:process=":ui">
+ android:theme="@style/Theme.DeviceDefault.Resolver"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:process=":ui">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3039,102 +3090,102 @@
</intent-filter>
</activity>
<activity android:name="com.android.internal.app.IntentForwarderActivity"
- android:finishOnCloseSystemDialogs="true"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:label="@string/user_owner_label"
- android:exported="true"
- >
+ android:finishOnCloseSystemDialogs="true"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:label="@string/user_owner_label"
+ android:exported="true"
+ >
</activity>
<activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
- android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:exported="true"
- android:label="@string/user_owner_label">
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:exported="true"
+ android:label="@string/user_owner_label">
</activity-alias>
<activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
- android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:icon="@drawable/ic_corp_icon"
- android:exported="true"
- android:label="@string/managed_profile_label">
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:icon="@drawable/ic_corp_icon"
+ android:exported="true"
+ android:label="@string/managed_profile_label">
</activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/heavy_weight_switcher_title"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/heavy_weight_switcher_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
- android:configChanges="orientation|keyboardHidden"
- android:process=":ui">
+ android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DumpHeapActivity"
- android:theme="@style/Theme.Translucent.NoTitleBar"
- android:label="@string/dump_heap_title"
- android:finishOnCloseSystemDialogs="true"
- android:noHistory="true"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:label="@string/dump_heap_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<provider android:name="com.android.server.am.DumpHeapProvider"
- android:authorities="com.android.server.heapdump"
- android:grantUriPermissions="true"
- android:multiprocess="false"
- android:singleUser="true" />
+ android:authorities="com.android.server.heapdump"
+ android:grantUriPermissions="true"
+ android:multiprocess="false"
+ android:singleUser="true" />
<activity android:name="android.accounts.ChooseAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
- android:excludeFromRecents="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.CantAddAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.DialogWhenLarge"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.DialogWhenLarge"
+ android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/sync_too_many_deletes"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/sync_too_many_deletes"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.ShutdownActivity"
- android:permission="android.permission.SHUTDOWN"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true">
+ android:permission="android.permission.SHUTDOWN"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3146,9 +3197,9 @@
</activity>
<activity android:name="com.android.internal.app.NetInitiatedActivity"
- android:theme="@style/Theme.Material.Light.Dialog.Alert"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.SystemUserHomeActivity"
@@ -3165,9 +3216,9 @@
<!-- Activity to prompt user if it's ok to create a new user sandbox for a
specified account. -->
<activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
- android:excludeFromRecents="true"
- android:process=":ui"
- android:theme="@style/Theme.Material.Light.Dialog.Alert">
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert">
<intent-filter android:priority="1000">
<action android:name="android.os.action.CREATE_USER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3175,20 +3226,20 @@
</activity>
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
- android:theme="@style/Theme.Material.Light.Dialog.Alert"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<receiver android:name="com.android.server.BootReceiver"
- android:systemUserOnly="true">
+ android:systemUserOnly="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.CertPinInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_PINS" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3196,7 +3247,7 @@
</receiver>
<receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3204,7 +3255,7 @@
</receiver>
<receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3212,7 +3263,7 @@
</receiver>
<receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_APN_DB" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3220,7 +3271,7 @@
</receiver>
<receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3228,7 +3279,7 @@
</receiver>
<receiver android:name="com.android.server.updates.TzDataInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_TZDATA" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3236,7 +3287,7 @@
</receiver>
<receiver android:name="com.android.server.updates.SELinuxPolicyInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_SEPOLICY" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3244,7 +3295,7 @@
</receiver>
<receiver android:name="com.android.server.MasterClearReceiver"
- android:permission="android.permission.MASTER_CLEAR">
+ android:permission="android.permission.MASTER_CLEAR">
<intent-filter
android:priority="100" >
<!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
@@ -3257,12 +3308,12 @@
</receiver>
<service android:name="android.hardware.location.GeofenceHardwareService"
- android:permission="android.permission.LOCATION_HARDWARE"
- android:exported="false" />
+ android:permission="android.permission.LOCATION_HARDWARE"
+ android:exported="false" />
<service android:name="com.android.internal.backup.LocalTransportService"
- android:permission="android.permission.CONFIRM_FULL_BACKUP"
- android:exported="false">
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
<intent-filter>
<action android:name="android.backup.TRANSPORT_HOST" />
</intent-filter>
@@ -3287,9 +3338,9 @@
</service>
<service
- android:name="com.android.server.pm.BackgroundDexOptService"
- android:exported="true"
- android:permission="android.permission.BIND_JOB_SERVICE">
+ android:name="com.android.server.pm.BackgroundDexOptService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
</service>
</application>
diff --git a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
index dbc8ede..be380c7 100644
--- a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
@@ -259,13 +259,14 @@
#define FIXED_ADDR 0x45678000
#define TIMEOUT 60 /* seconds */
-struct iovec *iovs = NULL;
-int fd[2];
+static struct iovec *iovs = NULL;
+static int fd[2];
+static void *overflow_addr;
void* func_map(void*)
{
- munmap((void*)(FIXED_ADDR), PAGE_SIZE);
- mmap((void*)(FIXED_ADDR), PAGE_SIZE, PROT_READ | PROT_WRITE,
+ munmap(overflow_addr, PAGE_SIZE);
+ overflow_addr = mmap(overflow_addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return NULL;
}
@@ -306,8 +307,10 @@
iovs[OVERFLOW_BUF].iov_base = bufs[OVERFLOW_BUF];
iovs[OVERFLOW_BUF].iov_len = IOV_LEN;
- bufs[OVERFLOW_BUF] = mmap((void*)(FIXED_ADDR), PAGE_SIZE, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ overflow_addr = mmap((void *) FIXED_ADDR, PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ bufs[OVERFLOW_BUF] = overflow_addr;
if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
ALOGE("mmap fixed addr failed:%s", strerror(errno));
goto __close_pipe;
@@ -338,6 +341,12 @@
pthread_join(thr_map, NULL);
pthread_join(thr_readv, NULL);
+ bufs[OVERFLOW_BUF] = overflow_addr;
+ if (bufs[OVERFLOW_BUF] == MAP_FAILED) {
+ ALOGE("mmap fixed addr failed:%s", strerror(errno));
+ goto __free_bufs;
+ }
+
clock_gettime(CLOCK_MONOTONIC, &ts);
if ((ts.tv_sec - time) > TIMEOUT) {
ret = true;
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index db7a974..18dc03d 100755
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -29,6 +29,7 @@
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
+import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
@@ -262,6 +263,9 @@
return;
}
+ assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
+ TextUtils.isEmpty(mDestAddr));
+
String mccmnc = mTelephonyManager.getSimOperator();
mSendIntent = new Intent(SMS_SEND_ACTION);
@@ -291,9 +295,11 @@
// send single text sms
init();
sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent);
- assertTrue(mSendReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue("[RERUN] Could not send SMS. Check signal.",
+ mSendReceiver.waitForCalls(1, TIME_OUT));
if (mDeliveryReportSupported) {
- assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue("[RERUN] SMS message delivery notification not received. Check signal.",
+ mDeliveryReceiver.waitForCalls(1, TIME_OUT));
}
// non-default app should receive only SMS_RECEIVED_ACTION
assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
@@ -314,12 +320,14 @@
init();
sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent);
- assertTrue(mSendReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue("[RERUN] Could not send data SMS. Check signal.",
+ mSendReceiver.waitForCalls(1, TIME_OUT));
if (mDeliveryReportSupported) {
- assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
+ assertTrue("[RERUN] Data SMS message delivery notification not received. " +
+ "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT));
}
mDataSmsReceiver.waitForCalls(1, TIME_OUT);
- assertTrue(mReceivedDataSms);
+ assertTrue("[RERUN] Data SMS message not received. Check signal.", mReceivedDataSms);
assertEquals(mReceivedText, mText);
} else {
// This GSM network doesn't support Data(binary) SMS message.
@@ -338,9 +346,11 @@
deliveryIntents.add(PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent, 0));
}
sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents);
- assertTrue(mSendReceiver.waitForCalls(numParts, TIME_OUT));
+ assertTrue("[RERUN] Could not send multi part SMS. Check signal.",
+ mSendReceiver.waitForCalls(numParts, TIME_OUT));
if (mDeliveryReportSupported) {
- assertTrue(mDeliveryReceiver.waitForCalls(numParts, TIME_OUT));
+ assertTrue("[RERUN] Multi part SMS message delivery notification not received. " +
+ "Check signal.", mDeliveryReceiver.waitForCalls(numParts, TIME_OUT));
}
// non-default app should receive only SMS_RECEIVED_ACTION
assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 366e061..ae9dda1 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -98,9 +98,7 @@
});
t.start();
synchronized (mLock) {
- while (!mOnCellLocationChangedCalled) {
- mLock.wait();
- }
+ mLock.wait(TOLERANCE);
}
assertTrue(mOnCellLocationChangedCalled);
diff --git a/tests/tests/text/res/layout/keylistener_layout.xml b/tests/tests/text/res/layout/keylistener_layout.xml
index cb8dbad..0ee015d 100644
--- a/tests/tests/text/res/layout/keylistener_layout.xml
+++ b/tests/tests/text/res/layout/keylistener_layout.xml
@@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
-<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+<android.text.method.cts.EditTextNoIme
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keylistener_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 3d5335d..87e1e1a 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -982,7 +982,7 @@
ArrowKeyMovementMethod method = new ArrowKeyMovementMethod();
SpannableString spannable = new SpannableString("Test Content");
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
- TextView view = new TextView(getActivity());
+ TextView view = new TextViewNoIme(getActivity());
assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
assertFalse(method.onKeyUp(null, null, 0, null));
@@ -1393,7 +1393,7 @@
}
private void initTextViewWithNullLayout(CharSequence text) {
- mTextView = new TextView(getActivity());
+ mTextView = new TextViewNoIme(getActivity());
mTextView.setText(text, BufferType.EDITABLE);
assertNull(mTextView.getLayout());
mEditable = (Editable) mTextView.getText();
diff --git a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
index fa2e262..1705326 100644
--- a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
@@ -16,18 +16,14 @@
package android.text.method.cts;
-import android.app.Activity;
import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.text.method.BaseKeyListener;
-import android.text.method.cts.KeyListenerTestCase;
import android.view.KeyEvent;
-import android.widget.EditText;
import android.widget.TextView.BufferType;
/**
- * Test backspace key handling of {@link android.text.method.BaseKeyListner}.
+ * Test backspace key handling of {@link android.text.method.BaseKeyListener}.
*/
public class BackspaceTest extends KeyListenerTestCase {
private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
diff --git a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
index 8fa8780..d913cf9 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -16,16 +16,15 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.os.SystemClock;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.BaseKeyListener;
-import android.text.method.cts.KeyListenerTestCase;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.widget.TextView;
import android.widget.TextView.BufferType;
/**
@@ -34,6 +33,14 @@
public class BaseKeyListenerTest extends KeyListenerTestCase {
private static final CharSequence TEST_STRING = "123456";
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testBackspace() {
testBackspace(0);
}
@@ -129,12 +136,12 @@
// Delete the first character '1'
prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 1);
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
assertEquals("23456", mTextView.getText().toString());
// Delete character '2' and '3'
prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 3);
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
assertEquals("1456", mTextView.getText().toString());
// Delete everything on the line the cursor is on.
@@ -149,7 +156,7 @@
// DEL key does not take effect when TextView does not have BaseKeyListener.
prepTextViewSync(TEST_STRING, null, true, 1, 1);
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
assertEquals(TEST_STRING, mTextView.getText().toString());
}
@@ -499,19 +506,19 @@
// press '0' key.
prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
- sendKeys(KeyEvent.KEYCODE_0);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
assertEquals("123456", mTextView.getText().toString());
// delete character '2'
prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 1, 2);
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
assertEquals("13456", mTextView.getText().toString());
// test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), "abcd",
KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 2, 2);
- mInstrumentation.sendKeySync(event);
+ mKeyEventUtil.sendKey(mTextView, event);
mInstrumentation.waitForIdleSync();
// the text of TextView is never changed, onKeyOther never works.
// assertEquals("13abcd456", mTextView.getText().toString());
@@ -558,12 +565,14 @@
* Sends alt-delete key combo via {@link #sendKeys(int... keys)}.
*/
private void sendAltDelete() {
- mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ALT_LEFT));
- mInstrumentation.sendKeySync(new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ mKeyEventUtil.sendKey(mTextView, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_ALT_LEFT));
+ mKeyEventUtil.sendKey(mTextView, new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_DEL, 0, KeyEvent.META_ALT_ON));
- mInstrumentation.sendKeySync(new KeyEvent(0, 0, KeyEvent.ACTION_UP,
+ mKeyEventUtil.sendKey(mTextView, new KeyEvent(0, 0, KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_DEL, 0, KeyEvent.META_ALT_ON));
- mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ALT_LEFT));
+ mKeyEventUtil.sendKey(mTextView, new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_ALT_LEFT));
}
/**
diff --git a/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
index 6ab79ad..b348c28 100644
--- a/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
+++ b/tests/tests/text/src/android/text/method/cts/CharacterPickerDialogTest.java
@@ -18,17 +18,13 @@
import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.text.Editable;
import android.text.Selection;
import android.text.method.CharacterPickerDialog;
import android.view.View;
-import android.widget.AdapterView;
import android.widget.Gallery;
-import android.widget.TextView;
public class CharacterPickerDialogTest extends
ActivityInstrumentationTestCase2<CtsActivity> {
@@ -48,7 +44,7 @@
public void testConstructor() {
final CharSequence str = "123456";
final Editable content = Editable.Factory.getInstance().newEditable(str);
- final View view = new TextView(mActivity);
+ final View view = new TextViewNoIme(mActivity);
new CharacterPickerDialog(view.getContext(), view, content, "\u00A1", false);
try {
@@ -68,7 +64,7 @@
final Gallery parent = new Gallery(mActivity);
final CharSequence str = "123456";
Editable text = Editable.Factory.getInstance().newEditable(str);
- final View view = new TextView(mActivity);
+ final View view = new TextViewNoIme(mActivity);
CharacterPickerDialog replacePickerDialog =
new CharacterPickerDialog(view.getContext(), view, text, "abc", false);
@@ -109,7 +105,7 @@
public void testOnClick() {
final CharSequence str = "123456";
final Editable content = Editable.Factory.getInstance().newEditable(str);
- final View view = new TextView(mActivity);
+ final View view = new TextViewNoIme(mActivity);
CharacterPickerDialog characterPickerDialog =
new CharacterPickerDialog(view.getContext(), view, content, "\u00A1", false);
diff --git a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
index 067a62e..7642d91 100644
--- a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
@@ -16,16 +16,24 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.text.InputType;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.DateKeyListener;
import android.view.KeyEvent;
-import android.widget.TextView;
/**
* Test {@link android.text.method.DateKeyListener}.
*/
public class DateKeyListenerTest extends KeyListenerTestCase {
+
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testConstructor() {
new DateKeyListener();
}
@@ -69,26 +77,26 @@
assertEquals("", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("1", mTextView.getText().toString());
// press '2' key.
- sendKeys(KeyEvent.KEYCODE_2);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
assertEquals("12", mTextView.getText().toString());
// press an unaccepted key if it exists.
int keyCode = TextMethodUtils.getUnacceptedKeyCode(DateKeyListener.CHARACTERS);
if (-1 != keyCode) {
- sendKeys(keyCode);
+ mKeyEventUtil.sendKeys(mTextView, keyCode);
assertEquals("12", mTextView.getText().toString());
}
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("12-", mTextView.getText().toString());
// press '/' key.
- sendKeys(KeyEvent.KEYCODE_SLASH);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_SLASH);
assertEquals("12-/", mTextView.getText().toString());
// remove DateKeyListener
@@ -96,7 +104,7 @@
assertEquals("12-/", mTextView.getText().toString());
// press '/' key, it will not be accepted.
- sendKeys(KeyEvent.KEYCODE_SLASH);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_SLASH);
assertEquals("12-/", mTextView.getText().toString());
}
diff --git a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
index 03683dc..9dfc38a 100644
--- a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
@@ -16,16 +16,25 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.text.InputType;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.DateTimeKeyListener;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
/**
- * Test {@link android.DateTimeKeyListener}.
+ * Test {@link android.text.method.DateTimeKeyListener}.
*/
public class DateTimeKeyListenerTest extends KeyListenerTestCase {
+
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testConstructor() {
new DateTimeKeyListener();
}
@@ -71,12 +80,12 @@
assertEquals(expectedText, mTextView.getText().toString());
// press '1' key.
- mInstrumentation.sendStringSync("1");
+ mKeyEventUtil.sendString(mTextView, "1");
expectedText += "1";
assertEquals(expectedText, mTextView.getText().toString());
// press '2' key.
- mInstrumentation.sendStringSync("2");
+ mKeyEventUtil.sendString(mTextView, "2");
expectedText += "2";
assertEquals(expectedText, mTextView.getText().toString());
@@ -84,28 +93,28 @@
KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
if ('a' == kcm.getMatch(KeyEvent.KEYCODE_A, DateTimeKeyListener.CHARACTERS)) {
expectedText += "a";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_A);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_A);
assertEquals(expectedText, mTextView.getText().toString());
}
// press 'p' key if producible
if ('p' == kcm.getMatch(KeyEvent.KEYCODE_P, DateTimeKeyListener.CHARACTERS)) {
expectedText += "p";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_P);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_P);
assertEquals(expectedText, mTextView.getText().toString());
}
// press 'm' key if producible
if ('m' == kcm.getMatch(KeyEvent.KEYCODE_M, DateTimeKeyListener.CHARACTERS)) {
expectedText += "m";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_M);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_M);
assertEquals(expectedText, mTextView.getText().toString());
}
// press an unaccepted key if it exists.
int keyCode = TextMethodUtils.getUnacceptedKeyCode(DateTimeKeyListener.CHARACTERS);
if (-1 != keyCode) {
- sendKeys(keyCode);
+ mKeyEventUtil.sendKeys(mTextView, keyCode);
assertEquals(expectedText, mTextView.getText().toString());
}
@@ -113,7 +122,7 @@
setKeyListenerSync(null);
assertEquals(expectedText, mTextView.getText().toString());
- mInstrumentation.sendStringSync("1");
+ mKeyEventUtil.sendString(mTextView, "1");
assertEquals(expectedText, mTextView.getText().toString());
}
diff --git a/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
index 9456c7e..219869c 100644
--- a/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
@@ -19,7 +19,6 @@
import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableString;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.DialerKeyListener;
import android.view.KeyEvent;
diff --git a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
index 33a23e3..3170482 100644
--- a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
@@ -16,11 +16,11 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.DigitsKeyListener;
import android.view.KeyEvent;
@@ -28,6 +28,15 @@
* Test {@link DigitsKeyListener}.
*/
public class DigitsKeyListenerTest extends KeyListenerTestCase {
+
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testConstructor() {
new DigitsKeyListener();
@@ -394,19 +403,19 @@
assertEquals("", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("1", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("1", mTextView.getText().toString());
// press '2' key.
- sendKeys(KeyEvent.KEYCODE_2);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
assertEquals("12", mTextView.getText().toString());
}
@@ -428,27 +437,27 @@
assertEquals("", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("-", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("-1", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("-1", mTextView.getText().toString());
// press '+' key.
- sendKeys(KeyEvent.KEYCODE_PLUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
assertEquals("-1", mTextView.getText().toString());
// press '2' key.
- sendKeys(KeyEvent.KEYCODE_2);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
assertEquals("-12", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("-12", mTextView.getText().toString());
}
@@ -470,27 +479,27 @@
assertEquals("", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("", mTextView.getText().toString());
// press '+' key.
- sendKeys(KeyEvent.KEYCODE_PLUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
assertEquals("", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("1", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("1.", mTextView.getText().toString());
// press '2' key.
- sendKeys(KeyEvent.KEYCODE_2);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
assertEquals("1.2", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("1.2", mTextView.getText().toString());
}
@@ -514,27 +523,27 @@
assertEquals("", mTextView.getText().toString());
// press '+' key.
- sendKeys(KeyEvent.KEYCODE_PLUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PLUS);
assertEquals("+", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("+1", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("+1.", mTextView.getText().toString());
// press '2' key.
- sendKeys(KeyEvent.KEYCODE_2);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_2);
assertEquals("+1.2", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("+1.2", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("+1.2", mTextView.getText().toString());
}
@@ -555,19 +564,19 @@
assertEquals("", mTextView.getText().toString());
// press '1' key.
- sendKeys(KeyEvent.KEYCODE_1);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_1);
assertEquals("", mTextView.getText().toString());
// press '5' key.
- sendKeys(KeyEvent.KEYCODE_5);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_5);
assertEquals("5", mTextView.getText().toString());
// press '.' key.
- sendKeys(KeyEvent.KEYCODE_PERIOD);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_PERIOD);
assertEquals("5", mTextView.getText().toString());
// press '-' key.
- sendKeys(KeyEvent.KEYCODE_MINUS);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_MINUS);
assertEquals("5", mTextView.getText().toString());
// remove DigitsKeyListener
@@ -581,7 +590,7 @@
assertEquals("5", mTextView.getText().toString());
// press '5' key.
- sendKeys(KeyEvent.KEYCODE_5);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_5);
assertEquals("5", mTextView.getText().toString());
}
diff --git a/tests/tests/text/src/android/text/method/cts/EditTextNoIme.java b/tests/tests/text/src/android/text/method/cts/EditTextNoIme.java
new file mode 100644
index 0000000..cdb7511
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/EditTextNoIme.java
@@ -0,0 +1,51 @@
+/*
+ * 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.text.method.cts;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+/**
+ * An EditText that returns null for onCreateInputConnection.
+ */
+public class EditTextNoIme extends EditText {
+
+ public EditTextNoIme(Context context) {
+ super(context);
+ }
+
+ public EditTextNoIme(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public EditTextNoIme(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public EditTextNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ return null;
+ }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
index 47c2795..40ed593 100644
--- a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
@@ -16,14 +16,10 @@
package android.text.method.cts;
-import android.app.Activity;
import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.text.method.BaseKeyListener;
-import android.text.method.cts.KeyListenerTestCase;
import android.view.KeyEvent;
-import android.widget.EditText;
import android.widget.TextView.BufferType;
/**
diff --git a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
index 520b91f..d8de43d 100644
--- a/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/LinkMovementMethodTest.java
@@ -65,7 +65,7 @@
mMethod = new LinkMovementMethod();
// Set the content view with a text view which contains 3 lines,
- mView = new TextView(getActivity());
+ mView = new TextViewNoIme(getActivity());
mView.setText(CONTENT, BufferType.SPANNABLE);
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
@@ -129,7 +129,7 @@
// null parameters
try {
- method.onTakeFocus(new TextView(getActivity()), null, View.FOCUS_RIGHT);
+ method.onTakeFocus(new TextViewNoIme(getActivity()), null, View.FOCUS_RIGHT);
fail("The method did not throw NullPointerException when param spannable is null.");
} catch (NullPointerException e) {
// expected
@@ -228,7 +228,7 @@
LinkMovementMethod method = new LinkMovementMethod();
// always returns false
assertFalse(method.onKeyUp(null, null, 0, null));
- assertFalse(method.onKeyUp(new TextView(getActivity()), null, 0, null));
+ assertFalse(method.onKeyUp(new TextViewNoIme(getActivity()), null, 0, null));
assertFalse(method.onKeyUp(null, new SpannableString("blahblah"), 0, null));
assertFalse(method.onKeyUp(null, null, KeyEvent.KEYCODE_0,
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0)));
diff --git a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
index fa0db0d..09053f1 100644
--- a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
@@ -16,22 +16,28 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;
-import android.view.View;
-import android.widget.TextView;
import android.widget.TextView.BufferType;
public class NumberKeyListenerTest extends KeyListenerTestCase {
private MockNumberKeyListener mMockNumberKeyListener;
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
/**
* Check point:
* 1. Filter "Android test", return "".
@@ -138,13 +144,13 @@
mInstrumentation.waitForIdleSync();
assertEquals("123456", mTextView.getText().toString());
// press '0' key.
- sendKeys(KeyEvent.KEYCODE_0);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
assertEquals("0123456", mTextView.getText().toString());
// an unaccepted key if it exists.
int keyCode = TextMethodUtils.getUnacceptedKeyCode(MockNumberKeyListener.DIGITS);
if (-1 != keyCode) {
- sendKeys(keyCode);
+ mKeyEventUtil.sendKeys(mTextView, keyCode);
// text of TextView will not be changed.
assertEquals("0123456", mTextView.getText().toString());
}
@@ -157,7 +163,7 @@
});
mInstrumentation.waitForIdleSync();
// press '0' key.
- sendKeys(KeyEvent.KEYCODE_0);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_0);
assertEquals("0123456", mTextView.getText().toString());
}
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index ea679c5..490a062 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -17,6 +17,7 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.cts.util.PollingCheck;
import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
@@ -66,6 +67,8 @@
super("android.text.cts", CtsActivity.class);
}
+ private KeyEventUtil mKeyEventUtil;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -80,7 +83,7 @@
try {
runTestOnUiThread(new Runnable() {
public void run() {
- EditText editText = new EditText(mActivity);
+ EditText editText = new EditTextNoIme(mActivity);
editText.setId(EDIT_TXT_ID);
editText.setTransformationMethod(mMethod);
Button button = new Button(mActivity);
@@ -102,6 +105,8 @@
mEditText = (EditText) getActivity().findViewById(EDIT_TXT_ID);
assertTrue(mEditText.isFocused());
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+
enableAppOps();
savePasswordPref();
switchShowPassword(true);
@@ -157,10 +162,10 @@
KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) {
// "HELLO" in case of 12-key(NUMERIC) keyboard
- sendKeys("6*4 6*3 7*5 DPAD_RIGHT 7*5 7*6 DPAD_RIGHT");
+ mKeyEventUtil.sendKeys(mEditText, "6*4 6*3 7*5 DPAD_RIGHT 7*5 7*6 DPAD_RIGHT");
}
else {
- sendKeys("H E 2*L O");
+ mKeyEventUtil.sendKeys(mEditText, "H E 2*L O");
}
assertTrue(mMethod.hasCalledBeforeTextChanged());
assertTrue(mMethod.hasCalledOnTextChanged());
@@ -221,14 +226,14 @@
// lose focus
mMethod.reset();
assertTrue(mEditText.isFocused());
- sendKeys("DPAD_DOWN");
+ mKeyEventUtil.sendKeys(mEditText, "DPAD_DOWN");
assertFalse(mEditText.isFocused());
assertTrue(mMethod.hasCalledOnFocusChanged());
// gain focus
mMethod.reset();
assertFalse(mEditText.isFocused());
- sendKeys("DPAD_UP");
+ mKeyEventUtil.sendKeys(mEditText, "DPAD_UP");
assertTrue(mEditText.isFocused());
assertTrue(mMethod.hasCalledOnFocusChanged());
}
diff --git a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
index b66e19a..39deda3 100644
--- a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
@@ -20,12 +20,9 @@
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.QwertyKeyListener;
-import android.text.method.TextKeyListener;
import android.text.method.TextKeyListener.Capitalize;
import android.view.KeyEvent;
-import android.widget.TextView;
import android.widget.TextView.BufferType;
public class QwertyKeyListenerTest extends KeyListenerTestCase {
diff --git a/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
index 6b3e149..e0b8011 100644
--- a/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ReplacementTransformationMethodTest.java
@@ -17,10 +17,8 @@
package android.text.method.cts;
-import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase2;
import android.text.method.ReplacementTransformationMethod;
-import android.view.View;
import android.widget.EditText;
/**
@@ -43,7 +41,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mEditText = new EditText(getActivity());
+ mEditText = new EditTextNoIme(getActivity());
}
public void testGetTransformation() {
diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
index 49196bdc..3333a88 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -60,7 +60,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mTextView = new TextView(getActivity());
+ mTextView = new TextViewNoIme(getActivity());
mTextView.setText(THREE_LINES_TEXT, BufferType.EDITABLE);
mSpannable = (Spannable) mTextView.getText();
mScaledTouchSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop();
@@ -649,7 +649,7 @@
ScrollingMovementMethod method = new ScrollingMovementMethod();
SpannableString spannable = new SpannableString("Test Content");
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
- TextView view = new TextView(getActivity());
+ TextView view = new TextViewNoIme(getActivity());
assertFalse(method.onKeyUp(view, spannable, KeyEvent.KEYCODE_0, event));
assertFalse(method.onKeyUp(null, null, 0, null));
diff --git a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
index 1756a0f..2f8789a 100644
--- a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
@@ -19,7 +19,6 @@
import android.test.ActivityInstrumentationTestCase2;
import android.text.method.SingleLineTransformationMethod;
-import android.view.View;
import android.widget.EditText;
/**
@@ -54,7 +53,7 @@
CharSequence result = method.getTransformation("hello\nworld\r", null);
assertEquals("hello world\uFEFF", result.toString());
- EditText editText = new EditText(getActivity());
+ EditText editText = new EditTextNoIme(getActivity());
editText.setText("hello\nworld\r");
// TODO cannot get transformed text from the view
}
diff --git a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
index 3e09a60..19003cf 100644
--- a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
@@ -16,6 +16,7 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.os.SystemClock;
import android.test.UiThreadTest;
import android.text.Editable;
@@ -23,13 +24,10 @@
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.TextKeyListener;
import android.text.method.TextKeyListener.Capitalize;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.View;
-import android.widget.TextView;
import android.widget.TextView.BufferType;
public class TextKeyListenerTest extends KeyListenerTestCase {
@@ -38,6 +36,14 @@
*/
private static final long TIME_OUT = 3000;
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testConstructor() {
new TextKeyListener(Capitalize.NONE, true);
@@ -192,7 +198,7 @@
mInstrumentation.waitForIdleSync();
assertEquals("", mTextView.getText().toString());
- sendKeys(KeyEvent.KEYCODE_4);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_4);
waitForListenerTimeout();
String text = mTextView.getText().toString();
int keyType = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getKeyboardType();
@@ -226,7 +232,7 @@
// test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), text,
1, KeyEvent.FLAG_WOKE_HERE);
- mInstrumentation.sendKeySync(event);
+ mKeyEventUtil.sendKey(mTextView, event);
mInstrumentation.waitForIdleSync();
// the text of TextView is never changed, onKeyOther never works.
// assertEquals(text, mTextView.getText().toString()); issue 1731439
diff --git a/tests/tests/text/src/android/text/method/cts/TextViewNoIme.java b/tests/tests/text/src/android/text/method/cts/TextViewNoIme.java
new file mode 100644
index 0000000..1ff63ef
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/TextViewNoIme.java
@@ -0,0 +1,51 @@
+/*
+ * 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.text.method.cts;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+/**
+ * A TextView that returns null for onCreateInputConnection.
+ */
+public class TextViewNoIme extends TextView {
+
+ public TextViewNoIme(Context context) {
+ super(context);
+ }
+
+ public TextViewNoIme(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public TextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public TextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ return null;
+ }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
index 7d8631b..4f68d54 100644
--- a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
@@ -16,13 +16,22 @@
package android.text.method.cts;
+import android.cts.util.KeyEventUtil;
import android.text.InputType;
-import android.text.method.cts.KeyListenerTestCase;
import android.text.method.TimeKeyListener;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
public class TimeKeyListenerTest extends KeyListenerTestCase {
+
+ private KeyEventUtil mKeyEventUtil;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mKeyEventUtil = new KeyEventUtil(getInstrumentation());
+ }
+
public void testConstructor() {
new TimeKeyListener();
}
@@ -67,12 +76,12 @@
assertEquals(expectedText, mTextView.getText().toString());
// press '1' key.
- mInstrumentation.sendStringSync("1");
+ mKeyEventUtil.sendString(mTextView, "1");
expectedText += "1";
assertEquals(expectedText, mTextView.getText().toString());
// press '2' key.
- mInstrumentation.sendStringSync("2");
+ mKeyEventUtil.sendString(mTextView, "2");
expectedText += "2";
assertEquals("12", mTextView.getText().toString());
@@ -80,35 +89,35 @@
KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
if ('a' == kcm.getMatch(KeyEvent.KEYCODE_A, TimeKeyListener.CHARACTERS)) {
expectedText += "a";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_A);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_A);
assertEquals(expectedText, mTextView.getText().toString());
}
// press 'p' key if producible
if ('p' == kcm.getMatch(KeyEvent.KEYCODE_P, TimeKeyListener.CHARACTERS)) {
expectedText += "p";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_P);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_P);
assertEquals(expectedText, mTextView.getText().toString());
}
// press 'm' key if producible
if ('m' == kcm.getMatch(KeyEvent.KEYCODE_M, TimeKeyListener.CHARACTERS)) {
expectedText += "m";
- mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_M);
+ mKeyEventUtil.sendKeyDownUp(mTextView, KeyEvent.KEYCODE_M);
assertEquals(expectedText, mTextView.getText().toString());
}
// press an unaccepted key if it exists.
int keyCode = TextMethodUtils.getUnacceptedKeyCode(TimeKeyListener.CHARACTERS);
if (-1 != keyCode) {
- sendKeys(keyCode);
+ mKeyEventUtil.sendKeys(mTextView, keyCode);
assertEquals(expectedText, mTextView.getText().toString());
}
setKeyListenerSync(null);
// press '1' key.
- mInstrumentation.sendStringSync("1");
+ mKeyEventUtil.sendString(mTextView, "1");
assertEquals(expectedText, mTextView.getText().toString());
}
diff --git a/tests/tests/text/src/android/text/method/cts/TouchTest.java b/tests/tests/text/src/android/text/method/cts/TouchTest.java
index 3e26084..8204287 100644
--- a/tests/tests/text/src/android/text/method/cts/TouchTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TouchTest.java
@@ -21,7 +21,6 @@
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.text.Layout;
-import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.method.Touch;
@@ -53,7 +52,7 @@
}
public void testScrollTo() throws Throwable {
- final TextView tv = new TextView(mActivity);
+ final TextView tv = new TextViewNoIme(mActivity);
runTestOnUiThread(new Runnable() {
public void run() {
mActivity.setContentView(tv);
@@ -105,7 +104,7 @@
}
public void testOnTouchEvent() throws Throwable {
- final TextView tv = new TextView(mActivity);
+ final TextView tv = new TextViewNoIme(mActivity);
// Create a string that is wider than the screen.
DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
diff --git a/tests/tests/util/src/android/util/cts/LocaleListTest.java b/tests/tests/util/src/android/util/cts/LocaleListTest.java
index e64d955..7693adf 100644
--- a/tests/tests/util/src/android/util/cts/LocaleListTest.java
+++ b/tests/tests/util/src/android/util/cts/LocaleListTest.java
@@ -32,22 +32,6 @@
assertNull(ll.get(1));
assertNull(ll.get(10));
- ll = new LocaleList((Locale) null);
- assertNotNull(ll);
- assertTrue(ll.isEmpty());
- assertEquals(0, ll.size());
- assertNull(ll.get(0));
- assertNull(ll.get(1));
- assertNull(ll.get(10));
-
- ll = new LocaleList((Locale[]) null);
- assertNotNull(ll);
- assertTrue(ll.isEmpty());
- assertEquals(0, ll.size());
- assertNull(ll.get(0));
- assertNull(ll.get(1));
- assertNull(ll.get(10));
-
ll = new LocaleList(new Locale[0]);
assertNotNull(ll);
assertTrue(ll.isEmpty());
@@ -78,6 +62,21 @@
assertNull(ll.get(10));
}
+ public void testNullArgument() {
+ try {
+ LocaleList ll = new LocaleList((Locale) null);
+ fail("Initializing a LocaleList with a null argument should throw.");
+ } catch (Throwable e) {
+ assertEquals(NullPointerException.class, e.getClass());
+ }
+ try {
+ LocaleList ll = new LocaleList((Locale[]) null);
+ fail("Initializing a LocaleList with a null array should throw.");
+ } catch (Throwable e) {
+ assertEquals(NullPointerException.class, e.getClass());
+ }
+ }
+
public void testNullArguments() {
final Locale[] la = {Locale.US, null};
LocaleList ll = null;
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 31126f8..2862de5 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -147,6 +147,14 @@
</intent-filter>
</activity>
+ <activity android:name="android.view.cts.PixelCopyVideoSourceActivity"
+ android:label="PixelCopyVideoSourceActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.view.cts.FocusFinderCtsActivity"
android:label="FocusFinderCtsActivity">
<intent-filter>
diff --git a/tests/tests/view/res/raw/colorgrid_video.mp4 b/tests/tests/view/res/raw/colorgrid_video.mp4
new file mode 100644
index 0000000..1be8bee
--- /dev/null
+++ b/tests/tests/view/res/raw/colorgrid_video.mp4
Binary files differ
diff --git a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
index bc916a7..bff6511 100644
--- a/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/GLSurfaceViewCtsActivity.java
@@ -83,6 +83,17 @@
mGlVersion = 0;
}
+ private static boolean mFixedSizeSet = false;
+ private static int mFixedWidth, mFixedHeight;
+ public static void setFixedSize(int width, int height) {
+ mFixedSizeSet = true;
+ mFixedWidth = width;
+ mFixedHeight = height;
+ }
+ public static void resetFixedSize() {
+ mFixedSizeSet = false;
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -101,6 +112,9 @@
if (mRenderModeSet) {
mView.setRenderMode(mRenderMode);
}
+ if (mFixedSizeSet) {
+ mView.getHolder().setFixedSize(mFixedWidth, mFixedHeight);
+ }
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(mView);
}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTests.java b/tests/tests/view/src/android/view/cts/PixelCopyTests.java
new file mode 100644
index 0000000..1555d00
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTests.java
@@ -0,0 +1,334 @@
+/*
+ * 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.view.cts;
+
+import android.app.Instrumentation;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Log;
+import android.view.PixelCopy;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.PixelCopy.OnPixelCopyFinishedListener;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_SCISSOR_TEST;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glEnable;
+import static android.opengl.GLES20.glScissor;
+
+import static org.junit.Assert.*;
+
+@MediumTest
+public class PixelCopyTests {
+ private static final String TAG = "PixelCopyTests";
+
+ @Rule
+ public ActivityTestRule<GLSurfaceViewCtsActivity> mGLSurfaceViewActivityRule =
+ new ActivityTestRule<>(GLSurfaceViewCtsActivity.class, false, false);
+
+ @Rule
+ public ActivityTestRule<PixelCopyVideoSourceActivity> mVideoSourceActivityRule =
+ new ActivityTestRule<>(PixelCopyVideoSourceActivity.class, false, false);
+
+ private Instrumentation mInstrumentation;
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ assertNotNull(mInstrumentation);
+ }
+
+ @Test
+ public void testErrors() {
+ Bitmap dest = null;
+ SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
+ SurfaceTexture surfaceTexture = null;
+ Surface surface = null;
+
+ try {
+ surfaceTexture = new SurfaceTexture(false);
+ surface = new Surface(surfaceTexture);
+ try {
+ copyHelper.request(surface, dest);
+ fail("Should have generated an IllegalArgumentException, null dest!");
+ } catch (IllegalArgumentException iae) {
+ // success!
+ } catch (Throwable t) {
+ throw new AssertionError("Should have generated an IllegalArgumentException!", t);
+ }
+
+ dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888);
+ int result = copyHelper.request(surface, dest);
+ assertEquals(PixelCopy.ERROR_SOURCE_NO_DATA, result);
+
+ dest.recycle();
+ try {
+ copyHelper.request(surface, dest);
+ fail("Should have generated an IllegalArgumentException!");
+ } catch (IllegalArgumentException iae) {
+ // success!
+ } catch (Throwable t) {
+ throw new AssertionError(
+ "Should have generated an IllegalArgumentException, recycled bitmap!", t);
+ }
+ } finally {
+ try {
+ if (surface != null) surface.release();
+ } catch (Throwable t) {}
+ try {
+ if (surfaceTexture != null) surfaceTexture.release();
+ } catch (Throwable t) {}
+ surface = null;
+ surfaceTexture = null;
+ }
+ }
+
+ @Test
+ public void testGlProducer() {
+ try {
+ CountDownLatch swapFence = new CountDownLatch(2);
+ GLSurfaceViewCtsActivity.setGlVersion(2);
+ GLSurfaceViewCtsActivity.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ GLSurfaceViewCtsActivity.setFixedSize(100, 100);
+ GLSurfaceViewCtsActivity.setRenderer(new QuadColorGLRenderer(
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, swapFence));
+
+ GLSurfaceViewCtsActivity activity =
+ mGLSurfaceViewActivityRule.launchActivity(null);
+
+ while (!swapFence.await(5, TimeUnit.MILLISECONDS)) {
+ activity.getView().requestRender();
+ }
+
+ // Test a fullsize copy
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+ SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
+ int result = copyHelper.request(activity.getView(), bitmap);
+ assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result);
+ // Make sure nothing messed with the bitmap
+ assertEquals(100, bitmap.getWidth());
+ assertEquals(100, bitmap.getHeight());
+ assertEquals(Config.ARGB_8888, bitmap.getConfig());
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+
+ // Test that scaling works
+ // Since we only sample mid-pixel of each qudrant, filtering
+ // quality isn't tested
+ bitmap.reconfigure(20, 20, Config.ARGB_8888);
+ result = copyHelper.request(activity.getView(), bitmap);
+ assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result);
+ // Make sure nothing messed with the bitmap
+ assertEquals(20, bitmap.getWidth());
+ assertEquals(20, bitmap.getHeight());
+ assertEquals(Config.ARGB_8888, bitmap.getConfig());
+ assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+
+ } catch (InterruptedException e) {
+ fail("Interrupted, error=" + e.getMessage());
+ } finally {
+ GLSurfaceViewCtsActivity.resetFixedSize();
+ GLSurfaceViewCtsActivity.resetGlVersion();
+ GLSurfaceViewCtsActivity.resetRenderer();
+ GLSurfaceViewCtsActivity.resetRenderMode();
+ }
+ }
+
+ @Test
+ public void testVideoProducer() throws InterruptedException {
+ PixelCopyVideoSourceActivity activity =
+ mVideoSourceActivityRule.launchActivity(null);
+ if (!activity.canPlayVideo()) {
+ Log.i(TAG, "Skipping testVideoProducer, video codec isn't supported");
+ }
+ // This returns when the video has been prepared and playback has
+ // been started, it doesn't necessarily means a frame has actually been
+ // produced. There sadly isn't a callback for that.
+ // So we'll try for up to 300ms after this event to acquire a frame, otherwise
+ // it's considered a timeout.
+ activity.waitForPlaying();
+ SynchronousPixelCopy copyHelper = new SynchronousPixelCopy();
+ Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+ int copyResult = PixelCopy.ERROR_SOURCE_NO_DATA;
+ for (int i = 0; i < 30; i++) {
+ copyResult = copyHelper.request(activity.getVideoView(), bitmap);
+ if (copyResult != PixelCopy.ERROR_SOURCE_NO_DATA) {
+ break;
+ }
+ Thread.sleep(10);
+ }
+ assertEquals(PixelCopy.SUCCESS, copyResult);
+ // A large threshold is used because decoder accuracy is covered in the
+ // media CTS tests, so we are mainly interested in verifying that rotation
+ // and YUV->RGB conversion were handled properly.
+ assertBitmapQuadColor(bitmap, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30);
+ }
+
+ private static int getPixelFloatPos(Bitmap bitmap, float xpos, float ypos) {
+ return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
+ }
+
+ private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+ int bottomLeft, int bottomRight) {
+ // Just quickly sample 4 pixels in the various regions.
+ assertEquals("Top left", topLeft, getPixelFloatPos(bitmap, .25f, .25f));
+ assertEquals("Top right", topRight, getPixelFloatPos(bitmap, .75f, .25f));
+ assertEquals("Bottom left", bottomLeft, getPixelFloatPos(bitmap, .25f, .75f));
+ assertEquals("Bottom right", bottomRight, getPixelFloatPos(bitmap, .75f, .75f));
+ }
+
+ private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+ int bottomLeft, int bottomRight, int threshold) {
+ // Just quickly sample 4 pixels in the various regions.
+ assertTrue("Top left", pixelsAreSame(topLeft, getPixelFloatPos(bitmap, .25f, .25f), threshold));
+ assertTrue("Top right", pixelsAreSame(topRight, getPixelFloatPos(bitmap, .75f, .25f), threshold));
+ assertTrue("Bottom left", pixelsAreSame(bottomLeft, getPixelFloatPos(bitmap, .25f, .75f), threshold));
+ assertTrue("Bottom right", pixelsAreSame(bottomRight, getPixelFloatPos(bitmap, .75f, .75f), threshold));
+ }
+
+ private boolean pixelsAreSame(int ideal, int given, int threshold) {
+ int error = Math.abs(Color.red(ideal) - Color.red(given));
+ error += Math.abs(Color.green(ideal) - Color.green(given));
+ error += Math.abs(Color.blue(ideal) - Color.blue(given));
+ return (error < threshold);
+ }
+
+ private static class QuadColorGLRenderer implements Renderer {
+
+ private final int mTopLeftColor;
+ private final int mTopRightColor;
+ private final int mBottomLeftColor;
+ private final int mBottomRightColor;
+
+ private final CountDownLatch mFence;
+
+ private int mWidth, mHeight;
+
+ public QuadColorGLRenderer(int topLeft, int topRight,
+ int bottomLeft, int bottomRight, CountDownLatch fence) {
+ mTopLeftColor = topLeft;
+ mTopRightColor = topRight;
+ mBottomLeftColor = bottomLeft;
+ mBottomRightColor = bottomRight;
+ mFence = fence;
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ int cx = mWidth / 2;
+ int cy = mHeight / 2;
+
+ glEnable(GL_SCISSOR_TEST);
+
+ glScissor(0, cy, cx, mHeight - cy);
+ clearColor(mTopLeftColor);
+
+ glScissor(cx, cy, mWidth - cx, mHeight - cy);
+ clearColor(mTopRightColor);
+
+ glScissor(0, 0, cx, cy);
+ clearColor(mBottomLeftColor);
+
+ glScissor(cx, 0, mWidth - cx, cy);
+ clearColor(mBottomRightColor);
+
+ mFence.countDown();
+ }
+
+ private void clearColor(int color) {
+ glClearColor(Color.red(color) / 255.0f,
+ Color.green(color) / 255.0f,
+ Color.blue(color) / 255.0f,
+ Color.alpha(color) / 255.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+ private static class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
+ private static Handler sHandler;
+ static {
+ HandlerThread thread = new HandlerThread("PixelCopyHelper");
+ thread.start();
+ sHandler = new Handler(thread.getLooper());
+ }
+
+ private int mStatus = -1;
+
+ public int request(Surface source, Bitmap dest) {
+ synchronized (this) {
+ PixelCopy.request(source, dest, this, sHandler);
+ return getResultLocked();
+ }
+ }
+
+ public int request(SurfaceView source, Bitmap dest) {
+ synchronized (this) {
+ PixelCopy.request(source, dest, this, sHandler);
+ return getResultLocked();
+ }
+ }
+
+ private int getResultLocked() {
+ try {
+ this.wait(1000);
+ } catch (InterruptedException e) {
+ fail("PixelCopy request didn't complete within 1s");
+ }
+ return mStatus;
+ }
+
+ @Override
+ public void onPixelCopyFinished(int copyResult) {
+ synchronized (this) {
+ mStatus = copyResult;
+ this.notify();
+ }
+ }
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java
new file mode 100644
index 0000000..08e3951
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/PixelCopyVideoSourceActivity.java
@@ -0,0 +1,60 @@
+/*
+ * 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.view.cts;
+
+import android.app.Activity;
+import android.cts.util.MediaUtils;
+import android.net.Uri;
+import android.os.Bundle;
+import android.widget.VideoView;
+
+import java.util.concurrent.CountDownLatch;
+
+public class PixelCopyVideoSourceActivity extends Activity {
+ private VideoView mVideoView;
+ private CountDownLatch mVideoPlayingFence = new CountDownLatch(1);
+ private boolean mCanPlayVideo;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mVideoView = new VideoView(this);
+ mVideoView.setOnPreparedListener(mp -> {
+ mp.setLooping(true);
+ mVideoView.start();
+ mVideoPlayingFence.countDown();
+ });
+ mCanPlayVideo = MediaUtils.hasCodecsForResource(this, R.raw.colorgrid_video);
+ if (mCanPlayVideo) {
+ Uri uri = Uri.parse("android.resource://android.view.cts/" + R.raw.colorgrid_video);
+ mVideoView.setVideoURI(uri);
+ }
+ setContentView(mVideoView);
+ }
+
+ public boolean canPlayVideo() {
+ return mCanPlayVideo;
+ }
+
+ public void waitForPlaying() throws InterruptedException {
+ mVideoPlayingFence.await();
+ }
+
+ public VideoView getVideoView() {
+ return mVideoView;
+ }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
index 1394ccd..b6dc991 100644
--- a/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/GeolocationTest.java
@@ -64,6 +64,7 @@
// url, and different domains.
private static final String URL_1 = "https://www.example.com";
private static final String URL_2 = "https://www.example.org";
+ private static final String URL_INSECURE = "http://www.example.org";
private static final String JS_INTERFACE_NAME = "Android";
private static final int POLLING_TIMEOUT = 60 * 1000;
@@ -536,7 +537,7 @@
originCheck.run();
}
- // Test loading pages and checks rejecting once and recjecting the domain forever
+ // Test loading pages and checks rejecting once and rejecting the domain forever
public void testSimpleGeolocationRequestReject() throws Exception {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
@@ -591,6 +592,26 @@
falseCheck.run();
}
+ // Test deny geolocation on insecure origins
+ public void testGeolocationRequestDeniedOnInsecureOrigin() throws Exception {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ final TestSimpleGeolocationRequestWebChromeClient chromeClientAcceptAlways =
+ new TestSimpleGeolocationRequestWebChromeClient(mOnUiThread, true, true);
+ mOnUiThread.setWebChromeClient(chromeClientAcceptAlways);
+ loadUrlAndUpdateLocation(URL_INSECURE);
+ Callable<Boolean> locationDenied = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return mJavascriptStatusReceiver.mDenied;
+ }
+ };
+ PollingCheck.check("JS got position", POLLING_TIMEOUT, locationDenied);
+ // The geolocation permission prompt should not be called
+ assertFalse(chromeClientAcceptAlways.mReceivedRequest);
+ }
+
// Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
// notify back to Java when a location or error is received.
public final static class JavascriptStatusReceiver {
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 48f2f06..224966d 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -254,7 +254,9 @@
</activity>
<activity android:name="android.widget.cts.TextViewCtsActivity"
- android:label="TextViewCtsActivity">
+ android:label="TextViewCtsActivity"
+ android:screenOrientation="nosensor"
+ android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -286,7 +288,7 @@
</activity>
<activity android:name="android.widget.cts.VideoViewCtsActivity"
- android:configChanges="keyboardHidden|orientation|screenSize">
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:label="VideoViewCtsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -295,7 +297,9 @@
</activity>
<activity android:name="android.widget.cts.AutoCompleteCtsActivity"
- android:label="AutoCompleteCtsActivity">
+ android:label="AutoCompleteCtsActivity"
+ android:screenOrientation="nosensor"
+ android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
diff --git a/tests/tests/widget/res/layout/autocompletetextview_layout.xml b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
index 25a8541..27eccab 100644
--- a/tests/tests/widget/res/layout/autocompletetextview_layout.xml
+++ b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
@@ -24,7 +24,7 @@
android:layout_height="wrap_content"
android:text="@string/notify" />
- <AutoCompleteTextView android:id="@+id/autocompletetv_edit"
+ <android.widget.cts.AutoCompleteTextViewNoIme android:id="@+id/autocompletetv_edit"
android:completionThreshold="1"
android:completionHint="@string/tabs_1"
android:layout_width="match_parent"
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java
new file mode 100644
index 0000000..c4ada69
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewNoIme.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package android.widget.cts;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.AutoCompleteTextView;
+
+/**
+ * An AutoCompleteTextView that returns null for onCreateInputConnection.
+ */
+public class AutoCompleteTextViewNoIme extends AutoCompleteTextView {
+
+ public AutoCompleteTextViewNoIme(Context context) {
+ super(context);
+ }
+
+ public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public AutoCompleteTextViewNoIme(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes, Resources.Theme popupTheme) {
+ super(context, attrs, defStyleAttr, defStyleRes, popupTheme);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ return null;
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index ea0861f..073a90b 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -475,6 +475,8 @@
promptView.getLocationOnScreen(promptViewOnScreenXY);
final ListView listView = mPopupWindow.getListView();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+
final View firstListChild = listView.getChildAt(0);
final int[] firstChildOnScreenXY = new int[2];
firstListChild.getLocationOnScreen(firstChildOnScreenXY);
@@ -498,6 +500,8 @@
promptView.getLocationOnScreen(promptViewOnScreenXY);
final ListView listView = mPopupWindow.getListView();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, listView, null);
+
final View lastListChild = listView.getChildAt(listView.getChildCount() - 1);
final int[] lastChildOnScreenXY = new int[2];
lastListChild.getLocationOnScreen(lastChildOnScreenXY);
@@ -595,6 +599,8 @@
.withDismissListener().withItemSelectedListener();
mPopupWindowBuilder.show();
+ final View root = mPopupWindow.getListView().getRootView();
+
// "Point" our custom extension of EditText to our ListPopupWindow
final MockViewForListPopupWindow anchor =
(MockViewForListPopupWindow) mPopupWindow.getAnchorView();
@@ -617,6 +623,8 @@
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.waitForIdleSync();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
// At this point we expect that item #2 was selected
verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
any(AdapterView.class), any(View.class), eq(2), eq(2L));
@@ -627,6 +635,8 @@
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
mInstrumentation.waitForIdleSync();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
// At this point we expect that item #1 was selected
verify(mPopupWindowBuilder.mOnItemSelectedListener, times(2)).onItemSelected(
any(AdapterView.class), any(View.class), eq(1), eq(1L));
@@ -637,6 +647,8 @@
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
mInstrumentation.waitForIdleSync();
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, root, null);
+
// At this point we expect that item #0 was selected
verify(mPopupWindowBuilder.mOnItemSelectedListener, times(1)).onItemSelected(
any(AdapterView.class), any(View.class), eq(0), eq(0L));
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 40d42a2..effc685 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -23,6 +23,7 @@
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources.NotFoundException;
+import android.cts.util.KeyEventUtil;
import android.cts.util.PollingCheck;
import android.cts.util.WidgetTestUtils;
import android.graphics.Bitmap;
@@ -123,6 +124,7 @@
+ "this text, I would love to see the kind of devices you guys now use!";
private static final long TIMEOUT = 5000;
private CharSequence mTransformedText;
+ private KeyEventUtil mKeyEventUtil;
public TextViewTest() {
super("android.widget.cts", TextViewCtsActivity.class);
@@ -139,6 +141,7 @@
}
}.run();
mInstrumentation = getInstrumentation();
+ mKeyEventUtil = new KeyEventUtil(mInstrumentation);
}
/**
@@ -1400,7 +1403,7 @@
initTextViewForTyping();
// Type some text.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Precondition: The cursor is at the end of the text.
@@ -1432,8 +1435,9 @@
initTextViewForTyping();
// Simulate deleting text and undoing it.
- mInstrumentation.sendStringSync("xyz");
- sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendString(mTextView, "xyz");
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
+ KeyEvent.KEYCODE_DEL);
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Precondition: The text was actually deleted.
@@ -1563,8 +1567,9 @@
initTextViewForTyping();
// Create two undo operations, an insert and a delete.
- mInstrumentation.sendStringSync("xyz");
- sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendString(mTextView, "xyz");
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL,
+ KeyEvent.KEYCODE_DEL);
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Calling setText() clears both undo operations, so undo doesn't happen.
@@ -1585,7 +1590,7 @@
initTextViewForTyping();
// Type some text. This creates an undo entry.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Undo the typing to create a redo entry.
@@ -1604,7 +1609,7 @@
initTextViewForTyping();
// Type some text.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Programmatically append some text.
@@ -1627,7 +1632,7 @@
initTextViewForTyping();
// Type some text.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Directly modify the underlying Editable to insert some text.
@@ -1676,7 +1681,7 @@
mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
// Type some text.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// TextWatcher altered the text.
@@ -1714,7 +1719,7 @@
initTextViewForTyping();
// Type some text.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Pressing Control-Z triggers undo.
@@ -1737,7 +1742,7 @@
initTextViewForTyping();
// Type some text to create an undo operation.
- mInstrumentation.sendStringSync("abc");
+ mKeyEventUtil.sendString(mTextView, "abc");
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Parcel and unparcel the TextView.
@@ -1748,7 +1753,7 @@
mInstrumentation.waitForIdleSync();
// Delete a character to create a new undo operation.
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
mActivity.runOnUiThread(new Runnable() {
public void run() {
assertEquals("ab", mTextView.getText().toString());
@@ -1775,8 +1780,8 @@
initTextViewForTyping();
// Type and delete to create two new undo operations.
- mInstrumentation.sendStringSync("a");
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendString(mTextView, "a");
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Empty the undo stack then parcel and unparcel the TextView. While the undo
@@ -1790,8 +1795,8 @@
mInstrumentation.waitForIdleSync();
// Create two more undo operations.
- mInstrumentation.sendStringSync("b");
- sendKeys(KeyEvent.KEYCODE_DEL);
+ mKeyEventUtil.sendString(mTextView, "b");
+ mKeyEventUtil.sendKeys(mTextView, KeyEvent.KEYCODE_DEL);
mActivity.runOnUiThread(new Runnable() {
public void run() {
// Verify undo still works.
diff --git a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
index 02ac28c..e9ef867 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
@@ -19,6 +19,8 @@
import junit.framework.Assert;
import android.app.Instrumentation;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnDrawListener;
@@ -37,10 +39,11 @@
*
* @param instrumentation the instrumentation used to run the test
* @param view the view whose tree should be drawn before returning
- * @param runner the runnable to run on the main thread
+ * @param runner the runnable to run on the main thread, or {@code null} to
+ * simply force invalidation and a draw pass
*/
- public static void runOnMainAndDrawSync(Instrumentation instrumentation,
- final View view, final Runnable runner) {
+ public static void runOnMainAndDrawSync(@NonNull Instrumentation instrumentation,
+ @NonNull final View view, @Nullable final Runnable runner) {
final CountDownLatch latch = new CountDownLatch(1);
instrumentation.runOnMainSync(() -> {
@@ -54,7 +57,12 @@
};
observer.addOnDrawListener(listener);
- runner.run();
+
+ if (runner != null) {
+ runner.run();
+ } else {
+ view.invalidate();
+ }
});
try {
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 4b43d39..f4c0a5c 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -25,7 +25,8 @@
DEVICE_INFO_ACTIVITIES := \
com.android.compatibility.common.deviceinfo.GlesStubActivity \
- com.android.cts.deviceinfo.CameraDeviceInfo
+ com.android.cts.deviceinfo.CameraDeviceInfo \
+ com.android.cts.deviceinfo.SensorDeviceInfo
LOCAL_PACKAGE_NAME := CtsDeviceInfo
diff --git a/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java
new file mode 100644
index 0000000..1d266f5
--- /dev/null
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/SensorDeviceInfo.java
@@ -0,0 +1,88 @@
+/*
+ * 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 com.android.cts.deviceinfo;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.os.Bundle;
+
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
+import com.android.compatibility.common.util.DeviceInfoStore;
+
+import java.lang.Exception;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Sensor device info collector.
+ */
+public class SensorDeviceInfo extends DeviceInfo {
+
+ private static final String SENSOR = "sensor";
+ private static final String REPORTING_MODE = "reporting_mode";
+ private static final String NAME = "name";
+ private static final String VENDOR = "vendor";
+ private static final String TYPE = "type";
+ private static final String VERSION = "version";
+ private static final String MAXIMUM_RANGE = "maximum_range";
+ private static final String RESOLUTION = "resolution";
+ private static final String POWER = "power";
+ private static final String MIN_DELAY = "min_delay";
+ private static final String FIFO_RESERVED_EVENT_COUNT =
+ "fifo_reserved_event_count";
+ private static final String FIFO_MAX_EVENT_COUNT = "fifo_max_event_count";
+ private static final String STRING_TYPE = "string_type";
+ private static final String ID = "id";
+ private static final String MAX_DELAY = "max_delay";
+ private static final String IS_WAKE_UP_SENSOR = "is_wake_up_sensor";
+ private static final String IS_DYNAMIC_SENSOR = "is_dynamic_sensor";
+ private static final String IS_ADDITONAL_INFO_SUPPORTED =
+ "is_additional_info_supported";
+
+ @Override
+ protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
+ SensorManager sensorManager = (SensorManager)
+ getContext().getSystemService(Context.SENSOR_SERVICE);
+ List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+ store.startArray(SENSOR);
+ for (Sensor sensor : sensors) {
+ store.startGroup();
+ store.addResult(REPORTING_MODE, sensor.getReportingMode());
+ store.addResult(NAME, sensor.getName());
+ store.addResult(VENDOR, sensor.getVendor());
+ store.addResult(TYPE, sensor.getType());
+ store.addResult(VERSION, sensor.getVersion());
+ store.addResult(MAXIMUM_RANGE, sensor.getMaximumRange());
+ store.addResult(RESOLUTION, sensor.getResolution());
+ store.addResult(POWER, sensor.getPower());
+ store.addResult(MIN_DELAY, sensor.getMinDelay());
+ store.addResult(FIFO_RESERVED_EVENT_COUNT,
+ sensor.getFifoReservedEventCount());
+ store.addResult(FIFO_MAX_EVENT_COUNT,
+ sensor.getFifoMaxEventCount());
+ store.addResult(STRING_TYPE, sensor.getStringType());
+ store.addResult(ID, sensor.getId());
+ store.addResult(MAX_DELAY, sensor.getMaxDelay());
+ store.addResult(IS_WAKE_UP_SENSOR, sensor.isWakeUpSensor());
+ store.addResult(IS_DYNAMIC_SENSOR, sensor.isDynamicSensor());
+ store.addResult(IS_ADDITONAL_INFO_SUPPORTED,
+ sensor.isAdditionalInfoSupported());
+ store.endGroup();
+ }
+ store.endArray(); // Sensor
+ }
+}
diff --git a/tests/inputmethod/Android.mk b/tools/testng/Android.mk
similarity index 61%
rename from tests/inputmethod/Android.mk
rename to tools/testng/Android.mk
index 3a90fa9..2abb7f9 100644
--- a/tests/inputmethod/Android.mk
+++ b/tools/testng/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2015 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.
@@ -12,18 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE := cts-testng
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := testng
+LOCAL_DEX_PREOPT := false
+include $(BUILD_JAVA_LIBRARY)
-LOCAL_PACKAGE_NAME := CtsInputMethodTestCases
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-include $(BUILD_CTS_PACKAGE)
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+ $(copy-file-to-target)
diff --git a/tools/testng/OjTests.xml b/tools/testng/OjTests.xml
new file mode 100644
index 0000000..2578fb9
--- /dev/null
+++ b/tools/testng/OjTests.xml
@@ -0,0 +1,450 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TestPackage name="CtsLibcoreOj" appPackageName="android.libcore.oj" version="1.0" testType="testNGDeviceTest" jarPath="CtsLibcoreOj.jar">
+ <TestSuite name="org">
+ <TestSuite name="openjdk">
+ <TestSuite name="tests">
+ <TestSuite name="java">
+ <TestSuite name="util">
+ <TestSuite name="stream">
+ <TestCase name="CollectionAndMapModifyStreamTest">
+ <Test name="testCollectionSizeRemove" />
+ <Test name="testMapEntriesSizeRemove" />
+ <Test name="testMapKeysSizeRemove" />
+ <Test name="testMapValuesSizeRemove" />
+ </TestCase>
+ <TestCase name="ConcatOpTest">
+ <Test name="testDoubleSize" />
+ <Test name="testIntSize" />
+ <Test name="testLongSize" />
+ <Test name="testOps" />
+ <Test name="testSize" />
+ </TestCase>
+ <TestCase name="ConcatTest">
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testDoubleConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testIntConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testLongConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ <Test name="testRefConcat" />
+ </TestCase>
+ <TestCase name="CountLargeTest">
+ <Test name="testDoubleLarge" />
+ <Test name="testIntLarge" />
+ <Test name="testLongLarge" />
+ <Test name="testRefLarge" />
+ </TestCase>
+ <TestCase name="CountTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="DistinctOpTest">
+ <Test name="testDistinctDistinct" />
+ <Test name="testDistinctSorted" />
+ <Test name="testOp" />
+ <Test name="testOpWithNull" />
+ <Test name="testOpWithNullSorted" />
+ <Test name="testSortedDistinct" />
+ <Test name="testStable" />
+ <Test name="testUniqOp" />
+ <Test name="testWithUnorderedInfiniteStream" />
+ </TestCase>
+ <TestCase name="DoublePrimitiveOpsTests">
+ <Test name="testLimit" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="ExplodeOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testFlatMap" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="FilterOpTest">
+ <Test name="testFilter" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="FindAnyOpTest">
+ <Test name="testDoubleStream" />
+ <Test name="testFindAny" />
+ <Test name="testFindAnyParallel" />
+ <Test name="testIntStream" />
+ <Test name="testLongStream" />
+ <Test name="testStream" />
+ </TestCase>
+ <TestCase name="FindFirstOpTest">
+ <Test name="testDoubleStream" />
+ <Test name="testFindFirst" />
+ <Test name="testIntStream" />
+ <Test name="testLongStream" />
+ <Test name="testStream" />
+ </TestCase>
+ <TestCase name="ForEachOpTest">
+ <Test name="testDoubleForEachOrdered" />
+ <Test name="testDoubleOps" />
+ <Test name="testForEach" />
+ <Test name="testForEach" />
+ <Test name="testForEachOrdered" />
+ <Test name="testIntForEach" />
+ <Test name="testIntForEachOrdered" />
+ <Test name="testLongForEachOrdered" />
+ <Test name="testLongOps" />
+ </TestCase>
+ <TestCase name="GroupByOpTest">
+ <Test name="testBypassCollect" />
+ <Test name="testGroupBy" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="InfiniteStreamWithLimitOpTest">
+ <Test name="testDoubleSubsizedWithRange" />
+ <Test name="testDoubleUnorderedFinite" />
+ <Test name="testDoubleUnorderedGenerator" />
+ <Test name="testDoubleUnorderedIteration" />
+ <Test name="testDoubleUnorderedSizedNotSubsizedFinite" />
+ <Test name="testIntSubsizedWithRange" />
+ <Test name="testIntUnorderedFinite" />
+ <Test name="testIntUnorderedGenerator" />
+ <Test name="testIntUnorderedIteration" />
+ <Test name="testIntUnorderedSizedNotSubsizedFinite" />
+ <Test name="testLongSubsizedWithRange" />
+ <Test name="testLongUnorderedFinite" />
+ <Test name="testLongUnorderedGenerator" />
+ <Test name="testLongUnorderedIteration" />
+ <Test name="testLongUnorderedSizedNotSubsizedFinite" />
+ <Test name="testSubsizedWithRange" />
+ <Test name="testUnorderedFinite" />
+ <Test name="testUnorderedGenerator" />
+ <Test name="testUnorderedIteration" />
+ <Test name="testUnorderedSizedNotSubsizedFinite" />
+ </TestCase>
+ <TestCase name="IntPrimitiveOpsTests">
+ <Test name="testBox" />
+ <Test name="testForEach" />
+ <Test name="testLimit" />
+ <Test name="testMap" />
+ <Test name="testParForEach" />
+ <Test name="testParSum" />
+ <Test name="testSequential" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testSum" />
+ <Test name="testTee" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="IntReduceTest">
+ <Test name="testOps" />
+ <Test name="testReduce" />
+ </TestCase>
+ <TestCase name="IntSliceOpTest">
+ <Test name="testLimit" />
+ <Test name="testLimitOps" />
+ <Test name="testLimitParallel" />
+ <Test name="testLimitShortCircuit" />
+ <Test name="testLimitSort" />
+ <Test name="testSkip" />
+ <Test name="testSkipLimit" />
+ <Test name="testSkipLimitOps" />
+ <Test name="testSkipOps" />
+ <Test name="testSkipParallel" />
+ </TestCase>
+ <TestCase name="IntUniqOpTest">
+ <Test name="testOp" />
+ <Test name="testOpSorted" />
+ <Test name="testUniqOp" />
+ </TestCase>
+ <TestCase name="LongPrimitiveOpsTests">
+ <Test name="testBox" />
+ <Test name="testForEach" />
+ <Test name="testLimit" />
+ <Test name="testMap" />
+ <Test name="testParForEach" />
+ <Test name="testParSum" />
+ <Test name="testSequential" />
+ <Test name="testSort" />
+ <Test name="testSortSort" />
+ <Test name="testSum" />
+ <Test name="testTee" />
+ <Test name="testToArray" />
+ <Test name="testUnBox" />
+ </TestCase>
+ <TestCase name="MapOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testEveryMapShape" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testMap" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="MatchOpTest">
+ <Test name="testDoubleInfinite" />
+ <Test name="testDoubleStream" />
+ <Test name="testDoubleStreamMatches" />
+ <Test name="testInfinite" />
+ <Test name="testIntInfinite" />
+ <Test name="testIntStream" />
+ <Test name="testIntStreamMatches" />
+ <Test name="testLongInfinite" />
+ <Test name="testLongStream" />
+ <Test name="testLongStreamMatches" />
+ <Test name="testStream" />
+ <Test name="testStreamMatches" />
+ </TestCase>
+ <TestCase name="MinMaxTest">
+ <Test name="testDoubleMinMax" />
+ <Test name="testDoubleOps" />
+ <Test name="testIntMinMax" />
+ <Test name="testIntOps" />
+ <Test name="testLongMinMax" />
+ <Test name="testLongOps" />
+ <Test name="testMinMax" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="PrimitiveAverageOpTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="PrimitiveSumTest">
+ <Test name="testOps" />
+ <Test name="testOps" />
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="RangeTest">
+ <Test name="tesIntRangeReduce" />
+ <Test name="testInfiniteRangeFindFirst" />
+ <Test name="testIntInfiniteRangeFindFirst" />
+ <Test name="testIntInfiniteRangeLimit" />
+ <Test name="testIntRange" />
+ <Test name="testLongInfiniteRangeFindFirst" />
+ <Test name="testLongInfiniteRangeLimit" />
+ <Test name="testLongLongRange" />
+ <Test name="testLongLongRangeClosed" />
+ <Test name="testLongRange" />
+ <Test name="testLongRangeReduce" />
+ </TestCase>
+ <TestCase name="ReduceByOpTest">
+ <Test name="testOps" />
+ </TestCase>
+ <TestCase name="ReduceTest">
+ <Test name="testOps" />
+ <Test name="testReduce" />
+ </TestCase>
+ <TestCase name="SequentialOpTest">
+ <Test name="testLazy" />
+ <Test name="testMixedSeqPar" />
+ </TestCase>
+ <TestCase name="SliceOpTest">
+ <Test name="testLimit" />
+ <Test name="testLimitOps" />
+ <Test name="testLimitShortCircuit" />
+ <Test name="testLimitSort" />
+ <Test name="testSkip" />
+ <Test name="testSkipLimit" />
+ <Test name="testSkipLimitOps" />
+ <Test name="testSkipLimitOpsWithNonSplittingSpliterator" />
+ <Test name="testSkipOps" />
+ <Test name="testSlice" />
+ </TestCase>
+ <TestCase name="SortedOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testDoubleSequentialShortCircuitTerminal" />
+ <Test name="testDoubleSortSort" />
+ <Test name="testDoubleStreamTooLarge" />
+ <Test name="testIntOps" />
+ <Test name="testIntSequentialShortCircuitTerminal" />
+ <Test name="testIntSortSort" />
+ <Test name="testIntStreamTooLarge" />
+ <Test name="testLongOps" />
+ <Test name="testLongSequentialShortCircuitTerminal" />
+ <Test name="testLongSortSort" />
+ <Test name="testLongStreamTooLarge" />
+ <Test name="testOps" />
+ <Test name="testRefStreamTooLarge" />
+ <Test name="testSequentialShortCircuitTerminal" />
+ <Test name="testSortSort" />
+ <Test name="testSorted" />
+ </TestCase>
+ <TestCase name="SpliteratorTest">
+ <Test name="testDoubleSpliterator" />
+ <Test name="testIntSpliterator" />
+ <Test name="testLongSpliterator" />
+ <Test name="testSpliterator" />
+ </TestCase>
+ <TestCase name="StreamBuilderTest">
+ <Test name="testAfterBuilding" />
+ <Test name="testDoubleAfterBuilding" />
+ <Test name="testDoubleSingleton" />
+ <Test name="testDoubleStreamBuilder" />
+ <Test name="testIntAfterBuilding" />
+ <Test name="testIntSingleton" />
+ <Test name="testIntStreamBuilder" />
+ <Test name="testLongAfterBuilding" />
+ <Test name="testLongSingleton" />
+ <Test name="testLongStreamBuilder" />
+ <Test name="testSingleton" />
+ <Test name="testStreamBuilder" />
+ </TestCase>
+ <TestCase name="StreamCloseTest">
+ <Test name="testCascadedExceptions" />
+ <Test name="testEmptyCloseHandler" />
+ <Test name="testOneCloseHandler" />
+ <Test name="testTwoCloseHandlers" />
+ </TestCase>
+ <TestCase name="StreamLinkTest">
+ <Test name="testDoubleManyStreams" />
+ <Test name="testIntManyStreams" />
+ <Test name="testLongManyStreams" />
+ <Test name="testManyStreams" />
+ </TestCase>
+ <TestCase name="StreamParSeqTest">
+ <Test name="testParSeq" />
+ </TestCase>
+ <TestCase name="StreamSpliteratorTest">
+ <Test name="testDoubleParSpliterators" />
+ <Test name="testDoubleSpliterators" />
+ <Test name="testDoubleSplitting" />
+ <Test name="testDoubleStreamSpliterators" />
+ <Test name="testIntParSpliterators" />
+ <Test name="testIntSpliterators" />
+ <Test name="testIntSplitting" />
+ <Test name="testIntStreamSpliterators" />
+ <Test name="testLongParSpliterators" />
+ <Test name="testLongSpliterators" />
+ <Test name="testLongSplitting" />
+ <Test name="testLongStreamSpliterators" />
+ <Test name="testParSpliterators" />
+ <Test name="testSpliterators" />
+ <Test name="testSplitting" />
+ <Test name="testStreamSpliterators" />
+ </TestCase>
+ <TestCase name="SummaryStatisticsTest">
+ <Test name="testDoubleStatistics" />
+ <Test name="testIntStatistics" />
+ <Test name="testLongStatistics" />
+ </TestCase>
+ <TestCase name="TabulatorsTest">
+ <Test name="testComposeFinisher" />
+ <Test name="testGroupedReduce" />
+ <Test name="testJoin" />
+ <Test name="testReduce" />
+ <Test name="testSimpleGroupBy" />
+ <Test name="testSimplePartition" />
+ <Test name="testSimpleToMap" />
+ <Test name="testTwoLevelGroupBy" />
+ <Test name="testTwoLevelPartition" />
+ </TestCase>
+ <TestCase name="TeeOpTest">
+ <Test name="testDoubleOps" />
+ <Test name="testIntOps" />
+ <Test name="testLongOps" />
+ <Test name="testOps" />
+ <Test name="testTee" />
+ </TestCase>
+ <TestCase name="ToArrayOpTest">
+ <Test name="testAsArrayWithType" />
+ <Test name="testDistinctAndSortedPermutations" />
+ <Test name="testDoubleDistinctAndSortedPermutations" />
+ <Test name="testDoubleOps" />
+ <Test name="testDoubleOpsWithFilter" />
+ <Test name="testDoubleOpsWithFlatMap" />
+ <Test name="testDoubleOpsWithMap" />
+ <Test name="testDoubleOpsWithSorted" />
+ <Test name="testDoubleStatefulOpPermutations" />
+ <Test name="testIntDistinctAndSortedPermutations" />
+ <Test name="testIntOps" />
+ <Test name="testIntOpsWithFilter" />
+ <Test name="testIntOpsWithFlatMap" />
+ <Test name="testIntOpsWithMap" />
+ <Test name="testIntOpsWithSorted" />
+ <Test name="testIntStatefulOpPermutations" />
+ <Test name="testLongDistinctAndSortedPermutations" />
+ <Test name="testLongOps" />
+ <Test name="testLongOpsWithFilter" />
+ <Test name="testLongOpsWithFlatMap" />
+ <Test name="testLongOpsWithMap" />
+ <Test name="testLongOpsWithSorted" />
+ <Test name="testLongStatefulOpPermutations" />
+ <Test name="testOps" />
+ <Test name="testOpsWithFilter" />
+ <Test name="testOpsWithFlatMap" />
+ <Test name="testOpsWithMap" />
+ <Test name="testOpsWithSorted" />
+ <Test name="testStatefulOpPermutations" />
+ <Test name="testToArray" />
+ </TestCase>
+ </TestSuite>
+ <TestCase name="FillableStringTest">
+ <Test name="testStringBuffer" />
+ <Test name="testStringBuilder" />
+ <Test name="testStringJoiner" />
+ </TestCase>
+ <TestCase name="MapTest">
+ <Test name="testForEach" />
+ <Test name="testReplaceAll" />
+ </TestCase>
+ </TestSuite>
+ <TestSuite name="lang">
+ <TestSuite name="invoke">
+ <TestCase name="DeserializeMethodTest">
+ <Test name="testCapturingNonSerLambda" />
+ <Test name="testCapturingNonserIntersectionLambda" />
+ <Test name="testCapturingSerLambda" />
+ <Test name="testEmptyClass" />
+ </TestCase>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+ </TestSuite>
+</TestPackage>
diff --git a/tools/testng/gen-test-list-xml b/tools/testng/gen-test-list-xml
new file mode 100755
index 0000000..e2a5ef8
--- /dev/null
+++ b/tools/testng/gen-test-list-xml
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+# 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.
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+#
+# Usage:
+# -- Update test_list.txt with new tests/methods whenever new code is added.
+# -- Run this script ./gen-test-list-xml
+# -- Save the updated .xml file into the build, so ctsv1 knows how to run our testng tests.
+#
+
+test_list_txt=$DIR/test_list.txt
+[[ -f $test_list_txt ]] || echo "Can't find $test_list_txt" >&2
+
+$DIR/gen-test-list-xml.py --app-package-name android.libcore.oj --cts-name CtsLibcoreOj --jar-path CtsLibcoreOj.jar $DIR/test_list.txt
diff --git a/tools/testng/gen-test-list-xml.py b/tools/testng/gen-test-list-xml.py
new file mode 100755
index 0000000..961410d
--- /dev/null
+++ b/tools/testng/gen-test-list-xml.py
@@ -0,0 +1,248 @@
+#!/usr/bin/python2.7
+
+# 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.
+
+#
+# Generate a CTS test XML file from a text file containing every single class#method per line
+#
+# For example, given an input file:
+#
+# foo.txt:
+# com.android.ClassName#methodNameA
+# com.android.ClassName#methodNameB
+#
+# Will generate the output file:
+#
+# TestPackage.xml:
+# <TestPackage>
+# <TestSuite name="com">
+# <TestSuite name="android">
+# <TestCase name="ClassName">
+# <Test name="methodNameA" />
+# <Test name="methodNameB" />
+# </TestCase>
+# </TestSuite>
+# </TestSuite>
+# </TestPackage>
+#
+
+import argparse
+import sys
+
+INDENTATION_INCREASE=2
+
+class BaseNode(object):
+ def __init__(self, name=None):
+ self._children = []
+ self._name = name
+ self._properties = []
+
+ def _get_children(self):
+ return self._children
+
+ def _set_children(self, value):
+ self._children = value
+
+ children = property(_get_children, _set_children, doc="Get/set list of children BaseNode")
+
+ def append_child(self, child):
+ self._children.append(child)
+
+ def has_children(self):
+ return not not self._children
+
+ def _get_name(self):
+ return self._name
+
+ def _set_name(self, value):
+ self._name = value
+
+ name = property(_get_name, _set_name, doc="Get/set the name property of the current XML node")
+
+ def _get_type_name(self):
+ return type(self).__name__
+
+ type_name = property(_get_type_name, doc="Get the name of the current XML node")
+
+ def _set_properties(self, value):
+ self._properties = value
+
+ def _get_properties(self):
+ return self._properties
+
+ properties = property(_get_properties, _set_properties, doc="Get/set additional XML properties such as appPackageName (as a dict)")
+
+ def write_xml(self, out, indent=0):
+ out.write(' ' * indent)
+ out.write('<' + self.type_name)
+
+ if self.name is not None:
+ out.write(' name="')
+ out.write(self.name)
+ out.write('"')
+
+ if self.properties:
+ for key, value in self.properties.iteritems():
+ out.write(' ' + key + '="' + value + '"')
+
+ if not self.has_children():
+ out.write(' />')
+ out.write('\n')
+ return
+
+ out.write('>\n')
+
+ #TODO: print all the properties
+
+ for child in self.children:
+ child.write_xml(out, indent + INDENTATION_INCREASE)
+
+ out.write(' ' * indent)
+ out.write('</' + self.type_name + '>')
+ out.write('\n')
+
+class _SuiteContainer(BaseNode):
+ def get_or_create_suite(self, package_list):
+ debug_print("get_or_create_suite, package_list = " + str(package_list))
+ debug_print("name = " + self.name)
+ # If we are empty, then we just reached the TestSuite which we actually wanted. Return.
+ if not package_list:
+ return self
+
+ current_package = package_list[0]
+ rest_of_packages = package_list[1:]
+
+ # If a suite already exists for the requested package, then have it look/create recursively.
+ for child in self.children:
+ if child.name == current_package:
+ return child.get_or_create_suite(rest_of_packages)
+
+ # No suite exists yet, create it recursively
+ new_suite = TestSuite(name=current_package)
+ self.append_child(new_suite)
+ return new_suite.get_or_create_suite(rest_of_packages)
+
+class TestPackage(_SuiteContainer):
+ def add_class_and_method(self, fq_class_name, method):
+ debug_print("add_class_and_method, fq_class_name=" + fq_class_name + ", method=" + method)
+ package_list = fq_class_name.split(".")[:-1] # a.b.c -> ['a', 'b']
+ just_class_name = fq_class_name.split(".")[-1] # a.b.c -> 'c'
+
+ test_suite = self.get_or_create_suite(package_list)
+
+ if test_suite == self:
+ raise Exception("The suite cannot be the package")
+
+ return test_suite.add_class_and_method(just_class_name, method)
+
+class TestSuite(_SuiteContainer):
+ def add_class_and_method(self, just_class_name, method_name):
+ test_case = self.get_or_create_test_case(just_class_name)
+ return test_case.add_method(method_name)
+
+ def get_or_create_test_case(self, just_class_name):
+ for child in self.children:
+ if child.name == just_class_name:
+ return child
+
+ new_test_case = TestCase(name=just_class_name)
+ self.append_child(new_test_case)
+ return new_test_case
+
+class TestCase(BaseNode):
+ def add_method(self, method_name):
+ tst = Test(name=method_name)
+ self.append_child(tst)
+ return tst
+
+class Test(BaseNode):
+ def __init__(self, name):
+ super(Test, self).__init__(name)
+ self._children = None
+
+def debug_print(x):
+ #print x
+ pass
+
+def build_xml_test_package(input, name, xml_properties):
+ root = TestPackage(name=name)
+
+ for line in input:
+ class_and_method_name = line.split('#')
+ fq_class_name = class_and_method_name[0].strip()
+ method_name = class_and_method_name[1].strip()
+
+ root.add_class_and_method(fq_class_name, method_name)
+
+ root.properties = xml_properties
+ return root
+
+def write_xml(out, test_package):
+ out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+ test_package.write_xml(out)
+
+def main():
+ parser = argparse.ArgumentParser(description='Process a test methods list file to generate CTS test xml.')
+
+ # Named required
+ parser.add_argument('--cts-name', help="name (e.g. CtsJdwp)", required=True)
+ parser.add_argument('--app-package-name', help="appPackageName (e.g. android.jdwp)", required=True)
+ parser.add_argument('--jar-path', help="jarPath (e.g. CtsJdwp.jar)", required=True)
+
+ # Named optionals
+ parser.add_argument('--test-type', help="testType (default testNGDeviceTest)",
+ default="testNGDeviceTest")
+ parser.add_argument('--runtime-args', help="runtimeArgs (e.g. -XXlib:libart.so)")
+ parser.add_argument('--version', help="version (default 1.0)", default="1.0")
+
+ # Positional optionals
+ parser.add_argument('input-filename', nargs='?',
+ help='name of the cts test file (stdin by default)')
+ parser.add_argument('output-filename', nargs='?',
+ help='name of the cts output file (stdout by default)')
+
+ # Map named arguments into the xml <TestPackage> property key name
+ argv_to_xml = {
+ 'app_package_name' : 'appPackageName',
+ 'jar_path' : 'jarPath',
+ 'test_type' : 'testType',
+ 'runtime_args' : 'runtimeArgs',
+ 'version' : 'version'
+ }
+
+ args = parser.parse_args()
+ argv = vars(args) # convert Namespace to Dict
+
+ xml_properties = {}
+ for key, value in argv_to_xml.iteritems():
+ if argv.get(key):
+ xml_properties[value] = argv[key]
+
+ debug_print(argv['input-filename'])
+ debug_print(argv['output-filename'])
+
+ name_in = argv['input-filename']
+ name_out = argv['output-filename']
+
+ file_in = name_in and open(name_in, "r") or sys.stdin
+ file_out = name_out and open(name_out, "w+") or sys.stdout
+
+ # read all the input
+ test_package = build_xml_test_package(file_in, args.cts_name, xml_properties)
+ # write all the output
+ write_xml(file_out, test_package)
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunListener.java b/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunListener.java
new file mode 100644
index 0000000..2509366
--- /dev/null
+++ b/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunListener.java
@@ -0,0 +1,95 @@
+/*
+ * 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 com.android.cts.testng;
+
+import java.util.Arrays;
+
+public class SingleTestNGTestRunListener implements org.testng.ITestListener {
+ private static class Prefixes {
+ @SuppressWarnings("unused")
+ private static final String INFORMATIONAL_MARKER = "[----------]";
+ private static final String START_TEST_MARKER = "[ RUN ]";
+ private static final String OK_TEST_MARKER = "[ OK ]";
+ private static final String ERROR_TEST_RUN_MARKER = "[ ERROR ]";
+ private static final String SKIPPED_TEST_MARKER = "[ SKIP ]";
+ private static final String TEST_RUN_MARKER = "[==========]";
+ }
+
+ @Override
+ public void onFinish(org.testng.ITestContext context) {
+ System.out.println(String.format("%s", Prefixes.TEST_RUN_MARKER));
+ }
+
+ @Override
+ public void onStart(org.testng.ITestContext context) {
+ System.out.println(String.format("%s", Prefixes.INFORMATIONAL_MARKER));
+ }
+
+ @Override
+ public void onTestFailedButWithinSuccessPercentage(org.testng.ITestResult result) {
+ onTestFailure(result);
+ }
+
+ @Override
+ public void onTestFailure(org.testng.ITestResult result) {
+ // All failures are coalesced into one '[ FAILED ]' message at the end
+ // This is because a single test method can run multiple times with different parameters.
+ // Since we only test a single method, it's safe to combine all failures into one
+ // failure at the end.
+ //
+ // The big pass/fail is printed from SingleTestNGTestRunner, not from the listener.
+ System.out.println(String.format("%s %s ::: %s", Prefixes.ERROR_TEST_RUN_MARKER,
+ getId(result), stringify(result.getThrowable())));
+ }
+
+ @Override
+ public void onTestSkipped(org.testng.ITestResult result) {
+ System.out.println(String.format("%s %s", Prefixes.SKIPPED_TEST_MARKER,
+ getId(result)));
+ }
+
+ @Override
+ public void onTestStart(org.testng.ITestResult result) {
+ System.out.println(String.format("%s %s", Prefixes.START_TEST_MARKER,
+ getId(result)));
+ }
+
+ @Override
+ public void onTestSuccess(org.testng.ITestResult result) {
+ System.out.println(String.format("%s", Prefixes.OK_TEST_MARKER));
+ }
+
+ private String getId(org.testng.ITestResult test) {
+ // TestNG is quite complicated since tests can have arbitrary parameters.
+ // Use its code to stringify a result name instead of doing it ourselves.
+
+ org.testng.remote.strprotocol.TestResultMessage msg =
+ new org.testng.remote.strprotocol.TestResultMessage(
+ null, /*suite name*/
+ null, /*test name -- display the test method name instead */
+ test);
+
+ String className = test.getTestClass().getName();
+ //String name = test.getMethod().getMethodName();
+ return String.format("%s#%s", className, msg.toDisplayString());
+
+ }
+
+ private String stringify(Throwable error) {
+ return Arrays.toString(error.getStackTrace()).replaceAll("\n", " ");
+ }
+}
diff --git a/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunner.java b/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunner.java
new file mode 100644
index 0000000..c9f31af
--- /dev/null
+++ b/tools/testng/src/com/android/cts/testng/SingleTestNGTestRunner.java
@@ -0,0 +1,88 @@
+/*
+ * 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 com.android.cts.testng;
+
+import org.testng.TestNG;
+import org.testng.xml.XmlClass;
+import org.testng.xml.XmlInclude;
+import org.testng.xml.XmlSuite;
+import org.testng.xml.XmlTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test runner to run a single TestNG test. It will output either [PASSED] or [FAILED] at the end.
+ */
+public class SingleTestNGTestRunner {
+ private static String mUsage = "Usage: java -cp <classpath> SingleTestNGTestRunner" +
+ " class#testMethod";
+ private static final String PASSED_TEST_MARKER = "[ PASSED ]";
+ private static final String FAILED_TEST_MARKER = "[ FAILED ]";
+
+ public static void main(String... args) {
+ if (args.length != 1) {
+ throw new IllegalArgumentException(mUsage);
+ }
+ String[] classAndMethod = args[0].split("#");
+ if (classAndMethod.length != 2) {
+ throw new IllegalArgumentException(mUsage);
+ }
+
+ TestNG testng = createTestNG(classAndMethod[0], classAndMethod[1]);
+ testng.run();
+ String status = (!testng.hasFailure()) ? PASSED_TEST_MARKER : FAILED_TEST_MARKER;
+ System.out.println(String.format("%s %s.%s", status,
+ classAndMethod[0], classAndMethod[1]));
+ }
+
+ private static org.testng.TestNG createTestNG(String klass, String method) {
+ org.testng.TestNG testng = new org.testng.TestNG();
+ testng.setUseDefaultListeners(false); // Don't create the testng-specific HTML/XML reports.
+ testng.addListener(new SingleTestNGTestRunListener());
+
+ /* Construct the following equivalent XML configuration:
+ *
+ * <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
+ * <suite>
+ * <test>
+ * <classes>
+ * <class name="$klass">
+ * <include name="$method" />
+ * </class>
+ * </classes>
+ * </test>
+ * </suite>
+ *
+ * This will ensure that only a single klass/method is being run by testng.
+ * (It can still be run multiple times due to @DataProvider, with different parameters
+ * each time)
+ */
+ List<XmlSuite> suites = new ArrayList<>();
+ XmlSuite the_suite = new XmlSuite();
+ XmlTest the_test = new XmlTest(the_suite);
+ XmlClass the_class = new XmlClass(klass);
+ XmlInclude the_include = new XmlInclude(method);
+
+ the_class.getIncludedMethods().add(the_include);
+ the_test.getXmlClasses().add(the_class);
+ suites.add(the_suite);
+ testng.setXmlSuites(suites);
+
+ return testng;
+ }
+}
diff --git a/tools/testng/test-script b/tools/testng/test-script
new file mode 100755
index 0000000..9bfdf82
--- /dev/null
+++ b/tools/testng/test-script
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+adb push $ANDROID_PRODUCT_OUT/system/framework/cts-testng.jar /data/local/tmp
+adb shell "cd /data/local/tmp && dalvikvm -cp cts-testng.jar:ctslibcore/CtsLibcoreOjTestCases.apk com.android.cts.testng.SingleTestNGTestRunner org.openjdk.tests.java.util.stream.GroupByOpTest#testOps"
diff --git a/tools/testng/test_list.txt b/tools/testng/test_list.txt
new file mode 100644
index 0000000..5516c0d
--- /dev/null
+++ b/tools/testng/test_list.txt
@@ -0,0 +1,345 @@
+org.openjdk.tests.java.util.stream.CollectionAndMapModifyStreamTest#testCollectionSizeRemove
+org.openjdk.tests.java.util.stream.CollectionAndMapModifyStreamTest#testMapEntriesSizeRemove
+org.openjdk.tests.java.util.stream.CollectionAndMapModifyStreamTest#testMapKeysSizeRemove
+org.openjdk.tests.java.util.stream.CollectionAndMapModifyStreamTest#testMapValuesSizeRemove
+org.openjdk.tests.java.util.stream.ConcatOpTest#testDoubleSize
+org.openjdk.tests.java.util.stream.ConcatOpTest#testIntSize
+org.openjdk.tests.java.util.stream.ConcatOpTest#testLongSize
+org.openjdk.tests.java.util.stream.ConcatOpTest#testOps
+org.openjdk.tests.java.util.stream.ConcatOpTest#testSize
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testDoubleConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testIntConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testLongConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.ConcatTest#testRefConcat
+org.openjdk.tests.java.util.stream.CountLargeTest#testDoubleLarge
+org.openjdk.tests.java.util.stream.CountLargeTest#testIntLarge
+org.openjdk.tests.java.util.stream.CountLargeTest#testLongLarge
+org.openjdk.tests.java.util.stream.CountLargeTest#testRefLarge
+org.openjdk.tests.java.util.stream.CountTest#testOps
+org.openjdk.tests.java.util.stream.CountTest#testOps
+org.openjdk.tests.java.util.stream.CountTest#testOps
+org.openjdk.tests.java.util.stream.CountTest#testOps
+org.openjdk.tests.java.lang.invoke.DeserializeMethodTest#testCapturingNonSerLambda
+org.openjdk.tests.java.lang.invoke.DeserializeMethodTest#testCapturingNonserIntersectionLambda
+org.openjdk.tests.java.lang.invoke.DeserializeMethodTest#testCapturingSerLambda
+org.openjdk.tests.java.lang.invoke.DeserializeMethodTest#testEmptyClass
+org.openjdk.tests.java.util.stream.DistinctOpTest#testDistinctDistinct
+org.openjdk.tests.java.util.stream.DistinctOpTest#testDistinctSorted
+org.openjdk.tests.java.util.stream.DistinctOpTest#testOp
+org.openjdk.tests.java.util.stream.DistinctOpTest#testOpWithNull
+org.openjdk.tests.java.util.stream.DistinctOpTest#testOpWithNullSorted
+org.openjdk.tests.java.util.stream.DistinctOpTest#testSortedDistinct
+org.openjdk.tests.java.util.stream.DistinctOpTest#testStable
+org.openjdk.tests.java.util.stream.DistinctOpTest#testUniqOp
+org.openjdk.tests.java.util.stream.DistinctOpTest#testWithUnorderedInfiniteStream
+org.openjdk.tests.java.util.stream.DoublePrimitiveOpsTests#testLimit
+org.openjdk.tests.java.util.stream.DoublePrimitiveOpsTests#testSort
+org.openjdk.tests.java.util.stream.DoublePrimitiveOpsTests#testSortSort
+org.openjdk.tests.java.util.stream.DoublePrimitiveOpsTests#testToArray
+org.openjdk.tests.java.util.stream.DoublePrimitiveOpsTests#testUnBox
+org.openjdk.tests.java.util.stream.ExplodeOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.ExplodeOpTest#testFlatMap
+org.openjdk.tests.java.util.stream.ExplodeOpTest#testIntOps
+org.openjdk.tests.java.util.stream.ExplodeOpTest#testLongOps
+org.openjdk.tests.java.util.stream.ExplodeOpTest#testOps
+org.openjdk.tests.java.util.FillableStringTest#testStringBuffer
+org.openjdk.tests.java.util.FillableStringTest#testStringBuilder
+org.openjdk.tests.java.util.FillableStringTest#testStringJoiner
+org.openjdk.tests.java.util.stream.FilterOpTest#testFilter
+org.openjdk.tests.java.util.stream.FilterOpTest#testOps
+org.openjdk.tests.java.util.stream.FilterOpTest#testOps
+org.openjdk.tests.java.util.stream.FilterOpTest#testOps
+org.openjdk.tests.java.util.stream.FilterOpTest#testOps
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testDoubleStream
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testFindAny
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testFindAnyParallel
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testIntStream
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testLongStream
+org.openjdk.tests.java.util.stream.FindAnyOpTest#testStream
+org.openjdk.tests.java.util.stream.FindFirstOpTest#testDoubleStream
+org.openjdk.tests.java.util.stream.FindFirstOpTest#testFindFirst
+org.openjdk.tests.java.util.stream.FindFirstOpTest#testIntStream
+org.openjdk.tests.java.util.stream.FindFirstOpTest#testLongStream
+org.openjdk.tests.java.util.stream.FindFirstOpTest#testStream
+org.openjdk.tests.java.util.stream.ForEachOpTest#testDoubleForEachOrdered
+org.openjdk.tests.java.util.stream.ForEachOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.ForEachOpTest#testForEach
+org.openjdk.tests.java.util.stream.ForEachOpTest#testForEach
+org.openjdk.tests.java.util.stream.ForEachOpTest#testForEachOrdered
+org.openjdk.tests.java.util.stream.ForEachOpTest#testIntForEach
+org.openjdk.tests.java.util.stream.ForEachOpTest#testIntForEachOrdered
+org.openjdk.tests.java.util.stream.ForEachOpTest#testLongForEachOrdered
+org.openjdk.tests.java.util.stream.ForEachOpTest#testLongOps
+org.openjdk.tests.java.util.stream.GroupByOpTest#testBypassCollect
+org.openjdk.tests.java.util.stream.GroupByOpTest#testGroupBy
+org.openjdk.tests.java.util.stream.GroupByOpTest#testOps
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testDoubleSubsizedWithRange
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testDoubleUnorderedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testDoubleUnorderedGenerator
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testDoubleUnorderedIteration
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testDoubleUnorderedSizedNotSubsizedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testIntSubsizedWithRange
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testIntUnorderedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testIntUnorderedGenerator
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testIntUnorderedIteration
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testIntUnorderedSizedNotSubsizedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testLongSubsizedWithRange
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testLongUnorderedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testLongUnorderedGenerator
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testLongUnorderedIteration
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testLongUnorderedSizedNotSubsizedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testSubsizedWithRange
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testUnorderedFinite
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testUnorderedGenerator
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testUnorderedIteration
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest#testUnorderedSizedNotSubsizedFinite
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testBox
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testForEach
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testLimit
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testMap
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testParForEach
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testParSum
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testSequential
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testSort
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testSortSort
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testSum
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testTee
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testToArray
+org.openjdk.tests.java.util.stream.IntPrimitiveOpsTests#testUnBox
+org.openjdk.tests.java.util.stream.IntReduceTest#testOps
+org.openjdk.tests.java.util.stream.IntReduceTest#testReduce
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testLimit
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testLimitOps
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testLimitParallel
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testLimitShortCircuit
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testLimitSort
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testSkip
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testSkipLimit
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testSkipLimitOps
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testSkipOps
+org.openjdk.tests.java.util.stream.IntSliceOpTest#testSkipParallel
+org.openjdk.tests.java.util.stream.IntUniqOpTest#testOp
+org.openjdk.tests.java.util.stream.IntUniqOpTest#testOpSorted
+org.openjdk.tests.java.util.stream.IntUniqOpTest#testUniqOp
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testBox
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testForEach
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testLimit
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testMap
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testParForEach
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testParSum
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testSequential
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testSort
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testSortSort
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testSum
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testTee
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testToArray
+org.openjdk.tests.java.util.stream.LongPrimitiveOpsTests#testUnBox
+org.openjdk.tests.java.util.stream.MapOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.MapOpTest#testEveryMapShape
+org.openjdk.tests.java.util.stream.MapOpTest#testIntOps
+org.openjdk.tests.java.util.stream.MapOpTest#testLongOps
+org.openjdk.tests.java.util.stream.MapOpTest#testMap
+org.openjdk.tests.java.util.stream.MapOpTest#testOps
+org.openjdk.tests.java.util.MapTest#testForEach
+org.openjdk.tests.java.util.MapTest#testReplaceAll
+org.openjdk.tests.java.util.stream.MatchOpTest#testDoubleInfinite
+org.openjdk.tests.java.util.stream.MatchOpTest#testDoubleStream
+org.openjdk.tests.java.util.stream.MatchOpTest#testDoubleStreamMatches
+org.openjdk.tests.java.util.stream.MatchOpTest#testInfinite
+org.openjdk.tests.java.util.stream.MatchOpTest#testIntInfinite
+org.openjdk.tests.java.util.stream.MatchOpTest#testIntStream
+org.openjdk.tests.java.util.stream.MatchOpTest#testIntStreamMatches
+org.openjdk.tests.java.util.stream.MatchOpTest#testLongInfinite
+org.openjdk.tests.java.util.stream.MatchOpTest#testLongStream
+org.openjdk.tests.java.util.stream.MatchOpTest#testLongStreamMatches
+org.openjdk.tests.java.util.stream.MatchOpTest#testStream
+org.openjdk.tests.java.util.stream.MatchOpTest#testStreamMatches
+org.openjdk.tests.java.util.stream.MinMaxTest#testDoubleMinMax
+org.openjdk.tests.java.util.stream.MinMaxTest#testDoubleOps
+org.openjdk.tests.java.util.stream.MinMaxTest#testIntMinMax
+org.openjdk.tests.java.util.stream.MinMaxTest#testIntOps
+org.openjdk.tests.java.util.stream.MinMaxTest#testLongMinMax
+org.openjdk.tests.java.util.stream.MinMaxTest#testLongOps
+org.openjdk.tests.java.util.stream.MinMaxTest#testMinMax
+org.openjdk.tests.java.util.stream.MinMaxTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveAverageOpTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveAverageOpTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveAverageOpTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveSumTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveSumTest#testOps
+org.openjdk.tests.java.util.stream.PrimitiveSumTest#testOps
+org.openjdk.tests.java.util.stream.RangeTest#tesIntRangeReduce
+org.openjdk.tests.java.util.stream.RangeTest#testInfiniteRangeFindFirst
+org.openjdk.tests.java.util.stream.RangeTest#testIntInfiniteRangeFindFirst
+org.openjdk.tests.java.util.stream.RangeTest#testIntInfiniteRangeLimit
+org.openjdk.tests.java.util.stream.RangeTest#testIntRange
+org.openjdk.tests.java.util.stream.RangeTest#testLongInfiniteRangeFindFirst
+org.openjdk.tests.java.util.stream.RangeTest#testLongInfiniteRangeLimit
+org.openjdk.tests.java.util.stream.RangeTest#testLongLongRange
+org.openjdk.tests.java.util.stream.RangeTest#testLongLongRangeClosed
+org.openjdk.tests.java.util.stream.RangeTest#testLongRange
+org.openjdk.tests.java.util.stream.RangeTest#testLongRangeReduce
+org.openjdk.tests.java.util.stream.ReduceByOpTest#testOps
+org.openjdk.tests.java.util.stream.ReduceTest#testOps
+org.openjdk.tests.java.util.stream.ReduceTest#testReduce
+org.openjdk.tests.java.util.stream.SequentialOpTest#testLazy
+org.openjdk.tests.java.util.stream.SequentialOpTest#testMixedSeqPar
+org.openjdk.tests.java.util.stream.SliceOpTest#testLimit
+org.openjdk.tests.java.util.stream.SliceOpTest#testLimitOps
+org.openjdk.tests.java.util.stream.SliceOpTest#testLimitShortCircuit
+org.openjdk.tests.java.util.stream.SliceOpTest#testLimitSort
+org.openjdk.tests.java.util.stream.SliceOpTest#testSkip
+org.openjdk.tests.java.util.stream.SliceOpTest#testSkipLimit
+org.openjdk.tests.java.util.stream.SliceOpTest#testSkipLimitOps
+org.openjdk.tests.java.util.stream.SliceOpTest#testSkipLimitOpsWithNonSplittingSpliterator
+org.openjdk.tests.java.util.stream.SliceOpTest#testSkipOps
+org.openjdk.tests.java.util.stream.SliceOpTest#testSlice
+org.openjdk.tests.java.util.stream.SortedOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.SortedOpTest#testDoubleSequentialShortCircuitTerminal
+org.openjdk.tests.java.util.stream.SortedOpTest#testDoubleSortSort
+org.openjdk.tests.java.util.stream.SortedOpTest#testDoubleStreamTooLarge
+org.openjdk.tests.java.util.stream.SortedOpTest#testIntOps
+org.openjdk.tests.java.util.stream.SortedOpTest#testIntSequentialShortCircuitTerminal
+org.openjdk.tests.java.util.stream.SortedOpTest#testIntSortSort
+org.openjdk.tests.java.util.stream.SortedOpTest#testIntStreamTooLarge
+org.openjdk.tests.java.util.stream.SortedOpTest#testLongOps
+org.openjdk.tests.java.util.stream.SortedOpTest#testLongSequentialShortCircuitTerminal
+org.openjdk.tests.java.util.stream.SortedOpTest#testLongSortSort
+org.openjdk.tests.java.util.stream.SortedOpTest#testLongStreamTooLarge
+org.openjdk.tests.java.util.stream.SortedOpTest#testOps
+org.openjdk.tests.java.util.stream.SortedOpTest#testRefStreamTooLarge
+org.openjdk.tests.java.util.stream.SortedOpTest#testSequentialShortCircuitTerminal
+org.openjdk.tests.java.util.stream.SortedOpTest#testSortSort
+org.openjdk.tests.java.util.stream.SortedOpTest#testSorted
+org.openjdk.tests.java.util.stream.SpliteratorTest#testDoubleSpliterator
+org.openjdk.tests.java.util.stream.SpliteratorTest#testIntSpliterator
+org.openjdk.tests.java.util.stream.SpliteratorTest#testLongSpliterator
+org.openjdk.tests.java.util.stream.SpliteratorTest#testSpliterator
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testAfterBuilding
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testDoubleAfterBuilding
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testDoubleSingleton
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testDoubleStreamBuilder
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testIntAfterBuilding
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testIntSingleton
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testIntStreamBuilder
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testLongAfterBuilding
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testLongSingleton
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testLongStreamBuilder
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testSingleton
+org.openjdk.tests.java.util.stream.StreamBuilderTest#testStreamBuilder
+org.openjdk.tests.java.util.stream.StreamCloseTest#testCascadedExceptions
+org.openjdk.tests.java.util.stream.StreamCloseTest#testEmptyCloseHandler
+org.openjdk.tests.java.util.stream.StreamCloseTest#testOneCloseHandler
+org.openjdk.tests.java.util.stream.StreamCloseTest#testTwoCloseHandlers
+org.openjdk.tests.java.util.stream.StreamLinkTest#testDoubleManyStreams
+org.openjdk.tests.java.util.stream.StreamLinkTest#testIntManyStreams
+org.openjdk.tests.java.util.stream.StreamLinkTest#testLongManyStreams
+org.openjdk.tests.java.util.stream.StreamLinkTest#testManyStreams
+org.openjdk.tests.java.util.stream.StreamParSeqTest#testParSeq
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testDoubleParSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testDoubleSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testDoubleSplitting
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testDoubleStreamSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testIntParSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testIntSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testIntSplitting
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testIntStreamSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testLongParSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testLongSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testLongSplitting
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testLongStreamSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testParSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testSpliterators
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testSplitting
+org.openjdk.tests.java.util.stream.StreamSpliteratorTest#testStreamSpliterators
+org.openjdk.tests.java.util.stream.SummaryStatisticsTest#testDoubleStatistics
+org.openjdk.tests.java.util.stream.SummaryStatisticsTest#testIntStatistics
+org.openjdk.tests.java.util.stream.SummaryStatisticsTest#testLongStatistics
+org.openjdk.tests.java.util.stream.TabulatorsTest#testComposeFinisher
+org.openjdk.tests.java.util.stream.TabulatorsTest#testGroupedReduce
+org.openjdk.tests.java.util.stream.TabulatorsTest#testJoin
+org.openjdk.tests.java.util.stream.TabulatorsTest#testReduce
+org.openjdk.tests.java.util.stream.TabulatorsTest#testSimpleGroupBy
+org.openjdk.tests.java.util.stream.TabulatorsTest#testSimplePartition
+org.openjdk.tests.java.util.stream.TabulatorsTest#testSimpleToMap
+org.openjdk.tests.java.util.stream.TabulatorsTest#testTwoLevelGroupBy
+org.openjdk.tests.java.util.stream.TabulatorsTest#testTwoLevelPartition
+org.openjdk.tests.java.util.stream.TeeOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.TeeOpTest#testIntOps
+org.openjdk.tests.java.util.stream.TeeOpTest#testLongOps
+org.openjdk.tests.java.util.stream.TeeOpTest#testOps
+org.openjdk.tests.java.util.stream.TeeOpTest#testTee
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testAsArrayWithType
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDistinctAndSortedPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleDistinctAndSortedPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleOps
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleOpsWithFilter
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleOpsWithFlatMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleOpsWithMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleOpsWithSorted
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testDoubleStatefulOpPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntDistinctAndSortedPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntOps
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntOpsWithFilter
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntOpsWithFlatMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntOpsWithMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntOpsWithSorted
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testIntStatefulOpPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongDistinctAndSortedPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongOps
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongOpsWithFilter
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongOpsWithFlatMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongOpsWithMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongOpsWithSorted
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testLongStatefulOpPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testOps
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testOpsWithFilter
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testOpsWithFlatMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testOpsWithMap
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testOpsWithSorted
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testStatefulOpPermutations
+org.openjdk.tests.java.util.stream.ToArrayOpTest#testToArray
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestNGDeviceTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestNGDeviceTest.java
new file mode 100644
index 0000000..377c0c0
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestNGDeviceTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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 com.android.cts.tradefed.testtype;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.AbiFormatter;
+import com.android.tradefed.util.ArrayUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Test} for running CTS TestNG tests on the device.
+ */
+public class TestNGDeviceTest implements IDeviceTest, IRemoteTest, IBuildReceiver {
+
+ private static final String TMP_DIR = "/data/local/tmp/";
+
+ @Option(name = "testng-device-runtime",
+ description = "The name of the runtime to use on the device",
+ importance = Importance.ALWAYS)
+ private String mRuntimePath = "dalvikvm|#ABI#|";
+
+ @Option(name = "testng-device-tmpdir", description = "Device path where to store the test jars."
+ , importance = Importance.IF_UNSET)
+ private String mDeviceTestTmpPath = TMP_DIR;
+
+
+ // default to no timeout
+ private long mMaxTimeToOutputResponse = 0;
+
+ private ITestDevice mDevice;
+ private String mRunName;
+ private Collection<TestIdentifier> mTests;
+ private CtsBuildHelper mCtsBuild = null;
+
+ private List<String> mJarPaths = new ArrayList<String>();
+
+ private String mRuntimeArgs;
+
+ private IAbi mAbi;
+
+ private static final String TESTNG_JAR = "cts-testng.jar";
+
+ private Set<String> mTestJars = new HashSet<String>(Arrays.asList(TESTNG_JAR));
+
+ /**
+ * @param abi The ABI to run the test on
+ */
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ @Override
+ public ITestDevice getDevice() {
+ return mDevice;
+ }
+
+ @Override
+ public void setDevice(ITestDevice device) {
+ mDevice = device;
+ }
+
+ public void addTestJarFileName(String jarFileName) {
+ mTestJars.add(jarFileName);
+ }
+
+ public void setRunName(String runName) {
+ mRunName = runName;
+ }
+
+ public void setTests(Collection<TestIdentifier> tests) {
+ mTests = tests;
+ }
+
+ public Collection<TestIdentifier> getTests() {
+ return mTests;
+ }
+
+ @Override
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ addTestJarFileName(TESTNG_JAR);
+ checkFields();
+ long startTime = System.currentTimeMillis();
+ listener.testRunStarted(mRunName, mTests.size());
+ try {
+ installJars();
+ String jarPath = ArrayUtil.join(":", mJarPaths);
+ for (TestIdentifier testId : mTests) {
+ SingleJUnitTestResultParser resultParser = new SingleJUnitTestResultParser(
+ testId, listener);
+ String cmdLine = String.format("ANDROID_DATA=%s %s -cp %s %s " +
+ "com.android.cts.testng.SingleTestNGTestRunner %s#%s",
+ mDeviceTestTmpPath, mRuntimePath, jarPath, getRuntimeArgsNotNull(),
+ testId.getClassName(), testId.getTestName());
+ String cmd = AbiFormatter.formatCmdForAbi(cmdLine, mAbi.getBitness());
+ CLog.d("Running %s", cmd);
+ listener.testStarted(testId);
+ mDevice.executeShellCommand(cmd, resultParser, mMaxTimeToOutputResponse,
+ TimeUnit.MILLISECONDS, 0);
+ }
+ } finally {
+ listener.testRunEnded(System.currentTimeMillis() - startTime,
+ Collections.<String, String> emptyMap());
+ // Remove jar files from device
+ removeJars();
+ }
+ }
+
+ /**
+ * Installs the jar files on the device under test.
+ *
+ * @throws DeviceNotAvailableException
+ */
+ protected void installJars() throws DeviceNotAvailableException {
+ for (String f : mTestJars) {
+ CLog.d("Installing %s on %s", f, getDevice().getSerialNumber());
+ File jarFile;
+ try {
+ String fullJarPath = String.format("%s%s", mDeviceTestTmpPath, f);
+ jarFile = mCtsBuild.getTestApp(f);
+ boolean result = getDevice().pushFile(jarFile, fullJarPath);
+ if (!result) {
+ throw new AssertionError(String.format("Failed to push file to %s", fullJarPath));
+ }
+ mJarPaths.add(fullJarPath);
+ } catch (FileNotFoundException e) {
+ throw new AssertionError(String.format("Could not find file %s", f));
+ }
+ }
+ }
+
+ /**
+ * Cleans up the jar files from the device under test.
+ *
+ * @throws DeviceNotAvailableException
+ */
+ protected void removeJars() throws DeviceNotAvailableException {
+ for (String f : mTestJars) {
+ String fullJarPath = String.format("%s%s", mDeviceTestTmpPath, f);
+ CLog.d("Uninstalling %s on %s", fullJarPath, getDevice().getSerialNumber());
+ getDevice().executeShellCommand(String.format("rm %s", fullJarPath));
+ }
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ }
+
+ /**
+ * Checks that all mandatory member fields has been set.
+ */
+ protected void checkFields() {
+ if (mRunName == null) {
+ throw new IllegalArgumentException("run name has not been set");
+ }
+ if (mDevice == null) {
+ throw new IllegalArgumentException("Device has not been set");
+ }
+ if (mTestJars.isEmpty()) {
+ throw new IllegalArgumentException("No test jar has been set");
+ }
+ if (mTests == null) {
+ throw new IllegalArgumentException("tests has not been set");
+ }
+ if (mCtsBuild == null) {
+ throw new IllegalArgumentException("build has not been set");
+ }
+ for (String f : mTestJars) {
+ try {
+
+ mCtsBuild.getTestApp(f);
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException(String.format(
+ "Could not find jar %s in CTS build %s", f,
+ mCtsBuild.getRootDir().getAbsolutePath()));
+ }
+ }
+ }
+
+ /**
+ * Add runtime arguments to run the tests with.
+ *
+ * @param mRunTimeArgs
+ */
+ public void addRunTimeArgs(String mRunTimeArgs) {
+ mRuntimeArgs = mRunTimeArgs;
+ }
+
+ private String getRuntimeArgsNotNull() {
+ if (mRuntimeArgs == null) {
+ return "";
+ }
+ return mRuntimeArgs;
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 1234893..9478900 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -54,6 +54,7 @@
public static final String VM_HOST_TEST = "vmHostTest";
public static final String DEQP_TEST = "deqpTest";
public static final String JUNIT_DEVICE_TEST = "jUnitDeviceTest";
+ public static final String TESTNG_DEVICE_TEST = "testNGDeviceTest";
private String mAppPackageName = null;
private String mAppNameSpace = null;
@@ -278,7 +279,18 @@
jUnitDeviceTest.setAbi(mAbi);
mDigest = generateDigest(testCaseDir, mJarPath);
return jUnitDeviceTest;
- } else {
+ } else if (TESTNG_DEVICE_TEST.equals(mTestType)){
+ CLog.d("Creating TestNG device test %s", mName);
+ TestNGDeviceTest testNGDeviceTest = new TestNGDeviceTest();
+ testNGDeviceTest.setRunName(getId());
+ testNGDeviceTest.addTestJarFileName(mJarPath);
+ testNGDeviceTest.addRunTimeArgs(mRunTimeArgs);
+ testNGDeviceTest.setTests(mTests);
+ testNGDeviceTest.setAbi(mAbi);
+ mDigest = generateDigest(testCaseDir, mJarPath);
+ return testNGDeviceTest;
+ }
+ else {
CLog.d("Creating instrumentation test for %s", mName);
CtsInstrumentationApkTest instrTest = new CtsInstrumentationApkTest();
if (mTimeoutInMins >= 0) {