Merge "Fix JobThrottling tests, take 2." into rvc-dev
diff --git a/apps/CrossProfileTestApp/Android.bp b/apps/CrossProfileTestApp/Android.bp
new file mode 100644
index 0000000..cbf092b
--- /dev/null
+++ b/apps/CrossProfileTestApp/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "CrossProfileTestApp",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ min_sdk_version: "12",
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
diff --git a/apps/CrossProfileTestApp/AndroidManifest.xml b/apps/CrossProfileTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..ab04e55
--- /dev/null
+++ b/apps/CrossProfileTestApp/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.crossprofilepermissioncontrol" >
+
+ <application android:label="Cross Profile Test App">
+ <activity android:name=".TestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.OPEN_CROSS_PROFILE_TEST_APP" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+</manifest>
diff --git a/apps/CrossProfileTestApp/OWNERS b/apps/CrossProfileTestApp/OWNERS
new file mode 100644
index 0000000..e889bfe
--- /dev/null
+++ b/apps/CrossProfileTestApp/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 149743808
+sandness@google.com
+arangelov@google.com
+alexkershaw@google.com
+scottjonathan@google.com
+kholoudm@google.com
diff --git a/apps/CrossProfileTestApp/res/layout/main.xml b/apps/CrossProfileTestApp/res/layout/main.xml
new file mode 100644
index 0000000..1b199ea
--- /dev/null
+++ b/apps/CrossProfileTestApp/res/layout/main.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center">
+ <Button
+ android:id="@+id/cross_profile_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/open_settings"/>
+
+ <TextView
+ android:id="@+id/cross_profile_app_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="30sp"
+ android:textAlignment="center"
+ android:gravity="center"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CrossProfileTestApp/res/values/strings.xml b/apps/CrossProfileTestApp/res/values/strings.xml
new file mode 100644
index 0000000..93c0174
--- /dev/null
+++ b/apps/CrossProfileTestApp/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="open_settings">Open Settings</string>
+ <string name="cross_profile_enabled">INTERACTING ACROSS PROFILES ALLOWED</string>
+ <string name="cross_profile_disabled">INTERACTING ACROSS PROFILES NOT ALLOWED</string>
+
+</resources>
\ No newline at end of file
diff --git a/apps/CrossProfileTestApp/src/com/android/cts/crossprofilepermissioncontrol/TestActivity.java b/apps/CrossProfileTestApp/src/com/android/cts/crossprofilepermissioncontrol/TestActivity.java
new file mode 100644
index 0000000..e4364f1
--- /dev/null
+++ b/apps/CrossProfileTestApp/src/com/android/cts/crossprofilepermissioncontrol/TestActivity.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 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.crossprofilepermissioncontrol;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.content.pm.CrossProfileApps;
+import android.os.Bundle;
+import android.os.Process;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Test activity to check if the app can interact across profiles.
+ */
+public class TestActivity extends Activity {
+ private static final String INTERACT_ACROSS_PROFILES =
+ "android.permission.INTERACT_ACROSS_PROFILES";
+ private AppOpsManager mAppOpsManager;
+ private CrossProfileApps mCrossProfileApps;
+ private TextView mTextView;
+ private Button mSettingsButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ mTextView = findViewById(R.id.cross_profile_app_text);
+ mSettingsButton = findViewById(R.id.cross_profile_settings);
+
+ mAppOpsManager = getSystemService(AppOpsManager.class);
+ mCrossProfileApps = getSystemService(CrossProfileApps.class);
+
+ mSettingsButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startActivity(mCrossProfileApps.createRequestInteractAcrossProfilesIntent());
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ updateText();
+ }
+
+ private void updateText() {
+ final String op = AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES);
+ if (AppOpsManager.MODE_ALLOWED == mAppOpsManager.checkOpNoThrow(
+ op, Process.myUid(), getPackageName())) {
+ mTextView.setText(R.string.cross_profile_enabled);
+ } else {
+ mTextView.setText(R.string.cross_profile_disabled);
+ }
+ }
+}
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index f5f0d5e..a7651b6 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -113,7 +113,8 @@
CtsEmptyDeviceOwner \
CtsPermissionApp \
CtsForceStopHelper \
- NotificationBot
+ NotificationBot \
+ CrossProfileTestApp
# Apps to be installed as Instant App using adb install --instant
pre-installed-instant-app := CtsVerifierInstantApp
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 0703a59..0d5b5b1 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2871,6 +2871,14 @@
android:label="@string/provisioning_byod_keyguard_disabled_features">
</activity>
+ <activity android:name=".managedprovisioning.CrossProfilePermissionControlActivity"
+ android:label="@string/provisioning_byod_cross_profile_permission_control">
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.action.CROSS_PROFILE_PERMISSION_CONTROL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".managedprovisioning.DisallowAppsControlActivity"
android:label="@string/provisioning_byod_disallow_apps_control">
</activity>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4f9cc0a9..bbc663c 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2775,6 +2775,44 @@
\n
Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
</string>
+ <string name="provisioning_byod_cross_profile_permission_control">Cross profile permission control</string>
+ <string name="provisioning_byod_cross_profile_permission_control_info">
+ This test exercises cross profile permission controls. Follow instructions above.
+ </string>
+ <string name="provisioning_byod_cross_profile_permission_control_instruction">
+ For this test you need to install CrossProfileTestApp.apk by running
+ adb install -r -t /path/to/CrossProfileTestApp.apk. Make sure the app is installed
+ on both the personal and work profiles.\n
+ Press the \"Prepare test\" button to enable configuring cross profile for the test app.\n
+ Then press through the following verification steps.\n
+ Mark the test as passed if all the following test cases are verified.
+ </string>
+ <string name="provisioning_byod_cross_profile_permission_control_prepare_button">Prepare test</string>
+ <string name="provisioning_byod_cross_profile_permission_disabled_by_default">Cross profile permission disabled by default</string>
+ <string name="provisioning_byod_cross_profile_permission_disabled_by_default_instruction">
+ Press the Go button to go to Settings > Apps & notifications > Special app access >\n
+ Connected personal and work apps.\n
+ Choose the \"Cross profile test app\" from the list and check that the switch is disabled.\n
+ Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
+ </string>
+ <string name="provisioning_byod_cross_profile_permission_enabled">Cross profile permission enabled</string>
+ <string name="provisioning_byod_cross_profile_permission_enabled_instruction">
+ Press the Go button to open the \"Cross Profile Test App\".\n
+ Press the \"Open Settings\" button to go to Settings > Apps & notifications > Special app access >
+ Connected personal and work apps > Cross profile test app, then enable the switch.\n
+ Verify that when you go back it takes you to the \"Cross Profile Test App\".\n
+ Now verify that it shows \"INTERACTING ACROSS PROFILES ALLOWED\" message.\n
+ Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
+ </string>
+ <string name="provisioning_byod_cross_profile_permission_disabled">Cross profile permission disabled</string>
+ <string name="provisioning_byod_cross_profile_permission_disabled_instruction">
+ Press the Go button to open the \"Cross Profile Test App\".\n
+ Press the \"Open Settings\" button to go to Settings > Apps & notifications > Special app access >
+ Connected personal and work apps > Cross profile test app, then disable the switch.\n
+ Verify that when you go back it takes you to the \"Cross Profile Test App\".\n
+ Now verify that it shows \"INTERACTING ACROSS PROFILES NOT ALLOWED\" message.\n
+ Go back to CTS Verifier and mark the test as \"Pass\" or \"Fail\".
+ </string>
<string name="provisioning_byod_app_linking_instruction">
Please press the Go button to start an action.\n
\n
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index b13e3aa..656cd89 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -23,7 +23,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
@@ -90,6 +89,7 @@
private DialogTestListItem mWorkAppVisibleTest;
private DialogTestListItem mCrossProfileIntentFiltersTestFromPersonal;
private DialogTestListItem mCrossProfileIntentFiltersTestFromWork;
+ private TestListItem mCrossProfilePermissionControl;
private DialogTestListItem mAppLinkingTest;
private TestListItem mNonMarketAppsTest;
private DialogTestListItem mWorkNotificationBadgedTest;
@@ -451,6 +451,13 @@
}
};
+ mCrossProfilePermissionControl = TestListItem.newTest(this,
+ R.string.provisioning_byod_cross_profile_permission_control,
+ CrossProfilePermissionControlActivity.class.getName(),
+ new Intent(
+ CrossProfilePermissionControlActivity.ACTION_CROSS_PROFILE_PERMISSION_CONTROL),
+ null);
+
mTurnOffWorkFeaturesTest = TestListItem.newTest(this,
R.string.provisioning_byod_turn_off_work,
TurnOffWorkActivity.class.getName(),
@@ -544,6 +551,7 @@
adapter.add(mAppLinkingTest);
*/
adapter.add(mIntentFiltersTest);
+ adapter.add(mCrossProfilePermissionControl);
adapter.add(mNonMarketAppsTest);
adapter.add(mPermissionLockdownTest);
adapter.add(mKeyguardDisabledFeaturesTest);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
index 24e0919..2bb1046 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
@@ -58,6 +58,7 @@
AuthenticationBoundKeyTestActivity.class.getName(),
VpnTestActivity.class.getName(),
AlwaysOnVpnSettingsTestActivity.class.getName(),
+ CrossProfilePermissionControlActivity.class.getName(),
IntermediateRecentActivity.class.getName(),
CommandReceiverActivity.class.getName(),
SetSupportMessageActivity.class.getName(),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfilePermissionControlActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfilePermissionControlActivity.java
new file mode 100644
index 0000000..ef7dd67
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfilePermissionControlActivity.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+
+import java.util.Set;
+
+public class CrossProfilePermissionControlActivity extends DialogTestListActivity {
+ static final String ACTION_CROSS_PROFILE_PERMISSION_CONTROL =
+ "com.android.cts.verifier.managedprovisioning.action.CROSS_PROFILE_PERMISSION_CONTROL";
+ private static final String TEST_APP_PACKAGE_NAME =
+ "com.android.cts.crossprofilepermissioncontrol";
+ private static final String OPEN_TEST_APP_ACTION =
+ "com.android.cts.verifier.managedprovisioning.action.OPEN_CROSS_PROFILE_TEST_APP";
+
+ protected DevicePolicyManager mDpm;
+
+ public CrossProfilePermissionControlActivity() {
+ super(R.layout.provisioning_byod,
+ R.string.provisioning_byod_cross_profile_permission_control,
+ R.string.provisioning_byod_cross_profile_permission_control_info,
+ R.string.provisioning_byod_cross_profile_permission_control_instruction);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mDpm = getSystemService(DevicePolicyManager.class);
+ mPrepareTestButton.setText(
+ R.string.provisioning_byod_cross_profile_permission_control_prepare_button);
+ mPrepareTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ whitelistTestApp();
+ }
+ });
+ }
+
+ protected void whitelistTestApp() {
+ mDpm.setCrossProfilePackages(getAdminComponent(), Set.of(TEST_APP_PACKAGE_NAME));
+ }
+
+ protected ComponentName getAdminComponent() {
+ return DeviceAdminTestReceiver.getReceiverComponentName();
+ }
+
+ protected void setupInteractAcrossProfilesDisabledByDefault(ArrayTestListAdapter adapter) {
+ adapter.add(new DialogTestListItem(
+ this, R.string.provisioning_byod_cross_profile_permission_disabled_by_default,
+ getTestIdPrefix() + "interactAcrossProfilesDisabledByDefault",
+ R.string.provisioning_byod_cross_profile_permission_disabled_by_default_instruction,
+ new Intent(Settings.ACTION_MANAGE_CROSS_PROFILE_ACCESS)));
+ }
+
+ protected void setupInteractAcrossProfilesEnabled(ArrayTestListAdapter adapter) {
+ adapter.add(new DialogTestListItem(
+ this, R.string.provisioning_byod_cross_profile_permission_enabled,
+ getTestIdPrefix() + "interactAcrossProfilesEnabled",
+ R.string.provisioning_byod_cross_profile_permission_enabled_instruction,
+ new Intent(OPEN_TEST_APP_ACTION)));
+ }
+
+ protected void setupInteractAcrossProfilesDisabled(ArrayTestListAdapter adapter) {
+ adapter.add(new DialogTestListItem(this,
+ R.string.provisioning_byod_cross_profile_permission_disabled,
+ getTestIdPrefix() + "DisableUnredactedNotifications",
+ R.string.provisioning_byod_cross_profile_permission_disabled_instruction,
+ new Intent(OPEN_TEST_APP_ACTION)));
+ }
+
+ protected String getTestIdPrefix() {
+ return "BYOD_";
+ }
+
+ @Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ setupInteractAcrossProfilesDisabledByDefault(adapter);
+ setupInteractAcrossProfilesEnabled(adapter);
+ setupInteractAcrossProfilesDisabled(adapter);
+ }
+}
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 11351ec..c9e2449 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -181,6 +181,8 @@
filter.addAction(KeyChainTestActivity.ACTION_KEYCHAIN);
filter.addAction(CommandReceiverActivity.ACTION_EXECUTE_COMMAND);
filter.addAction(WorkProfileWidgetActivity.ACTION_TEST_WORK_PROFILE_WIDGET);
+ filter.addAction(
+ CrossProfilePermissionControlActivity.ACTION_CROSS_PROFILE_PERMISSION_CONTROL);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
@@ -192,6 +194,7 @@
filter.addAction(ByodFlowTestActivity.ACTION_TEST_RESULT);
filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
filter.addAction(LocationListenerActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES);
+
dpm.addCrossProfileIntentFilter(getWho(context), filter,
DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
index e5300ab..2a322aa 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
@@ -5,4 +5,5 @@
<string name="Ask">Ask every time</string>
<string name="Allow">Allow</string>
<string name="AllowAll">Allow all the time</string>
+ <string name="AllowForeground">Allow only while using the app</string>
</resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
index e5300ab..2a322aa 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
@@ -5,4 +5,5 @@
<string name="Ask">Ask every time</string>
<string name="Allow">Allow</string>
<string name="AllowAll">Allow all the time</string>
+ <string name="AllowForeground">Allow only while using the app</string>
</resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index 8b5630c..da6e44b 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -16,18 +16,16 @@
package com.android.cts.usepermission;
-import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
import static com.android.compatibility.common.util.UiAutomatorUtils.getUiDevice;
+import static com.android.compatibility.common.util.UiAutomatorUtils.waitFindObject;
import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.SECONDS;
import android.Manifest;
import android.app.Activity;
@@ -36,20 +34,16 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.icu.text.CaseMap;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.util.ArrayMap;
@@ -67,7 +61,6 @@
import com.android.compatibility.common.util.UiDumpUtils;
import junit.framework.Assert;
-import junit.framework.TestCase;
import org.junit.Before;
import org.junit.runner.RunWith;
@@ -76,7 +69,6 @@
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
@@ -449,19 +441,27 @@
waitForIdle();
}
- final boolean wasGranted = isTv() ? false : !(waitFindObject(byText(R.string.Deny)).isChecked() || (!legacyApp && waitFindObject(byText(R.string.Ask)).isChecked()));
+ final boolean wasGranted = isTv()
+ ? false
+ : !(waitFindObject(byText(R.string.Deny)).isChecked()
+ || (legacyApp
+ && hasAskButton(permission)
+ && waitFindObject(byText(R.string.Ask)).isChecked()));
boolean alreadyChecked = false;
if (isTv()) {
waitFindObject(By.text(permissionLabel)).click();
} else if (state == STATE_ALLOWED) {
- UiObject2 object = waitFindObject(byText(R.string.Allow));
+ UiObject2 object = waitFindObject(byText(
+ showsForegroundOnlyButton(permission)
+ ? R.string.AllowForeground
+ : R.string.Allow));
alreadyChecked = object.isChecked();
if (!alreadyChecked) {
object.click();
}
} else if (state == STATE_DENIED){
UiObject2 object;
- if (legacyApp) {
+ if (legacyApp || !hasAskButton(permission)) {
object = waitFindObject(byText(R.string.Deny));
} else {
object = waitFindObject(byText(R.string.Ask));
@@ -529,6 +529,19 @@
return mPlatformResources.getString(resourceId);
}
+ private boolean hasAskButton(String permission) {
+ return Manifest.permission.CAMERA.equals(permission)
+ || Manifest.permission.RECORD_AUDIO.equals(permission)
+ || Manifest.permission.ACCESS_FINE_LOCATION.equals(permission)
+ || Manifest.permission.ACCESS_COARSE_LOCATION.equals(permission)
+ || Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission);
+ }
+
+ private boolean showsForegroundOnlyButton(String permission) {
+ return Manifest.permission.CAMERA.equals(permission)
+ || Manifest.permission.RECORD_AUDIO.equals(permission);
+ }
+
private void startActivity(final Intent intent) throws Exception {
getInstrumentation().getUiAutomation().executeAndWaitForEvent(
() -> {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
index a958816..3be949d 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/UsePermissionTest23.java
@@ -285,9 +285,9 @@
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));
+ .checkSelfPermission(Manifest.permission.CAMERA));
- String[] permissions = new String[] {Manifest.permission.READ_CALENDAR};
+ String[] permissions = new String[] {Manifest.permission.CAMERA};
// Request the permission and deny it
BasePermissionActivity.Result firstResult = requestPermissions(permissions, () -> {
@@ -300,7 +300,7 @@
// Request the permission and choose don't ask again
BasePermissionActivity.Result secondResult = requestPermissions(new String[]{
- Manifest.permission.READ_CALENDAR}, () -> {
+ Manifest.permission.CAMERA}, () -> {
denyWithPrejudice();
getUiDevice().waitForIdle();
});
@@ -309,8 +309,8 @@
assertPermissionRequestResult(secondResult, permissions, new boolean[] {false});
// Clear the denial with prejudice
- grantPermission(Manifest.permission.READ_CALENDAR);
- revokePermission(Manifest.permission.READ_CALENDAR);
+ grantPermission(Manifest.permission.CAMERA);
+ revokePermission(Manifest.permission.CAMERA);
// We just committed a suicide by revoking the permission. See part2 below...
}
@@ -319,17 +319,17 @@
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));
+ .checkSelfPermission(Manifest.permission.CAMERA));
// Request the permission and allow it
BasePermissionActivity.Result thirdResult = requestPermissions(new String[]{
- Manifest.permission.READ_CALENDAR}, () -> {
- clickAllowButton();
+ Manifest.permission.CAMERA}, () -> {
+ clickAllowForegroundButton();
getUiDevice().waitForIdle();
});
// Make sure the permission is granted
- assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.READ_CALENDAR},
+ assertPermissionRequestResult(thirdResult, new String[] {Manifest.permission.CAMERA},
new boolean[] {true});
}
diff --git a/hostsidetests/content/src/android/content/cts/ContextCrossProfileHostTest.java b/hostsidetests/content/src/android/content/cts/ContextCrossProfileHostTest.java
index ed8c59a..509bf75 100644
--- a/hostsidetests/content/src/android/content/cts/ContextCrossProfileHostTest.java
+++ b/hostsidetests/content/src/android/content/cts/ContextCrossProfileHostTest.java
@@ -74,7 +74,7 @@
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- mParentUserId, /* extraArgs= */"-t");
+ mParentUserId, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
}
@After
@@ -89,7 +89,7 @@
public void setBuild(IBuildInfo buildInfo) {
mCtsBuild = buildInfo;
}
-
+
@Test
public void testBindServiceAsUser_differentUser_bindsServiceToCorrectUser()
throws Exception {
@@ -98,13 +98,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -125,13 +125,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -152,13 +152,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -179,13 +179,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -206,13 +206,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -233,13 +233,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -260,13 +260,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -287,13 +287,15 @@
mTestArgs.put("testUser", Integer.toString(userInDifferentProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -314,13 +316,15 @@
mTestArgs.put("testUser", Integer.toString(userInDifferentProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -341,13 +345,15 @@
mTestArgs.put("testUser", Integer.toString(userInDifferentProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInDifferentProfileGroup, /* extraArgs= */"-t");
+ userInDifferentProfileGroup, /* extraArgs= */"-t",
+ /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -368,13 +374,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -395,13 +401,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
@@ -422,13 +428,13 @@
mTestArgs.put("testUser", Integer.toString(userInSameProfileGroup));
getDevice().installPackageForUser(
mApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
File testServiceApkFile = buildHelper.getTestFile(TEST_SERVICE_WITH_PERMISSION_APK);
getDevice().installPackageForUser(
testServiceApkFile, /* reinstall= */true, /* grantPermissions= */true,
- userInSameProfileGroup, /* extraArgs= */"-t");
+ userInSameProfileGroup, /* extraArgs= */"-t", /* extraArgs= */"--force-queryable");
runDeviceTests(
getDevice(),
diff --git a/hostsidetests/incident/Android.bp b/hostsidetests/incident/Android.bp
index 1589078..3a3801b 100644
--- a/hostsidetests/incident/Android.bp
+++ b/hostsidetests/incident/Android.bp
@@ -26,5 +26,6 @@
"tradefed",
"compatibility-host-util",
"platformprotos",
+ "truth-prebuilt",
],
}
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/Android.bp b/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
index 52b5c74..c64f8a8 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
+++ b/hostsidetests/incident/apps/graphicsstatsapp/Android.bp
@@ -24,6 +24,7 @@
"ctstestrunner-axt",
"compatibility-device-util-axt",
"androidx.legacy_legacy-support-v4",
+ "truth-prebuilt",
],
sdk_version: "test_current",
// tag this module as a cts test artifact
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
index be9d645..88e1eaf 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/graphicsstatsapp/AndroidManifest.xml
@@ -22,6 +22,8 @@
<uses-library android:name="android.test.runner" />
<activity android:name=".DrawFramesActivity"
android:label="GraphicsStats Test Activity"
+ android:screenOrientation="locked"
+ android:resizeableActivity="false"
android:theme="@style/DefaultTheme"/>
</application>
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
index 1bbc601..fd1206f 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
@@ -144,10 +144,6 @@
}
}
- public void drawFrames(final int frameCount) throws InterruptedException, TimeoutException {
- drawFrames(new int[frameCount]);
- }
-
public void waitForReady() throws InterruptedException, TimeoutException {
if (!mReady.await(4, TimeUnit.SECONDS)) {
throw new TimeoutException();
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
index 56413f8..1a93309 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/SimpleDrawFrameTests.java
@@ -15,13 +15,14 @@
*/
package com.android.server.cts.device.graphicsstats;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.google.common.collect.Range;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,25 +39,37 @@
public ActivityTestRule<DrawFramesActivity> mActivityRule =
new ActivityTestRule<>(DrawFramesActivity.class);
- @Test
- public void testDrawTenFrames() throws Throwable {
+ void runTest(final int frameCount) throws Throwable {
+ runTest(new int[frameCount]);
+ }
+
+ void runTest(final int[] framesToDraw) throws Throwable {
DrawFramesActivity activity = mActivityRule.getActivity();
activity.waitForReady();
int initialFrames = activity.getRenderedFramesCount();
- assertTrue(initialFrames < 5);
- assertEquals(0, activity.getDroppedReportsCount());
- activity.drawFrames(10);
- assertEquals(initialFrames + 10, activity.getRenderedFramesCount());
- assertEquals(0, activity.getDroppedReportsCount());
+ assertThat(initialFrames).isLessThan(5);
+ assertThat(activity.getDroppedReportsCount()).isEqualTo(0);
+ activity.drawFrames(framesToDraw);
+ final int expectedFrameCount = initialFrames + framesToDraw.length;
+ assertThat(activity.getRenderedFramesCount()).isIn(
+ Range.closedOpen(expectedFrameCount, expectedFrameCount + 5));
+ assertThat(activity.getDroppedReportsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testNothing() throws Throwable {
+ DrawFramesActivity activity = mActivityRule.getActivity();
+ activity.waitForReady();
+ activity.drawFrames(new int[10]);
+ }
+
+ @Test
+ public void testDrawTenFrames() throws Throwable {
+ runTest(10);
}
@Test
public void testDrawJankyFrames() throws Throwable {
- DrawFramesActivity activity = mActivityRule.getActivity();
- activity.waitForReady();
- int initialFrames = activity.getRenderedFramesCount();
- assertTrue(initialFrames < 5);
- assertEquals(0, activity.getDroppedReportsCount());
int[] frames = new int[50];
for (int i = 0; i < 10; i++) {
int indx = i * 5;
@@ -65,26 +78,17 @@
frames[indx + 2] = DrawFramesActivity.FRAME_JANK_LAYOUT;
frames[indx + 3] = DrawFramesActivity.FRAME_JANK_MISS_VSYNC;
}
- activity.drawFrames(frames);
- assertEquals(initialFrames + 50, activity.getRenderedFramesCount());
- assertEquals(0, activity.getDroppedReportsCount());
+ runTest(frames);
}
@Test
public void testDrawDaveyFrames() throws Throwable {
- DrawFramesActivity activity = mActivityRule.getActivity();
- activity.waitForReady();
- int initialFrames = activity.getRenderedFramesCount();
- assertTrue(initialFrames < 5);
- assertEquals(0, activity.getDroppedReportsCount());
int[] frames = new int[40];
for (int i = 0; i < 10; i++) {
int indx = i * 4;
frames[indx] = DrawFramesActivity.FRAME_JANK_DAVEY;
frames[indx + 2] = DrawFramesActivity.FRAME_JANK_DAVEY_JR;
}
- activity.drawFrames(frames);
- assertEquals(initialFrames + 40, activity.getRenderedFramesCount());
- assertEquals(0, activity.getDroppedReportsCount());
+ runTest(frames);
}
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index ea1f803..843531d 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -15,12 +15,14 @@
*/
package com.android.server.cts;
+import static com.google.common.truth.Truth.assertThat;
+
import android.service.GraphicsStatsHistogramBucketProto;
import android.service.GraphicsStatsJankSummaryProto;
import android.service.GraphicsStatsProto;
import android.service.GraphicsStatsServiceDumpProto;
-import com.android.tradefed.log.LogUtil.CLog;
+import com.google.common.collect.Range;
import java.util.ArrayList;
import java.util.Date;
@@ -46,7 +48,7 @@
turnScreenOn();
// Ensure that we have a starting point for our stats
runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".SimpleDrawFrameTests",
- "testDrawTenFrames");
+ "testNothing");
// Kill to ensure that stats persist/merge across process death
killTestApp();
}
@@ -91,24 +93,24 @@
int jankyDelta = summaryAfter.getJankyFrames() - summaryBefore.getJankyFrames();
// Test draws 50 frames + 1 initial frame. We expect 40 of them to be janky,
// 10 of each of ANIMATION, LAYOUT, RECORD_DRAW, and MISSED_VSYNC
- assertTrue(frameDelta < 55);
- assertTrue(jankyDelta >= 40);
- assertTrue(jankyDelta < 45);
+
+ assertThat(frameDelta).isAtLeast(50);
+ assertThat(jankyDelta).isAtLeast(40);
+ assertThat(jankyDelta).isLessThan(45);
// Although our current stats don't distinguish between ANIMATION, LAYOUT, and RECORD_DRAW
// so this will just be slowUi +30
int slowUiDelta = summaryAfter.getSlowUiThreadCount() - summaryBefore.getSlowUiThreadCount();
- assertTrue(slowUiDelta >= 30);
+ assertThat(slowUiDelta).isAtLeast(28);
int missedVsyncDelta = summaryAfter.getMissedVsyncCount()
- summaryBefore.getMissedVsyncCount();
- assertTrue(missedVsyncDelta >= 10);
- assertTrue(missedVsyncDelta <= 11);
+ assertThat(missedVsyncDelta).isIn(Range.closed(10, 11));
int veryJankyDelta = countFramesAbove(statsAfter, 60) - countFramesAbove(statsBefore, 60);
// The 1st frame could be >40ms, but nothing after that should be
- assertTrue(veryJankyDelta <= 2);
+ assertThat(veryJankyDelta).isAtMost(2);
int noGPUJank = countGPUFramesAbove(statsAfter, 60) - countGPUFramesAbove(statsBefore, 60);
- assertTrue(noGPUJank == 0);
+ assertThat(noGPUJank).isEqualTo(0);
}
public void testDaveyDrawFrame() throws Exception {
@@ -123,13 +125,12 @@
int jankyDelta = summaryAfter.getJankyFrames() - summaryBefore.getJankyFrames();
// Test draws 40 frames + 1 initial frame. We expect 10 of them to be daveys,
// 10 of them to be daveyjrs, and 20 to jank from missed vsync (from the davey/daveyjr prior to it)
- assertTrue(frameDelta < 45);
- assertTrue(jankyDelta >= 20);
- assertTrue(jankyDelta < 25);
+ assertThat(frameDelta).isAtLeast(40);
+ assertThat(jankyDelta).isAtLeast(20);
+ assertThat(jankyDelta).isLessThan(25);
int gt150msDelta = countFramesAbove(statsAfter, 150) - countFramesAbove(statsBefore, 150);
- assertTrue(gt150msDelta >= 20); // 10 davey jrs + 10 daveys + maybe first 2 frames
- assertTrue(gt150msDelta <= 22);
+ assertThat(gt150msDelta).isIn(Range.closed(20, 22));
int gt700msDelta = countFramesAbove(statsAfter, 700) - countFramesAbove(statsBefore, 700);
assertEquals(10, gt700msDelta); // 10 daveys
}
@@ -139,10 +140,10 @@
}
private GraphicsStatsProto[] doRunDrawTest(String testName, boolean canRetry) throws Exception {
- GraphicsStatsProto statsBefore = fetchStats();
- assertNotNull(statsBefore);
killTestApp();
turnScreenOn();
+ GraphicsStatsProto statsBefore = fetchStats();
+ assertNotNull(statsBefore);
runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".SimpleDrawFrameTests", testName);
killTestApp();
GraphicsStatsProto statsAfter = fetchStats();
diff --git a/hostsidetests/securitybulletin/res/CVE-2018-9490.pac b/hostsidetests/securitybulletin/res/CVE-2018-9490.pac
index 9fb7ba8..999518a 100644
--- a/hostsidetests/securitybulletin/res/CVE-2018-9490.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2018-9490.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
alert("enter");
let arr = [];
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2045.pac b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
index 1cb28ff..a6b0166 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
opttest();
opttest();
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2047.pac b/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
index 5e39e9b..b70e24a 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
for(var i = 0;i<0x10000;i++){
change_elements_kind(x);
@@ -40,4 +56,4 @@
var evil = new Array(1.1,2.2);
evil.x = {};
-var x = new Array({});
\ No newline at end of file
+var x = new Array({});
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2051.pac b/hostsidetests/securitybulletin/res/CVE-2019-2051.pac
index b014a16..b24b160 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2051.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2051.pac
@@ -1,5 +1,21 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
this.__defineGetter__("x", (a = (function f() { return; (function() {}); })()) => { });
x;
return "DIRECT";
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2052.pac b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
index ab5ed69..670e870 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
for(var i = 0;i < 0x1000;i++){
tt();
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2097.pac b/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
index 6c0a8b0..4880f54 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
for (var i = 0; i < 0x10000; i++){
f();
@@ -19,4 +35,4 @@
array[i][0] = {"abcd":0x4321};
}
double_arr[1] = 6.176516726456e-312;
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2130.pac b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
index 79d1967..77a0cb5 100644
--- a/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
function opt() {
opt['x'] = 1.1;
@@ -18,4 +34,4 @@
return "DIRECT";
}
-var object;
\ No newline at end of file
+var object;
diff --git a/hostsidetests/securitybulletin/res/bug_138441919.pac b/hostsidetests/securitybulletin/res/bug_138441919.pac
index 61a9ee2..006fb6a 100644
--- a/hostsidetests/securitybulletin/res/bug_138441919.pac
+++ b/hostsidetests/securitybulletin/res/bug_138441919.pac
@@ -1,6 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
Object.defineProperty(Promise, Symbol.species, { value: 0 });
var p = new Promise(function() {});
p.then();
return "DIRECT";
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/securitybulletin/res/bug_139806216.pac b/hostsidetests/securitybulletin/res/bug_139806216.pac
index 3a1e34d..256108d 100644
--- a/hostsidetests/securitybulletin/res/bug_139806216.pac
+++ b/hostsidetests/securitybulletin/res/bug_139806216.pac
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
function FindProxyForURL(url, host){
var x = new ArrayBuffer(1);
return "DIRECT";
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
index ef0a5cb..1a7e5b6 100755
--- a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
@@ -49,6 +49,8 @@
case InputMessage::Type::KEY: {
// uint32_t seq
outMsg->body.key.seq = msg.body.key.seq;
+ // int32_t eventId
+ outMsg->body.key.eventId = msg.body.key.eventId;
// nsecs_t eventTime
outMsg->body.key.eventTime = msg.body.key.eventTime;
// int32_t deviceId
@@ -78,6 +80,8 @@
case InputMessage::Type::MOTION: {
// uint32_t seq
outMsg->body.motion.seq = msg.body.motion.seq;
+ // int32_t eventId
+ outMsg->body.motion.eventId = msg.body.key.eventId;
// nsecs_t eventTime
outMsg->body.motion.eventTime = msg.body.motion.eventTime;
// int32_t deviceId
@@ -146,6 +150,7 @@
}
case InputMessage::Type::FOCUS: {
outMsg->body.focus.seq = msg.body.focus.seq;
+ outMsg->body.focus.eventId = msg.body.focus.eventId;
outMsg->body.focus.hasFocus = msg.body.focus.hasFocus;
outMsg->body.focus.inTouchMode = msg.body.focus.inTouchMode;
break;
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
index 238bb0b..b5386e1 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
@@ -1,4 +1,20 @@
/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
* CVE-2016-5862
*/
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
index c8e4a20..3b8771f 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
@@ -1,4 +1,20 @@
/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
* CVE-2016-5867
*/
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
index 1622b39..8dad1b8 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#ifndef __LOCAL_POC_H__
#define __LOCAL_POC_H__
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
index a89d596..d8f3471 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#define _GNU_SOURCE
#include <pthread.h>
#include <err.h>
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
index 5f9bd37..0b464e5 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <android/hardware/cas/1.0/ICas.h>
#include <android/hardware/cas/1.0/IMediaCasService.h>
#include <android/hardware/cas/native/1.0/IDescrambler.h>
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
index e62a7b3..1d57cb6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security.cts;
import com.android.ddmlib.Log;
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 9c55177..7458be5 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -22,7 +22,10 @@
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
@@ -61,6 +64,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
import org.junit.Test;
import java.util.Arrays;
@@ -71,6 +76,8 @@
public class AtomTests {
private static final String TAG = AtomTests.class.getSimpleName();
+ private static final String MY_PACKAGE_NAME = "com.android.server.cts.device.statsd";
+
@Test
public void testAudioState() {
// TODO: This should surely be getTargetContext(), here and everywhere, but test first.
@@ -230,6 +237,58 @@
}
@Test
+ public void testForegroundServiceAccessAppOp() throws Exception {
+ Context context = InstrumentationRegistry.getContext();
+ Intent fgsIntent = new Intent(context, StatsdCtsForegroundService.class);
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
+ // No foreground service session
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+
+ // Foreground service session 1
+ context.startService(fgsIntent);
+ while (!checkIfServiceRunning(context, StatsdCtsForegroundService.class.getName())) {
+ sleep(50);
+ }
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_FINE_LOCATION, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA, true);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, false);
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO, true);
+ context.stopService(fgsIntent);
+
+ // No foreground service session
+ noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION, true);
+
+ // TODO(b/149098800): Start fgs a second time and log OPSTR_CAMERA again
+ }
+
+ /** @param doNote true if should use noteOp; false if should use startOp. */
+ private void noteAppOp(AppOpsManager appOpsManager, String opStr, boolean doNote) {
+ if (doNote) {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(appOpsManager,
+ (aom) -> aom.noteOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null,
+ "statsdTest"));
+ } else {
+ ShellIdentityUtils.invokeMethodWithShellPermissions(appOpsManager,
+ (aom) -> aom.startOp(opStr, android.os.Process.myUid(),
+ MY_PACKAGE_NAME, null, "statsdTest"));
+ }
+ sleep(500);
+ }
+
+ /** Check if service is running. */
+ public boolean checkIfServiceRunning(Context context, String serviceName) {
+ ActivityManager manager = context.getSystemService(ActivityManager.class);
+ for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+ if (serviceName.equals(service.service.getClassName()) && service.foreground) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Test
public void testGpsScan() {
Context context = InstrumentationRegistry.getContext();
final LocationManager locManager = context.getSystemService(LocationManager.class);
@@ -396,7 +455,7 @@
@Test
public void testScheduledJob() throws Exception {
- final ComponentName name = new ComponentName("com.android.server.cts.device.statsd",
+ final ComponentName name = new ComponentName(MY_PACKAGE_NAME,
StatsdJobService.class.getName());
Context context = InstrumentationRegistry.getContext();
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 1d4b2d6..ac45c06 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -22,7 +22,6 @@
import android.os.WakeLockLevelEnum;
import android.server.ErrorSource;
-import com.android.internal.os.StatsdConfigProto.FieldMatcher;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.os.AtomsProto;
import com.android.os.AtomsProto.ANROccurred;
@@ -40,12 +39,13 @@
import com.android.os.AtomsProto.DangerousPermissionStateSampled;
import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
import com.android.os.AtomsProto.FlashlightStateChanged;
+import com.android.os.AtomsProto.ForegroundServiceAppOpSessionEnded;
import com.android.os.AtomsProto.ForegroundServiceStateChanged;
import com.android.os.AtomsProto.GpsScanStateChanged;
import com.android.os.AtomsProto.HiddenApiUsed;
import com.android.os.AtomsProto.IonHeapSize;
-import com.android.os.AtomsProto.LooperStats;
import com.android.os.AtomsProto.LmkKillOccurred;
+import com.android.os.AtomsProto.LooperStats;
import com.android.os.AtomsProto.MediaCodecStateChanged;
import com.android.os.AtomsProto.OverlayStateChanged;
import com.android.os.AtomsProto.PackageNotificationPreferences;
@@ -73,7 +73,6 @@
import java.lang.ProcessBuilder;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -544,6 +543,51 @@
atom -> atom.getForegroundServiceStateChanged().getState().getNumber());
}
+
+ public void testForegroundServiceAccessAppOp() throws Exception {
+ if (statsdDisabled()) {
+ return;
+ }
+ final int atomTag = Atom.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED_FIELD_NUMBER;
+ final String name = "testForegroundServiceAccessAppOp";
+
+ createAndUploadConfig(atomTag, false);
+ Thread.sleep(WAIT_TIME_SHORT);
+
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
+
+ // Sorted list of events in order in which they occurred.
+ List<EventMetricData> data = getEventMetricDataList();
+
+ assertWithMessage("Wrong atom size").that(data.size()).isEqualTo(3);
+ for (int i = 0; i < data.size(); i++) {
+ ForegroundServiceAppOpSessionEnded atom
+ = data.get(i).getAtom().getForegroundServiceAppOpSessionEnded();
+ final int opName = atom.getAppOpName().getNumber();
+ final int acceptances = atom.getCountOpsAccepted();
+ final int rejections = atom.getCountOpsRejected();
+ final int count = acceptances + rejections;
+ int expectedCount = 0;
+ switch (opName) {
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_CAMERA_VALUE:
+ expectedCount = 2;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_FINE_LOCATION_VALUE:
+ expectedCount = 1;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_RECORD_AUDIO_VALUE:
+ expectedCount = 2;
+ break;
+ case ForegroundServiceAppOpSessionEnded.AppOpName.OP_COARSE_LOCATION_VALUE:
+ // fall-through
+ default:
+ fail("Unexpected opName " + opName);
+ }
+ assertWithMessage("Wrong count for " + opName).that(count).isEqualTo(expectedCount);
+
+ }
+ }
+
public void testGpsScan() throws Exception {
if (statsdDisabled()) {
return;
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
index 0c9cebb..32f5a1a 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
@@ -133,12 +133,10 @@
private JobInfo makePhotosJobInfo() {
JobInfo.Builder builder = new JobInfo.Builder(TRIGGER_CONTENT_JOB_ID,
kTriggerContentServiceComponent);
- // Look for specific changes to images in the provider.
+ // Look for general reports of changes in the overall provider.
builder.addTriggerContentUri(new JobInfo.TriggerContentUri(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ MEDIA_URI,
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
- // Also look for general reports of changes in the overall provider.
- builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0));
// For testing purposes, react quickly.
builder.setTriggerContentUpdateDelay(500);
builder.setTriggerContentMaxDelay(500);
diff --git a/tests/accessibility/res/drawable/size_48x48.jpg b/tests/accessibility/res/drawable/jpg_48_48.jpg
similarity index 100%
rename from tests/accessibility/res/drawable/size_48x48.jpg
rename to tests/accessibility/res/drawable/jpg_48_48.jpg
Binary files differ
diff --git a/tests/accessibility/res/drawable/png_72_72.png b/tests/accessibility/res/drawable/png_72_72.png
new file mode 100644
index 0000000..941458d
--- /dev/null
+++ b/tests/accessibility/res/drawable/png_72_72.png
Binary files differ
diff --git a/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml b/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml
new file mode 100644
index 0000000..0d11dc0
--- /dev/null
+++ b/tests/accessibility/res/drawable/vector_drawable_6kdp_6kdp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="6000dp"
+ android:height="6000dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
+</vector>
diff --git a/tests/accessibility/res/raw/test_file b/tests/accessibility/res/raw/test_file
new file mode 100644
index 0000000..acea7ed
--- /dev/null
+++ b/tests/accessibility/res/raw/test_file
@@ -0,0 +1,12 @@
+10101010110101010101101010101011010101010110101010101101010101011010101010110
+1010101011010101010110101010101101010101011010101011010101101101010101011011011010101101101
+1011010101010011010101010110101011011010101010110101011011010101010110110110101010101101
+10110101010101101010101011010101010110101010101101010101010101101010101011010101
+101101010101011010101010110101010101101010101011010101101011010101010110101010101101010101011010101
+101101010101101010101011010101101101010101011010101001010110101011011010101010110110101010101
+10110101010101101010101011010101010110101010101101010101010101101
+101101010101010110101010101101010110110101010101101010101011010101011101010101011010101101101010
+10110101010101011010101101101010101011010101101010101011010101101010101011010101
+101101010101011010101011010101010110101011011010101010110101010101101010101
+
+
diff --git a/tests/accessibility/res/values/strings.xml b/tests/accessibility/res/values/strings.xml
index de1539a..40c3359 100644
--- a/tests/accessibility/res/values/strings.xml
+++ b/tests/accessibility/res/values/strings.xml
@@ -32,8 +32,26 @@
<!-- Description of the speaking accessibility service -->
<string name="some_description">Some description</string>
+ <!-- Html description of the vibrating accessibility service -->
+ <string name="html_description_vibrating_accessibility_service"><![CDATA[
+ <A href=\"fake_link\">Test link</a> <IMG src = \"R.drawable.file_name\">
+ ]]></string>
+
<!-- Html description of the speaking accessibility service -->
- <string name="some_html_description">Some html description</string>
+ <string name="html_description_speaking_accessibility_service"><![CDATA[
+ <a href=\"fake_link\"> <img src=\"R.drawable.file_name\">
+ ]]></string>
+
+ <!-- Html description of the speaking and vibrating accessibility service -->
+ <string name="html_description_speaking_and_vibrating_accessibility_service"><![CDATA[
+ <a href=fake_link> <img src=R.drawable.file_name>
+ ]]></string>
+
+ <!-- Html description of the accessibility button service -->
+ <string name="html_description_accessibility_button_service"><![CDATA[
+ <img src=\"r.drawable.file_name\"> <img alt=\"foo\" src=\"R.drawable.file_name\">
+ <img src=\"file://path\"> <img src=\"http://path\">
+ ]]></string>
<!-- Summary of the speaking accessibility service -->
<string name="some_summary">Some summary</string>
diff --git a/tests/accessibility/res/xml/accessibility_button_service.xml b/tests/accessibility/res/xml/accessibility_button_service.xml
index d475266..e483fd4 100644
--- a/tests/accessibility/res/xml/accessibility_button_service.xml
+++ b/tests/accessibility/res/xml/accessibility_button_service.xml
@@ -18,4 +18,6 @@
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagRequestAccessibilityButton"
+ android:animatedImageDrawable="@raw/test_file"
+ android:htmlDescription="@string/html_description_accessibility_button_service"
android:notificationTimeout="0" />
\ No newline at end of file
diff --git a/tests/accessibility/res/xml/speaking_accessibilityservice.xml b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
index ede686d..9128309 100644
--- a/tests/accessibility/res/xml/speaking_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/speaking_accessibilityservice.xml
@@ -21,9 +21,9 @@
android:canRequestTouchExplorationMode="true"
android:canRequestFilterKeyEvents="true"
android:settingsActivity="foo.bar.Activity"
- android:animatedImageDrawable="@drawable/size_48x48"
+ android:animatedImageDrawable="@drawable/jpg_48_48"
android:description="@string/some_description"
- android:htmlDescription="@string/some_html_description"
+ android:htmlDescription="@string/html_description_speaking_accessibility_service"
android:summary="@string/some_summary"
android:nonInteractiveUiTimeout="1000"
android:interactiveUiTimeout="6000"/>
\ No newline at end of file
diff --git a/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml b/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
index 3ac8661..09d36c6 100644
--- a/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/speaking_and_vibrating_accessibilityservice.xml
@@ -22,7 +22,7 @@
android:canRequestFilterKeyEvents="true"
android:canRequestEnhancedWebAccessibility="true"
android:settingsActivity="foo.bar.Activity"
- android:animatedImageDrawable="@drawable/size_48x48"
+ android:animatedImageDrawable="@drawable/vector_drawable_6kdp_6kdp"
android:description="@string/some_description"
- android:htmlDescription="@string/some_html_description"
+ android:htmlDescription="@string/html_description_speaking_and_vibrating_accessibility_service"
android:summary="@string/some_summary" />
diff --git a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
index 93d9f0d..ddf4018 100644
--- a/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
+++ b/tests/accessibility/res/xml/vibrating_accessibilityservice.xml
@@ -20,4 +20,6 @@
android:canRetrieveWindowContent="true"
android:canRequestTouchExplorationMode="true"
android:nonInteractiveUiTimeout="2000"
+ android:animatedImageDrawable="@drawable/png_72_72"
+ android:htmlDescription="@string/html_description_vibrating_accessibility_service"
android:interactiveUiTimeout="5000"/>
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
index d2f7c2d..2c8535d 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityServiceInfoTest.java
@@ -26,13 +26,14 @@
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.Service;
+import android.content.pm.PackageManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -49,22 +50,42 @@
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityServiceInfoTest {
+ private AccessibilityManager mAccessibilityManager;
+ private PackageManager mPackageManager;
- private InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
+ private final InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService>
mSpeakingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
- SpeakingAccessibilityService.class);
+ SpeakingAccessibilityService.class);
- private InstrumentedAccessibilityServiceTestRule<VibratingAccessibilityService>
+ private final InstrumentedAccessibilityServiceTestRule<VibratingAccessibilityService>
mVibratingAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
- VibratingAccessibilityService.class);
+ VibratingAccessibilityService.class);
+
+ private final InstrumentedAccessibilityServiceTestRule<SpeakingAndVibratingAccessibilityService>
+ mSpeakingAndVibratingAccessibilityServiceRule =
+ new InstrumentedAccessibilityServiceTestRule<>(
+ SpeakingAndVibratingAccessibilityService.class, /* enableService= */ false);
+
+ private final InstrumentedAccessibilityServiceTestRule<AccessibilityButtonService>
+ mA11yButtonServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
+ AccessibilityButtonService.class, /* enableService= */ false);
@Rule
public final RuleChain mRuleChain = RuleChain
.outerRule(mVibratingAccessibilityServiceRule)
.around(mSpeakingAccessibilityServiceRule)
+ .around(mSpeakingAndVibratingAccessibilityServiceRule)
+ .around(mA11yButtonServiceRule)
// Inner rule capture failure and dump data before finishing a11y service
.around(new AccessibilityDumpOnFailureRule());
+ @Before
+ public void setUp() throws Exception {
+ mAccessibilityManager = getInstrumentation().getContext().getSystemService(
+ AccessibilityManager.class);
+ mPackageManager = getInstrumentation().getContext().getPackageManager();
+ }
+
/**
* Tests whether a service can that requested it can retrieve
* window content.
@@ -73,13 +94,12 @@
@SuppressWarnings("deprecation")
@Test
public void testAccessibilityServiceInfoForEnabledService() {
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
- List<AccessibilityServiceInfo> enabledServices =
- accessibilityManager.getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_SPOKEN);
- assertSame("There should be one speaking service.", 1, enabledServices.size());
- AccessibilityServiceInfo speakingService = enabledServices.get(0);
+ final List<AccessibilityServiceInfo> enabledServices =
+ mAccessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+ assertSame(/* message= */ "There should be one speaking service.",
+ /* expected= */ 1, enabledServices.size());
+ final AccessibilityServiceInfo speakingService = enabledServices.get(0);
assertSame(AccessibilityEvent.TYPES_ALL_MASK, speakingService.eventTypes);
assertSame(AccessibilityServiceInfo.FEEDBACK_SPOKEN, speakingService.feedbackType);
assertEquals(AccessibilityServiceInfo.DEFAULT
@@ -89,8 +109,8 @@
| AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS
| AccessibilityServiceInfo.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK,
speakingService.flags);
- assertSame(0l, speakingService.notificationTimeout);
- assertEquals("Some description", speakingService.getDescription());
+ assertSame(/* expected= */ 0l, speakingService.notificationTimeout);
+ assertEquals(/* expected= */ "Some description", speakingService.getDescription());
assertNull(speakingService.packageNames /*all packages*/);
assertNotNull(speakingService.getId());
assertSame(speakingService.getCapabilities(),
@@ -98,15 +118,14 @@
| AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
| AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
assertEquals("foo.bar.Activity", speakingService.getSettingsActivityName());
- assertNotNull(speakingService.loadAnimatedImage(getInstrumentation().getContext()));
- assertEquals("Some description", speakingService.loadDescription(
- getInstrumentation().getContext().getPackageManager()));
- assertEquals("Some html description", speakingService.loadHtmlDescription(
- getInstrumentation().getContext().getPackageManager()));
- assertEquals("Some summary", speakingService.loadSummary(
- getInstrumentation().getContext().getPackageManager()));
+ assertEquals(/* expected= */ "Some description",
+ speakingService.loadDescription(mPackageManager));
+ assertEquals(/* expected= */ "Some summary",
+ speakingService.loadSummary(mPackageManager));
assertNotNull(speakingService.getResolveInfo());
- assertEquals(6000, speakingService.getInteractiveUiTimeoutMillis());
- assertEquals(1000, speakingService.getNonInteractiveUiTimeoutMillis());
+ assertEquals(/* expected= */ 6000,
+ speakingService.getInteractiveUiTimeoutMillis());
+ assertEquals(/* expected= */ 1000,
+ speakingService.getNonInteractiveUiTimeoutMillis());
}
}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
index 4111baf..8f79102 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
@@ -18,6 +18,7 @@
import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -69,6 +70,8 @@
private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
new AccessibilityDumpOnFailureRule();
+ private AccessibilityEmbeddedHierarchyActivity mActivity;
+
@Rule
public final RuleChain mRuleChain = RuleChain
.outerRule(mActivityRule)
@@ -90,8 +93,9 @@
@Before
public void setUp() throws Throwable {
- launchActivityAndWaitForItToBeOnscreen(sInstrumentation, sUiAutomation, mActivityRule)
- .waitForEmbeddedHierarchy();
+ mActivity = launchActivityAndWaitForItToBeOnscreen(sInstrumentation, sUiAutomation,
+ mActivityRule);
+ mActivity.waitForEmbeddedHierarchy();
}
@Test
@@ -114,6 +118,7 @@
final AccessibilityNodeInfo target =
findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
final AccessibilityNodeInfo parent = target.getParent();
+
final Rect hostViewBoundsInScreen = new Rect();
final Rect embeddedViewBoundsInScreen = new Rect();
parent.getBoundsInScreen(hostViewBoundsInScreen);
@@ -125,6 +130,36 @@
hostViewBoundsInScreen.contains(embeddedViewBoundsInScreen));
}
+ @Test
+ public void testEmbeddedViewHasCorrectBoundAfterHostViewMove() {
+ final AccessibilityNodeInfo target =
+ findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+
+ final Rect hostViewBoundsInScreen = new Rect();
+ final Rect newEmbeddedViewBoundsInScreen = new Rect();
+ final Rect oldEmbeddedViewBoundsInScreen = new Rect();
+ target.getBoundsInScreen(oldEmbeddedViewBoundsInScreen);
+
+ // Move Host SurfaceView from (0, 0) to (100, 100).
+ mActivity.requestNewLayoutForTest();
+
+ final AccessibilityNodeInfo newTarget =
+ findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+ final AccessibilityNodeInfo parent = newTarget.getParent();
+
+ newTarget.getBoundsInScreen(newEmbeddedViewBoundsInScreen);
+ parent.getBoundsInScreen(hostViewBoundsInScreen);
+
+ assertTrue("hostViewBoundsInScreen" + hostViewBoundsInScreen.toShortString()
+ + " doesn't contain newEmbeddedViewBoundsInScreen"
+ + newEmbeddedViewBoundsInScreen.toShortString(),
+ hostViewBoundsInScreen.contains(newEmbeddedViewBoundsInScreen));
+ assertFalse("newEmbeddedViewBoundsInScreen" + newEmbeddedViewBoundsInScreen.toShortString()
+ + " shouldn't be the same with oldEmbeddedViewBoundsInScreen"
+ + oldEmbeddedViewBoundsInScreen.toShortString(),
+ newEmbeddedViewBoundsInScreen.equals(oldEmbeddedViewBoundsInScreen));
+ }
+
private AccessibilityNodeInfo findEmbeddedAccessibilityNodeInfo(AccessibilityNodeInfo root) {
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -150,8 +185,11 @@
AccessibilityTestActivity implements SurfaceHolder.Callback {
private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
- private static final int DEFAULT_WIDTH = 200;
- private static final int DEFAULT_HEIGHT = 200;
+ private static final int DEFAULT_WIDTH = 150;
+ private static final int DEFAULT_HEIGHT = 150;
+
+ private static final int POSITION_X = 50;
+ private static final int POSITION_Y = 50;
private SurfaceView mSurfaceView;
private SurfaceControlViewHost mViewHost;
@@ -195,5 +233,13 @@
throw new AssertionError(e);
}
}
+
+ public void requestNewLayoutForTest() {
+ sInstrumentation.runOnMainSync(() -> {
+ mSurfaceView.setX(POSITION_X);
+ mSurfaceView.setY(POSITION_Y);
+ mSurfaceView.requestLayout();
+ });
+ }
}
}
diff --git a/tests/autofillservice/res/layout/login_activity.xml b/tests/autofillservice/res/layout/login_activity.xml
index ee21a00..e39e6ae 100644
--- a/tests/autofillservice/res/layout/login_activity.xml
+++ b/tests/autofillservice/res/layout/login_activity.xml
@@ -42,6 +42,7 @@
android:maxLength="25"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:textCursorDrawable="@android:color/transparent"
android:imeOptions="flagNoFullscreen" />
</LinearLayout>
@@ -61,6 +62,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
+ android:textCursorDrawable="@android:color/transparent"
android:imeOptions="flagNoFullscreen" />
</LinearLayout>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
index e496c24..e7c0cf7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
@@ -48,13 +48,6 @@
}
/**
- * Performs a click on username.
- */
- protected void requestClickOnUsername() throws TimeoutException {
- mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::performClick));
- }
-
- /**
* Requests focus on username and expect no Window event happens.
*/
protected void requestFocusOnUsernameNoWindowChange() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
index 92821a3..200e184 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AuthenticationTest.java
@@ -692,12 +692,12 @@
? AuthenticationActivity.createSender(mContext, 1,
dataset)
: AuthenticationActivity.createSender(mContext, 1,
- dataset, newClientState("CSI", "FromIntent"));
+ dataset, Helper.newClientState("CSI", "FromIntent"));
// Configure the service behavior
sReplier.addResponse(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
- .setExtras(newClientState("CSI", "FromResponse"))
+ .setExtras(Helper.newClientState("CSI", "FromResponse"))
.addDataset(new CannedDataset.Builder()
.setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
.setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
@@ -728,13 +728,14 @@
mUiBot.updateForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
// Assert client state on authentication activity.
- assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
+ Helper.assertAuthenticationClientState("auth activity", AuthenticationActivity.getData(),
+ "CSI", "FromResponse");
// Assert client state on save request.
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
? "FromResponse" : "FromIntent";
- assertClientState("on save", saveRequest.data, "CSI", expectedValue);
+ Helper.assertAuthenticationClientState("on save", saveRequest.data, "CSI", expectedValue);
}
@Test
@@ -1066,21 +1067,23 @@
.build());
if (where == ClientStateLocation.FILL_RESPONSE_ONLY || where == ClientStateLocation.BOTH) {
- authenticatedResponseBuilder.setExtras(newClientState("CSI", "FromAuthResponse"));
+ authenticatedResponseBuilder.setExtras(
+ Helper.newClientState("CSI", "FromAuthResponse"));
}
final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
? AuthenticationActivity.createSender(mContext, 1,
- authenticatedResponseBuilder.build())
+ authenticatedResponseBuilder.build())
: AuthenticationActivity.createSender(mContext, 1,
- authenticatedResponseBuilder.build(), newClientState("CSI", "FromIntent"));
+ authenticatedResponseBuilder.build(),
+ Helper.newClientState("CSI", "FromIntent"));
// Configure the service behavior
sReplier.addResponse(new CannedFillResponse.Builder()
.setAuthentication(authentication, ID_USERNAME)
.setIgnoreFields(ID_PASSWORD)
.setPresentation(createPresentation("Tap to auth response"))
- .setExtras(newClientState("CSI", "FromResponse"))
+ .setExtras(Helper.newClientState("CSI", "FromResponse"))
.build());
// Set expectation for the activity
@@ -1108,29 +1111,14 @@
mUiBot.updateForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
// Assert client state on authentication activity.
- assertClientState("auth activity", AuthenticationActivity.getData(), "CSI", "FromResponse");
+ Helper.assertAuthenticationClientState("auth activity", AuthenticationActivity.getData(),
+ "CSI", "FromResponse");
// Assert client state on save request.
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
? "FromAuthResponse" : "FromIntent";
- assertClientState("on save", saveRequest.data, "CSI", expectedValue);
- }
-
- // TODO(on master): move to helper / reuse in other places
- private void assertClientState(String where, Bundle data, String expectedKey,
- String expectedValue) {
- assertWithMessage("no client state on %s", where).that(data).isNotNull();
- final String extraValue = data.getString(expectedKey);
- assertWithMessage("invalid value for %s on %s", expectedKey, where)
- .that(extraValue).isEqualTo(expectedValue);
- }
-
- // TODO(on master): move to helper / reuse in other places
- private Bundle newClientState(String key, String value) {
- final Bundle clientState = new Bundle();
- clientState.putString(key, value);
- return clientState;
+ Helper.assertAuthenticationClientState("on save", saveRequest.data, "CSI", expectedValue);
}
@Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 74f9fd9..aa5c29d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -1309,6 +1309,20 @@
return false;
}
+ public static Bundle newClientState(String key, String value) {
+ final Bundle clientState = new Bundle();
+ clientState.putString(key, value);
+ return clientState;
+ }
+
+ public static void assertAuthenticationClientState(String where, Bundle data,
+ String expectedKey, String expectedValue) {
+ assertWithMessage("no client state on %s", where).that(data).isNotNull();
+ final String extraValue = data.getString(expectedKey);
+ assertWithMessage("invalid value for %s on %s", expectedKey, where)
+ .that(extraValue).isEqualTo(expectedValue);
+ }
+
/**
* Asserts that 2 bitmaps have are the same. If they aren't throws an exception and dump them
* locally so their can be visually inspected.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
new file mode 100644
index 0000000..d27f6fc
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAuthenticationTest.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2020 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.autofillservice.cts.inline;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.UNUSED_AUTOFILL_VALUE;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
+import static android.autofillservice.cts.Timeouts.MOCK_IME_TIMEOUT_MS;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectBindInput;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.autofillservice.cts.AbstractLoginActivityTestCase;
+import android.autofillservice.cts.AuthenticationActivity;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.Helper;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.content.IntentSender;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.MockImeSession;
+
+import org.junit.Test;
+
+import java.util.regex.Pattern;
+
+public class InlineAuthenticationTest extends AbstractLoginActivityTestCase {
+
+ private static final String TAG = "InlineAuthenticationTest";
+
+ // TODO: move common part to the other places
+ enum ClientStateLocation {
+ INTENT_ONLY,
+ FILL_RESPONSE_ONLY,
+ BOTH
+ }
+
+ @Override
+ protected void enableService() {
+ Helper.enableAutofillService(getContext(), SERVICE_NAME);
+ }
+
+ @Test
+ public void testDatasetAuthTwoFields() throws Exception {
+ datasetAuthTwoFields(/* cancelFirstAttempt */ false);
+ }
+
+ @Test
+ @AppModeFull(reason = "testDatasetAuthTwoFields() is enough")
+ public void testDatasetAuthTwoFieldsUserCancelsFirstAttempt() throws Exception {
+ datasetAuthTwoFields(/* cancelFirstAttempt */ true);
+ }
+
+ private void datasetAuthTwoFields(boolean cancelFirstAttempt) throws Exception {
+ // Set service.
+ enableService();
+
+ final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
+ assumeTrue("MockIME not available", mockImeSession != null);
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build());
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("auth"))
+ .setInlinePresentation(createInlinePresentation("auth"))
+ .setAuthentication(authentication)
+ .build());
+ sReplier.addResponse(builder.build());
+ mActivity.expectAutoFill("dude", "sweet");
+
+ final ImeEventStream stream = mockImeSession.openEventStream();
+ mockImeSession.callRequestShowSelf(0);
+
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+
+ // Trigger auto-fill.
+ assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
+ sReplier.getNextFillRequest();
+
+ // Make sure UI is show on 2nd field as well
+ assertSuggestionShownBySelectViewId(ID_PASSWORD, /* childrenCount */ 1);
+
+ // Now tap on 1st field to show it again...
+ assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
+
+ // TODO(b/149891961): add logic for cancelFirstAttempt
+ if (cancelFirstAttempt) {
+ // Trigger the auth dialog, but emulate cancel.
+ AuthenticationActivity.setResultCode(RESULT_CANCELED);
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mUiBot.assertSuggestionStrip(1);
+
+ // Make sure it's still shown on other fields...
+ assertSuggestionShownBySelectViewId(ID_PASSWORD, /* childrenCount */ 1);
+
+ // Tap on 1st field to show it again...
+ assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
+ }
+
+ // ...and select it this time
+ AuthenticationActivity.setResultCode(RESULT_OK);
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthFilteringUsingRegex() throws Exception {
+ // Set service.
+ enableService();
+
+ final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
+ assumeTrue("MockIME not available", mockImeSession != null);
+
+ // Create the authentication intents
+ final CannedDataset unlockedDataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ unlockedDataset);
+ final Pattern min2Chars = Pattern.compile(".{2,}");
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE, min2Chars)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("auth"))
+ .setInlinePresentation(createInlinePresentation("auth"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ final ImeEventStream stream = mockImeSession.openEventStream();
+ mockImeSession.callRequestShowSelf(0);
+
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+
+ // Trigger auto-fill, make sure it's showing initially.
+ assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
+ sReplier.getNextFillRequest();
+
+ // ...then type something to hide it.
+ mActivity.onUsername((v) -> v.setText("a"));
+ // Suggestion strip was not shown.
+ mUiBot.assertNoSuggestionStripEver();
+ mUiBot.waitForIdle();
+
+ // ...now type something again to show it, as the input will have 2 chars.
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.waitForIdle();
+ mUiBot.assertSuggestionStrip(1);
+
+ // Delete the char and assert it's not shown again...
+ mActivity.onUsername((v) -> v.setText("a"));
+ mUiBot.waitForIdle();
+ mUiBot.assertNoSuggestionStripEver();
+
+ // ...then type something again to show it, as the input will have 2 chars.
+ mActivity.onUsername((v) -> v.setText("aa"));
+ mUiBot.waitForIdle();
+ mUiBot.assertSuggestionStrip(1);
+
+ // ...and select it this time
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mUiBot.assertNoSuggestionStripEver();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ }
+
+ @Test
+ public void testDatasetAuthClientStateSetOnIntentOnly() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.INTENT_ONLY);
+ }
+
+ @Test
+ @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
+ public void testDatasetAuthClientStateSetOnFillResponseOnly() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.FILL_RESPONSE_ONLY);
+ }
+
+ @Test
+ @AppModeFull(reason = "testDatasetAuthClientStateSetOnIntentOnly() is enough")
+ public void testDatasetAuthClientStateSetOnIntentAndFillResponse() throws Exception {
+ fillDatasetAuthWithClientState(ClientStateLocation.BOTH);
+ }
+
+ private void fillDatasetAuthWithClientState(ClientStateLocation where) throws Exception {
+ // Set service.
+ enableService();
+
+ final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
+ assumeTrue("MockIME not available", mockImeSession != null);
+
+ // Prepare the authenticated response
+ final CannedDataset dataset = new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .build();
+ final IntentSender authentication = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? AuthenticationActivity.createSender(mContext, 1,
+ dataset)
+ : AuthenticationActivity.createSender(mContext, 1,
+ dataset, Helper.newClientState("CSI", "FromIntent"));
+
+ // Configure the service behavior
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+ .setExtras(Helper.newClientState("CSI", "FromResponse"))
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, UNUSED_AUTOFILL_VALUE)
+ .setField(ID_PASSWORD, UNUSED_AUTOFILL_VALUE)
+ .setPresentation(createPresentation("auth"))
+ .setInlinePresentation(createInlinePresentation("auth"))
+ .setAuthentication(authentication)
+ .build())
+ .build());
+
+ // Set expectation for the activity
+ mActivity.expectAutoFill("dude", "sweet");
+
+ final ImeEventStream stream = mockImeSession.openEventStream();
+ mockImeSession.callRequestShowSelf(0);
+
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+
+ // Trigger auto-fill, make sure it's showing initially.
+ assertSuggestionShownBySelectViewId(ID_USERNAME, /* childrenCount */ 1);
+ sReplier.getNextFillRequest();
+
+ // Tap authentication request.
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+ mUiBot.waitForIdle();
+
+ // Now trigger save.
+ mActivity.onUsername((v) -> v.setText("malkovich"));
+ mUiBot.waitForIdle();
+ mActivity.onPassword((v) -> v.setText("malkovich"));
+ mUiBot.waitForIdle();
+
+
+ final String expectedMessage = getWelcomeMessage("malkovich");
+ final String actualMessage = mActivity.tapLogin();
+ mUiBot.waitForIdle();
+ assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+
+ mUiBot.updateForAutofill(/* yesDoIt */ true, SAVE_DATA_TYPE_PASSWORD);
+ mUiBot.waitForIdle();
+
+ // Assert client state on authentication activity.
+ Helper.assertAuthenticationClientState("auth activity", AuthenticationActivity.getData(),
+ "CSI", "FromResponse");
+
+ // Assert client state on save request.
+ final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ final String expectedValue = where == ClientStateLocation.FILL_RESPONSE_ONLY
+ ? "FromResponse" : "FromIntent";
+ Helper.assertAuthenticationClientState("on save", saveRequest.data, "CSI", expectedValue);
+ }
+
+ private void assertSuggestionShownBySelectViewId(String id, int childrenCount)
+ throws Exception {
+ mUiBot.selectByRelativeId(id);
+ mUiBot.waitForIdle();
+ mUiBot.assertSuggestionStrip(childrenCount);
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java
new file mode 100644
index 0000000..941ebe2
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineFillEventHistoryTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2020 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.autofillservice.cts.inline;
+
+import static android.autofillservice.cts.CannedFillResponse.DO_NOT_REPLY_RESPONSE;
+import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
+import static android.autofillservice.cts.Helper.ID_PASSWORD;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.Helper.NULL_DATASET_ID;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetAuthenticationSelected;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetSelected;
+import static android.autofillservice.cts.Helper.assertFillEventForDatasetShown;
+import static android.autofillservice.cts.Helper.assertFillEventForSaveShown;
+import static android.autofillservice.cts.Helper.assertNoDeprecatedClientState;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilConnected;
+import static android.autofillservice.cts.InstrumentedAutoFillService.waitUntilDisconnected;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.autofillservice.cts.AbstractLoginActivityTestCase;
+import android.autofillservice.cts.AuthenticationActivity;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.CannedFillResponse.CannedDataset;
+import android.autofillservice.cts.Helper;
+import android.autofillservice.cts.InstrumentedAutoFillService;
+import android.autofillservice.cts.LoginActivity;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
+import android.service.autofill.FillEventHistory;
+import android.service.autofill.FillEventHistory.Event;
+import android.support.test.uiautomator.UiObject2;
+import android.view.View;
+
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Test that uses {@link LoginActivity} to test {@link FillEventHistory}.
+ */
+@AppModeFull(reason = "Service-specific test")
+public class InlineFillEventHistoryTest extends AbstractLoginActivityTestCase {
+
+ @Override
+ protected void enableService() {
+ Helper.enableAutofillService(getContext(), SERVICE_NAME);
+ }
+
+ @Test
+ public void testNoDatasetAndSave() throws Exception {
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME)
+ .build());
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+
+ sReplier.getNextFillRequest();
+
+ // Suggestion strip was never shown.
+ mUiBot.assertNoSuggestionStripEver();
+
+ // Change username
+ mActivity.syncRunOnUiThread(() -> mActivity.onUsername((v) -> v.setText("ID")));
+ mUiBot.waitForIdle();
+
+ // Trigger save UI.
+ mActivity.tapSave();
+ mUiBot.waitForIdle();
+
+ // Confirm the save UI shown
+ final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+ // Save it...
+ mUiBot.saveForAutofill(saveUi, true);
+ mUiBot.waitForIdle();
+ sReplier.getNextSaveRequest();
+
+ // Verify save event
+ final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(1);
+ assertNoDeprecatedClientState(selection);
+ final List<Event> events = selection.getEvents();
+ assertFillEventForSaveShown(events.get(0), NULL_DATASET_ID);
+ }
+
+ @Test
+ public void testOneDatasetAndSave() throws Exception {
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_USERNAME)
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "id")
+ .setField(ID_PASSWORD, "pass")
+ .setPresentation(createPresentation("Dataset"))
+ .setInlinePresentation(createInlinePresentation("Dataset"))
+ .build())
+ .build());
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+ sReplier.getNextFillRequest();
+
+ // Suggestion strip was shown.
+ mUiBot.assertSuggestionStrip(1);
+ mUiBot.waitForIdle();
+
+ mUiBot.selectSuggestion(0);
+
+ // Change username and password
+ mActivity.syncRunOnUiThread(() -> mActivity.onUsername((v) -> v.setText("ID")));
+ mActivity.syncRunOnUiThread(() -> mActivity.onPassword((v) -> v.setText("PASS")));
+ mUiBot.waitForIdle();
+
+ // Trigger save UI.
+ mActivity.tapSave();
+ mUiBot.waitForIdle();
+
+ // Confirm the save UI shown
+ final UiObject2 saveUi = mUiBot.assertUpdateShowing(SAVE_DATA_TYPE_GENERIC);
+
+ // Save it...
+ mUiBot.saveForAutofill(saveUi, true);
+ mUiBot.waitForIdle();
+ sReplier.getNextSaveRequest();
+
+ // Verify events history
+ final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(4);
+ assertNoDeprecatedClientState(selection);
+ final List<Event> events = selection.getEvents();
+ assertFillEventForDatasetShown(events.get(0));
+ assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+ assertFillEventForDatasetShown(events.get(0));
+ assertFillEventForSaveShown(events.get(3), NULL_DATASET_ID);
+ }
+
+ @Test
+ public void testDatasetAuthenticationSelected() throws Exception {
+ enableService();
+
+ // Set up FillResponse with dataset authentication
+ Bundle clientState = new Bundle();
+ clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+ // Prepare the authenticated response
+ final IntentSender authentication = AuthenticationActivity.createSender(mContext, 1,
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dataset"))
+ .setInlinePresentation(createInlinePresentation("Dataset"))
+ .build());
+
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setId("name")
+ .setPresentation(createPresentation("authentication"))
+ .setInlinePresentation(createInlinePresentation("authentication"))
+ .setAuthentication(authentication)
+ .build())
+ .setExtras(clientState).build());
+ mActivity.expectAutoFill("dude", "sweet");
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+
+ // ...
+ sReplier.getNextFillRequest();
+ mUiBot.assertSuggestionStrip(1);
+
+ // Authenticate
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mActivity.assertAutoFilled();
+
+ // Verify fill selection
+ final List<Event> events = InstrumentedAutoFillService.getFillEvents(2);
+ assertFillEventForDatasetShown(events.get(0), "clientStateKey", "clientStateValue");
+ assertFillEventForDatasetAuthenticationSelected(events.get(1), "name",
+ "clientStateKey", "clientStateValue");
+ }
+
+ @Test
+ public void testNoEvents_whenServiceReturnsNullResponse() throws Exception {
+ enableService();
+
+ // First reset
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setPresentation(createPresentation("dataset1"))
+ .setInlinePresentation(createInlinePresentation("dataset1"))
+ .build())
+ .build());
+ mActivity.expectAutoFill("username");
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ waitUntilConnected();
+ sReplier.getNextFillRequest();
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mActivity.assertAutoFilled();
+
+ {
+ // Verify fill selection
+ final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+ assertNoDeprecatedClientState(selection);
+ final List<Event> events = selection.getEvents();
+ assertFillEventForDatasetShown(events.get(0));
+ assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+ }
+
+ // Second request
+ sReplier.addResponse(NO_RESPONSE);
+ mActivity.onPassword(View::requestFocus);
+ sReplier.getNextFillRequest();
+ mUiBot.assertNoSuggestionStripEver();
+ waitUntilDisconnected();
+
+ InstrumentedAutoFillService.assertNoFillEventHistory();
+ }
+
+ @Test
+ public void testNoEvents_whenServiceReturnsFailure() throws Exception {
+ enableService();
+
+ // First reset
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setPresentation(createPresentation("dataset1"))
+ .setInlinePresentation(createInlinePresentation("dataset1"))
+ .build())
+ .build());
+ mActivity.expectAutoFill("username");
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ waitUntilConnected();
+ sReplier.getNextFillRequest();
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mActivity.assertAutoFilled();
+
+ {
+ // Verify fill selection
+ final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+ assertNoDeprecatedClientState(selection);
+ final List<Event> events = selection.getEvents();
+ assertFillEventForDatasetShown(events.get(0));
+ assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+ }
+
+ // Second request
+ sReplier.addResponse(new CannedFillResponse.Builder().returnFailure("D'OH!").build());
+ mActivity.onPassword(View::requestFocus);
+ sReplier.getNextFillRequest();
+ mUiBot.assertNoSuggestionStripEver();
+ waitUntilDisconnected();
+
+ InstrumentedAutoFillService.assertNoFillEventHistory();
+ }
+
+ @Test
+ public void testNoEvents_whenServiceTimesout() throws Exception {
+ enableService();
+
+ // First reset
+ sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+ new CannedDataset.Builder()
+ .setField(ID_USERNAME, "username")
+ .setPresentation(createPresentation("dataset1"))
+ .setInlinePresentation(createInlinePresentation("dataset1"))
+ .build())
+ .build());
+ mActivity.expectAutoFill("username");
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ waitUntilConnected();
+ sReplier.getNextFillRequest();
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+ mActivity.assertAutoFilled();
+
+ {
+ // Verify fill selection
+ final FillEventHistory selection = InstrumentedAutoFillService.getFillEventHistory(2);
+ assertNoDeprecatedClientState(selection);
+ final List<Event> events = selection.getEvents();
+ assertFillEventForDatasetShown(events.get(0));
+ assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID);
+ }
+
+ // Second request
+ sReplier.addResponse(DO_NOT_REPLY_RESPONSE);
+ mActivity.onPassword(View::requestFocus);
+ sReplier.getNextFillRequest();
+ waitUntilDisconnected();
+
+ InstrumentedAutoFillService.assertNoFillEventHistory();
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index 39139eb..f19087d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -170,4 +170,90 @@
assertWithMessage("Password node is focused").that(
findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse();
}
+
+ @Test
+ public void testAutofill_disjointDatasets() throws Exception {
+ // Set service.
+ enableService();
+
+ final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession();
+ assumeTrue("MockIME not available", mockImeSession != null);
+
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setPresentation(createPresentation("The Username"))
+ .setInlinePresentation(createInlinePresentation("The Username"))
+ .build())
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("The Password"))
+ .setInlinePresentation(createInlinePresentation("The Password"))
+ .build())
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_PASSWORD, "lollipop")
+ .setPresentation(createPresentation("The Password2"))
+ .setInlinePresentation(createInlinePresentation("The Password2"))
+ .build());
+
+ sReplier.addResponse(builder.build());
+ mActivity.expectAutoFill("dude");
+
+ final ImeEventStream stream = mockImeSession.openEventStream();
+
+ // Wait until the MockIme gets bound to the TestActivity.
+ expectBindInput(stream, Process.myPid(), MOCK_IME_TIMEOUT_MS);
+
+ // Wait until IME is displaying.
+ mockImeSession.callRequestShowSelf(0);
+ expectEvent(stream, event -> "showSoftInput".equals(event.getEventName()),
+ MOCK_IME_TIMEOUT_MS);
+ expectEvent(stream, event -> "onStartInputView".equals(event.getEventName()),
+ MOCK_IME_TIMEOUT_MS);
+
+ // Trigger auto-fill.
+ requestFocusOnUsername();
+ expectEvent(stream, editorMatcher("onStartInput", mActivity.getUsername().getId()),
+ MOCK_IME_TIMEOUT_MS);
+
+ // Wait until suggestion strip is updated
+ expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
+ MOCK_IME_TIMEOUT_MS);
+
+ mUiBot.assertNoDatasetsEver();
+
+ mUiBot.assertSuggestionStrip(1);
+
+ // Switch focus to password
+ requestFocusOnPassword();
+ expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
+ MOCK_IME_TIMEOUT_MS);
+
+ mUiBot.assertSuggestionStrip(2);
+
+ // Switch focus back to username
+ requestFocusOnUsername();
+ expectEvent(stream, event -> "onSuggestionViewUpdated".equals(event.getEventName()),
+ MOCK_IME_TIMEOUT_MS);
+
+ mUiBot.assertSuggestionStrip(1);
+ mUiBot.selectSuggestion(0);
+
+ // Check the results.
+ mActivity.assertAutoFilled();
+
+ // Make sure input was sanitized.
+ final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest();
+ assertWithMessage("CancelationSignal is null").that(request.cancellationSignal).isNotNull();
+ assertTextIsSanitized(request.structure, ID_PASSWORD);
+ final FillContext fillContext = request.contexts.get(request.contexts.size() - 1);
+ assertThat(fillContext.getFocusedId())
+ .isEqualTo(findAutofillIdByResourceId(fillContext, ID_USERNAME));
+
+ // Make sure initial focus was properly set.
+ assertWithMessage("Username node is not focused").that(
+ findNodeByResourceId(request.structure, ID_USERNAME).isFocused()).isTrue();
+ assertWithMessage("Password node is focused").that(
+ findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse();
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java
new file mode 100644
index 0000000..17bcc2f
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineSimpleSaveActivityTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 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.autofillservice.cts.inline;
+
+import static android.autofillservice.cts.Helper.assertTextAndValue;
+import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.autofillservice.cts.Helper.getContext;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_COMMIT;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_INPUT;
+import static android.autofillservice.cts.SimpleSaveActivity.ID_PASSWORD;
+import static android.autofillservice.cts.inline.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import android.autofillservice.cts.AutoFillServiceTestCase;
+import android.autofillservice.cts.AutofillActivityTestRule;
+import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.Helper;
+import android.autofillservice.cts.InstrumentedAutoFillService;
+import android.autofillservice.cts.SimpleSaveActivity;
+import android.support.test.uiautomator.UiObject2;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+
+public class InlineSimpleSaveActivityTest
+ extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
+
+ private static final String TAG = "InlineSimpleSaveActivityTest";
+ protected SimpleSaveActivity mActivity;
+
+ @Override
+ protected void enableService() {
+ Helper.enableAutofillService(getContext(), SERVICE_NAME);
+ }
+
+ @NonNull
+ @Override
+ protected AutofillActivityTestRule<SimpleSaveActivity> getActivityRule() {
+ return new AutofillActivityTestRule<SimpleSaveActivity>(SimpleSaveActivity.class) {
+ @Override
+ protected void afterActivityLaunched() {
+ mActivity = getActivity();
+ }
+ };
+ }
+
+ @Test
+ public void testAutofillSave() throws Exception {
+ // Set service.
+ enableService();
+
+ // Set expectations.
+ sReplier.addResponse(new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT)
+ .build());
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_INPUT);
+ mUiBot.waitForIdle();
+
+ sReplier.getNextFillRequest();
+
+ // Suggestion strip was never shown.
+ mUiBot.assertNoSuggestionStripEver();
+
+ // Change input
+ mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID"));
+ mUiBot.waitForIdle();
+
+ // Trigger save UI.
+ mUiBot.selectByRelativeId(ID_COMMIT);
+ mUiBot.waitForIdle();
+
+ // Confirm the save UI shown
+ final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
+
+ // Save it...
+ mUiBot.saveForAutofill(saveUi, true);
+
+ // ... and assert results
+ final InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "ID");
+ }
+
+ @Test
+ public void testAutofill_oneDatasetAndSave() throws Exception {
+ // Set service.
+ enableService();
+
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT, ID_PASSWORD)
+ .addDataset(new CannedFillResponse.CannedDataset.Builder()
+ .setField(ID_INPUT, "id")
+ .setField(ID_PASSWORD, "pass")
+ .setPresentation(createPresentation("YO"))
+ .setInlinePresentation(createInlinePresentation("YO"))
+ .build());
+ sReplier.addResponse(builder.build());
+ mActivity.expectAutoFill("id", "pass");
+
+ // Trigger auto-fill and IME.
+ mUiBot.selectByRelativeId(ID_INPUT);
+ mUiBot.waitForIdle();
+
+ sReplier.getNextFillRequest();
+
+ // Confirm one suggestion
+ mUiBot.assertSuggestionStrip(1);
+
+ // Select suggestion
+ mUiBot.selectSuggestion(0);
+ mUiBot.waitForIdle();
+
+ // Check the results.
+ mActivity.expectAutoFill("id", "pass");
+
+ // Change input
+ mActivity.syncRunOnUiThread(() -> mActivity.getInput().setText("ID"));
+ mUiBot.waitForIdle();
+
+ // Trigger save UI.
+ mUiBot.selectByRelativeId(ID_COMMIT);
+ mUiBot.waitForIdle();
+
+ // Confirm the save UI shown
+ final UiObject2 saveUi = mUiBot.assertUpdateShowing(SAVE_DATA_TYPE_GENERIC);
+
+ // Save it...
+ mUiBot.saveForAutofill(saveUi, true);
+
+ // ... and assert results
+ final InstrumentedAutoFillService.SaveRequest saveRequest = sReplier.getNextSaveRequest();
+ assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "ID");
+ assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_PASSWORD), "pass");
+ }
+}
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index f6113bf..507859b 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -477,6 +477,16 @@
</meta-data>
</service>
+ <service
+ android:name=".TestDream"
+ android:exported="true"
+ android:permission="android.permission.BIND_DREAM_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
<!-- Disable home activities by default or it may disturb other tests by
showing ResolverActivity when start home activity -->
<activity-alias android:name=".HomeActivity"
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 300398d..6751a1a 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -204,6 +204,9 @@
public static final ComponentName POPUP_MPP_ACTIVITY =
component("PopupMinimalPostProcessingActivity");
+ public static final ComponentName TEST_DREAM_SERVICE =
+ component("TestDream");
+
/**
* Action and extra key constants for {@link #INPUT_METHOD_TEST_ACTIVITY}.
*/
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/TestDream.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/TestDream.java
new file mode 100644
index 0000000..3a6cca0
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/TestDream.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.wm.app;
+
+import android.service.dreams.DreamService;
+
+public class TestDream extends DreamService {
+}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json b/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json
deleted file mode 100644
index 78fe375..0000000
--- a/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "setup": {
- "initialIntents": [
- {
- "flags": "FLAG_ACTIVITY_NEW_TASK",
- "class": "android.server.wm.intent.Activities$TaskAffinity1Activity",
- "package": "android.server.wm.cts",
- "startForResult": false
- }
- ],
- "act": [
- {
- "flags": "",
- "class": "android.server.wm.intent.Activities$SingleInstanceActivity",
- "package": "android.server.wm.cts",
- "startForResult": true
- }
- ]
- },
- "initialState": {
- "stacks": [
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
- }
- ]
- },
- "endState": {
- "stacks": [
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
- },
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
- "state": "STOPPED"
- }
- ]
- }
- ]
- }
- ]
- }
-}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json b/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json
deleted file mode 100644
index a288a9e..0000000
--- a/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "setup": {
- "initialIntents": [
- {
- "flags": "FLAG_ACTIVITY_NEW_TASK",
- "class": "android.server.wm.intent.Activities$SingleTopActivity",
- "package": "android.server.wm.cts",
- "startForResult": false
- }
- ],
- "act": [
- {
- "flags": "",
- "class": "android.server.wm.intent.Activities$SingleTopActivity",
- "package": "android.server.wm.cts",
- "startForResult": true
- }
- ]
- },
- "initialState": {
- "stacks": [
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
- }
- ]
- },
- "endState": {
- "stacks": [
- {
- "tasks": [
- {
- "activities": [
- {
- "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
- "state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
- }
- ]
- }
-}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
index a80e56b..6e97377 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
@@ -43,6 +43,10 @@
{
"name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
"state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
+ "state": "STOPPED"
}
]
}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
index a288a9e..2ed6023 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
@@ -43,6 +43,10 @@
{
"name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
"state": "RESUMED"
+ },
+ {
+ "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
+ "state": "STOPPED"
}
]
}
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
index be49412..33419d6 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
@@ -43,23 +43,15 @@
{
"name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
"state": "RESUMED"
- }
- ]
- }
- ],
- "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
- },
- {
- "tasks": [
- {
- "activities": [
+ },
{
"name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
"state": "STOPPED"
}
]
}
- ]
+ ],
+ "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
}
]
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
index 915bb8d..49ef515 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
@@ -27,6 +27,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.greaterThan;
@@ -79,7 +80,10 @@
@Presubmit
@android.server.wm.annotation.Group3
public class DisplayCutoutTests {
- static final Rect ZERO_RECT = new Rect();
+ static final String LEFT = "left";
+ static final String TOP = "top";
+ static final String RIGHT = "right";
+ static final String BOTTOM = "bottom";
@Rule
public final ErrorCollector mErrorCollector = new ErrorCollector();
@@ -164,8 +168,12 @@
public void testDisplayCutout_shortEdges_portrait() {
runTest(LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, (a, insets, displayCutout, which) -> {
if (which == ROOT) {
- assertThat("Display.getCutout() must equal view root cutout",
- a.getDisplay().getCutout(), equalTo(displayCutout));
+ assertThat("cutout is either null or the short edge insets must be equal to "
+ + "those of the Display.getCutout() and the long edge "
+ + "side insets must be 0",
+ safeInsets(displayCutout),
+ anyOf(is(nullValue()), onlyHasShortEdgeInsetsAndEqualsTo(
+ safeInsets(a.getDisplay().getCutout()))));
}
});
}
@@ -200,29 +208,26 @@
final DisplayCutout displayCutout = insets.getDisplayCutout();
final DisplayCutout dispatchedDisplayCutout = dispatchedInsets.getDisplayCutout();
if (displayCutout != null) {
- commonAsserts(activity, insets, displayCutout);
+ commonAsserts(activity, displayCutout);
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
shortEdgeAsserts(activity, insets, displayCutout);
}
- assertCutoutsAreConsistentWithInsets(displayCutout);
+ assertCutoutsAreConsistentWithInsets(activity, displayCutout);
}
test.run(activity, insets, displayCutout, ROOT);
if (dispatchedDisplayCutout != null) {
- commonAsserts(activity, dispatchedInsets, dispatchedDisplayCutout);
+ commonAsserts(activity, dispatchedDisplayCutout);
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
shortEdgeAsserts(activity, insets, displayCutout);
}
- assertCutoutsAreConsistentWithInsets(dispatchedDisplayCutout);
+ assertCutoutsAreConsistentWithInsets(activity, dispatchedDisplayCutout);
}
test.run(activity, dispatchedInsets, dispatchedDisplayCutout, DISPATCHED);
}
- private void commonAsserts(TestActivity activity, WindowInsets insets, DisplayCutout cutout) {
+ private void commonAsserts(TestActivity activity, DisplayCutout cutout) {
assertSafeInsetsValid(cutout);
- assertThat("systemWindowInsets (also known as content insets) must be at least as large as "
- + "cutout safe insets",
- safeInsets(cutout), insetsLessThanOrEqualTo(systemWindowInsets(insets)));
assertCutoutsAreWithinSafeInsets(activity, cutout);
assertBoundsAreNonEmpty(cutout);
assertAtMostOneCutoutPerEdge(activity, cutout);
@@ -231,26 +236,29 @@
private void shortEdgeAsserts(
TestActivity activity, WindowInsets insets, DisplayCutout cutout) {
assertOnlyShortEdgeHasInsets(activity, cutout);
- assertOnlyShortEdgeHasBounds(activity, insets, cutout);
+ assertOnlyShortEdgeHasBounds(activity, cutout);
+ assertThat("systemWindowInsets (also known as content insets) must be at least as "
+ + "large as cutout safe insets",
+ safeInsets(cutout), insetsLessThanOrEqualTo(systemWindowInsets(insets)));
}
- private void assertCutoutIsConsistentWithInset(String position, int insetSize, Rect bound) {
- if (insetSize > 0) {
- assertThat("cutout must have a bound on the " + position, bound,
- not(equalTo(ZERO_RECT)));
+ private void assertCutoutIsConsistentWithInset(String position, DisplayCutout cutout,
+ int safeInsetSize, Rect appBound) {
+ if (safeInsetSize > 0) {
+ assertThat("cutout must have a bound on the " + position,
+ hasBound(position, cutout, appBound), is(true));
} else {
- assertThat("cutout must have no bound on the " + position, bound,
- equalTo(ZERO_RECT));
+ assertThat("cutout must have no bound on the " + position,
+ hasBound(position, cutout, appBound), is(false));
}
}
- public void assertCutoutsAreConsistentWithInsets(DisplayCutout cutout) {
- final Rect safeInsets = safeInsets(cutout);
- assertCutoutIsConsistentWithInset("top", safeInsets.top, cutout.getBoundingRectTop());
- assertCutoutIsConsistentWithInset("bottom", safeInsets.bottom,
- cutout.getBoundingRectBottom());
- assertCutoutIsConsistentWithInset("left", safeInsets.left, cutout.getBoundingRectLeft());
- assertCutoutIsConsistentWithInset("right", safeInsets.right, cutout.getBoundingRectRight());
+ public void assertCutoutsAreConsistentWithInsets(TestActivity activity, DisplayCutout cutout) {
+ final Rect appBounds = getAppBounds(activity);
+ assertCutoutIsConsistentWithInset(TOP, cutout, cutout.getSafeInsetTop(), appBounds);
+ assertCutoutIsConsistentWithInset(BOTTOM, cutout, cutout.getSafeInsetBottom(), appBounds);
+ assertCutoutIsConsistentWithInset(LEFT, cutout, cutout.getSafeInsetLeft(), appBounds);
+ assertCutoutIsConsistentWithInset(RIGHT, cutout, cutout.getSafeInsetRight(), appBounds);
}
private void assertSafeInsetsValid(DisplayCutout displayCutout) {
@@ -312,32 +320,55 @@
}
}
- private void assertOnlyShortEdgeHasBounds(TestActivity activity, WindowInsets insets,
- DisplayCutout cutout) {
+ private void assertOnlyShortEdgeHasBounds(TestActivity activity, DisplayCutout cutout) {
final Point displaySize = new Point();
runOnMainSync(() -> activity.getDecorView().getDisplay().getRealSize(displaySize));
+ final Rect appBounds = getAppBounds(activity);
if (displaySize.y > displaySize.x) {
// Portrait display
assertThat("left edge has a cutout despite being long edge",
- cutout.getBoundingRectLeft(), is(ZERO_RECT));
+ hasBound(LEFT, cutout, appBounds), is(false));
+
assertThat("right edge has a cutout despite being long edge",
- cutout.getBoundingRectRight(), is(ZERO_RECT));
+ hasBound(RIGHT, cutout, appBounds), is(false));
}
if (displaySize.y < displaySize.x) {
// Landscape display
assertThat("top edge has a cutout despite being long edge",
- cutout.getBoundingRectTop(), is(ZERO_RECT));
+ hasBound(TOP, cutout, appBounds), is(false));
+
assertThat("bottom edge has a cutout despite being long edge",
- cutout.getBoundingRectBottom(), is(ZERO_RECT));
+ hasBound(BOTTOM, cutout, appBounds), is(false));
}
}
+ private boolean hasBound(String position, DisplayCutout cutout, Rect appBound) {
+ final Rect cutoutRect;
+ final int waterfallSize;
+ if (LEFT.equals(position)) {
+ cutoutRect = cutout.getBoundingRectLeft();
+ waterfallSize = cutout.getWaterfallInsets().left;
+ } else if (TOP.equals(position)) {
+ cutoutRect = cutout.getBoundingRectTop();
+ waterfallSize = cutout.getWaterfallInsets().top;
+ } else if (RIGHT.equals(position)) {
+ cutoutRect = cutout.getBoundingRectRight();
+ waterfallSize = cutout.getWaterfallInsets().right;
+ } else {
+ cutoutRect = cutout.getBoundingRectBottom();
+ waterfallSize = cutout.getWaterfallInsets().bottom;
+ }
+ return Rect.intersects(cutoutRect, appBound) || waterfallSize > 0;
+ }
+
private List<Rect> boundsWith(DisplayCutout cutout, Predicate<Rect> predicate) {
return cutout.getBoundingRects().stream().filter(predicate).collect(Collectors.toList());
}
-
private static Rect safeInsets(DisplayCutout displayCutout) {
+ if (displayCutout == null) {
+ return null;
+ }
return new Rect(displayCutout.getSafeInsetLeft(), displayCutout.getSafeInsetTop(),
displayCutout.getSafeInsetRight(), displayCutout.getSafeInsetBottom());
}
@@ -359,6 +390,15 @@
return safeRect;
}
+ private Rect getAppBounds(TestActivity a) {
+ final Rect appBounds = new Rect();
+ runOnMainSync(() -> {
+ appBounds.right = a.getDecorView().getWidth();
+ appBounds.bottom = a.getDecorView().getHeight();
+ });
+ return appBounds;
+ }
+
private static Matcher<Rect> insetsLessThanOrEqualTo(Rect max) {
return new CustomTypeSafeMatcher<Rect>("must be smaller on each side than " + max) {
@Override
@@ -369,6 +409,18 @@
};
}
+ private static Matcher<Rect> onlyHasShortEdgeInsetsAndEqualsTo(Rect expect) {
+ return new CustomTypeSafeMatcher<Rect>(
+ "must be 0 on long edge insets and equal on short edge insets to "
+ + expect) {
+ @Override
+ protected boolean matchesSafely(Rect actual) {
+ return actual != null && actual.left == 0 && actual.top == expect.top
+ && actual.right == 0 && actual.bottom == expect.bottom;
+ }
+ };
+ }
+
private static Matcher<Rect> intersectsWith(Rect safeRect) {
return new CustomTypeSafeMatcher<Rect>("intersects with " + safeRect) {
@Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
new file mode 100644
index 0000000..78ef876
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.wm;
+
+import static android.server.wm.app.Components.TEST_DREAM_SERVICE;
+
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.FlakyTest;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.Test;
+
+@Presubmit
+@FlakyTest(detail = "Promote once confirmed non-flaky")
+public class DreamManagerServiceTests extends ActivityManagerTestBase {
+
+ private static final ComponentName DREAM_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(TEST_DREAM_SERVICE.getPackageName(),
+ "android.service.dreams.DreamActivity");
+
+ private void startDream(ComponentName name) {
+ DreamManager dreamer = mContext.getSystemService(DreamManager.class);
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ dreamer.startDream(name);
+ });
+ }
+
+ private void stopDream() {
+ DreamManager dreamer = mContext.getSystemService(DreamManager.class);
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ dreamer.stopDream();
+ });
+ }
+
+ private void setActiveDream(ComponentName dream) {
+ DreamManager dreamer = mContext.getSystemService(DreamManager.class);
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ dreamer.setActiveDream(dream);
+ });
+ }
+
+ @Test
+ public void testStartAndStopDream() throws Exception {
+ setActiveDream(TEST_DREAM_SERVICE);
+
+ startDream(TEST_DREAM_SERVICE);
+ mWmState.waitForValidState(DREAM_ACTIVITY_COMPONENT_NAME);
+ mWmState.assertVisibility(DREAM_ACTIVITY_COMPONENT_NAME, true);
+ mWmState.assertHomeActivityVisible(false);
+
+ stopDream();
+ mWmState.waitAndAssertActivityRemoved(DREAM_ACTIVITY_COMPONENT_NAME);
+
+ mWmState.assertHomeActivityVisible(true);
+ }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index c454c84..5121a39 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -292,7 +292,6 @@
* Tests launching a single instance home activity on virtual display with system decoration
* support.
*/
- @FlakyTest(bugId = 149070587)
@Test
public void testLaunchSingleHomeActivityOnDisplayWithDecorations() {
createManagedHomeActivitySession(SINGLE_HOME_ACTIVITY);
@@ -316,7 +315,6 @@
* Tests launching a single instance home activity with SECONDARY_HOME on virtual display with
* system decoration support.
*/
- @FlakyTest(bugId = 149070587)
@Test
public void testLaunchSingleSecondaryHomeActivityOnDisplayWithDecorations() {
createManagedHomeActivitySession(SINGLE_SECONDARY_HOME_ACTIVITY);
@@ -340,7 +338,6 @@
* Tests launching a multi-instance home activity on virtual display with system decoration
* support.
*/
- @FlakyTest(bugId = 149070587)
@Test
public void testLaunchHomeActivityOnDisplayWithDecorations() {
createManagedHomeActivitySession(HOME_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index 998f553..0b44b01 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -24,11 +24,11 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
-import static android.server.wm.WindowManagerState.STATE_RESUMED;
-import static android.server.wm.WindowManagerState.STATE_STOPPED;
import static android.server.wm.ComponentNameUtils.getActivityName;
import static android.server.wm.ComponentNameUtils.getWindowName;
import static android.server.wm.UiDeviceUtils.pressWindowButton;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.WindowManagerState.STATE_STOPPED;
import static android.server.wm.app.Components.ALWAYS_FOCUSABLE_PIP_ACTIVITY;
import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
import static android.server.wm.app.Components.LAUNCH_ENTER_PIP_ACTIVITY;
@@ -88,10 +88,10 @@
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
-import android.server.wm.WindowManagerState.ActivityTask;
import android.server.wm.CommandSession.ActivityCallback;
import android.server.wm.CommandSession.SizeInfo;
import android.server.wm.TestJournalProvider.TestJournalContainer;
+import android.server.wm.WindowManagerState.ActivityTask;
import android.server.wm.settings.SettingsSession;
import android.util.Log;
import android.util.Size;
@@ -109,7 +109,6 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
/**
* Build/Install/Run:
@@ -210,46 +209,6 @@
mWmState.assertVisibility(PIP_ACTIVITY, true);
}
- private void waitForValidPinnedStackBounds(Function<WindowManagerState, Rect> boundsFunc) {
- mWmState.waitForWithAmState(wmState -> {
- final Rect bounds = boundsFunc.apply(wmState);
- final Rect displayStableBounds = wmState.getStableBounds();
- return bounds.width() > 0 && bounds.height() > 0
- && displayStableBounds.contains(bounds);
- }, "valid pinned stack bounds");
- }
-
- @Test
- public void testPinnedStackOutOfBoundsInsetsNonNegative() throws Exception {
- final WindowManagerState wmState = mWmState;
-
- // Launch an activity into the pinned stack
- launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true",
- EXTRA_TAP_TO_FINISH, "true");
- // Wait for animation complete since we are comparing bounds
- waitForEnterPipAnimationComplete(PIP_ACTIVITY);
-
- // Get the display dimensions
- WindowManagerState.WindowState windowState = getWindowState(PIP_ACTIVITY);
- WindowManagerState.DisplayContent display =
- wmState.getDisplay(windowState.getDisplayId());
- Rect displayRect = display.getDisplayRect();
-
- // Move the pinned stack offscreen
- final int stackId = getPinnedStack().mRootTaskId;
- final int top = 0;
- final int left = displayRect.width() - 200;
- resizePinnedStack(stackId, left, top, left + 500, top + 500);
-
- // Ensure that the surface insets are not negative
- windowState = getWindowState(PIP_ACTIVITY);
- Rect contentInsets = windowState.getContentInsets();
- if (contentInsets != null) {
- assertTrue(contentInsets.left >= 0 && contentInsets.top >= 0
- && contentInsets.width() >= 0 && contentInsets.height() >= 0);
- }
- }
-
@Test
public void testPinnedStackInBoundsAfterRotation() {
// Launch an activity into the pinned stack
@@ -299,6 +258,9 @@
}
private void testEnterPipAspectRatio(int num, int denom) throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
launchActivity(PIP_ACTIVITY,
EXTRA_ENTER_PIP, "true",
EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
@@ -324,6 +286,9 @@
}
private void testResizePipAspectRatio(int num, int denom) throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
launchActivity(PIP_ACTIVITY,
EXTRA_ENTER_PIP, "true",
EXTRA_SET_ASPECT_RATIO_NUMERATOR, Integer.toString(num),
@@ -349,6 +314,9 @@
}
private void testEnterPipExtremeAspectRatio(int num, int denom) throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
// Assert that we could not create a pinned stack with an extreme aspect ratio
launchActivity(PIP_ACTIVITY,
EXTRA_ENTER_PIP, "true",
@@ -370,6 +338,9 @@
}
private void testSetPipExtremeAspectRatio(int num, int denom) throws Exception {
+ // Launch a test activity so that we're not over home
+ launchActivity(TEST_ACTIVITY);
+
// Try to resize the a normal pinned stack to an extreme aspect ratio and ensure that
// fails (the aspect ratio remains the same)
launchActivity(PIP_ACTIVITY,
@@ -882,6 +853,7 @@
}
}
+ @Ignore("b/149946388")
@Test
public void testEnterPipInterruptedCallbacks() {
final TransitionAnimationScaleSession transitionAnimationScaleSession =
@@ -1018,18 +990,13 @@
waitForEnterPip(PIP_ACTIVITY);
assertPinnedStackExists();
ActivityTask stack = mWmState.getStandardStackByWindowingMode(WINDOWING_MODE_PINNED);
- int stackId = stack.mRootTaskId;
int taskId = stack.getTopTask().mTaskId;
// Launch task overlay activity into PiP activity task
launchPinnedActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId);
- // Finish the task overlay activity while animating and ensure that the PiP activity never
- // got resumed.
+ // Finish the task overlay activity and ensure that the PiP activity never got resumed.
separateTestJournal();
- SystemUtil.runWithShellPermissionIdentity(
- () -> mAtm.resizePinnedStack(stackId, new Rect(20, 20, 500, 500),
- true /* animate */));
mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF);
mWmState.waitFor((amState) ->
!amState.containsActivity(TRANSLUCENT_TEST_ACTIVITY),
@@ -1287,13 +1254,24 @@
/**
* Waits until the picture-in-picture animation has finished.
+ * TODO(b/149947030): use the transition completed signal from TaskOrganizer
*/
private void waitForEnterPipAnimationComplete(ComponentName activityName) {
waitForEnterPip(activityName);
- mWmState.waitFor((amState) -> {
- ActivityTask stack = amState.getStandardRootTaskByWindowingMode(WINDOWING_MODE_PINNED);
- return stack != null && !stack.mAnimatingBounds;
- }, "pinned stack bounds animation to finish");
+ final Rect pinnedStackBounds = new Rect();
+ mWmState.waitForWithAmState(wmState -> {
+ final Rect displayStableBounds = wmState.getStableBounds();
+ Rect newBounds = wmState.getStandardStackByWindowingMode(WINDOWING_MODE_PINNED)
+ .getBounds();
+ if (pinnedStackBounds.equals(newBounds)
+ && (displayStableBounds.width() / 2) > newBounds.width()
+ && (displayStableBounds.height() / 2) > newBounds.height()) {
+ return true;
+ } else if (newBounds != null) {
+ pinnedStackBounds.set(newBounds);
+ }
+ return false;
+ }, "stack bounds stabilized, consider in pinned mode");
}
/**
@@ -1307,12 +1285,28 @@
/**
* Waits until the picture-in-picture animation to fullscreen has finished.
+ * TODO(b/149947030): use the transition completed signal from TaskOrganizer
*/
private void waitForExitPipToFullscreen(ComponentName activityName) {
mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
.setActivityType(ACTIVITY_TYPE_STANDARD)
.build());
+ final Rect stackBounds = new Rect();
+ mWmState.waitForWithAmState(wmState -> {
+ final Rect displayStableBounds = wmState.getStableBounds();
+ final ActivityTask task = wmState.getTaskByActivity(activityName);
+ if (task == null) return false;
+ Rect newBounds = task.getBounds();
+ if (stackBounds.equals(newBounds)
+ && (displayStableBounds.width() / 2) < newBounds.width()
+ && (displayStableBounds.height() / 2) < newBounds.height()) {
+ return true;
+ } else if (newBounds != null) {
+ stackBounds.set(newBounds);
+ }
+ return false;
+ }, "stack bounds stabilized, consider in fullscreen mode");
}
/**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index f6646b4..c0bf81f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -410,119 +410,6 @@
}
}
- @Test
- public void testMinimizedFromEachDockedSide() {
- final RotationSession rotationSession = createManagedRotationSession();
- for (int i = 0; i < 2; i++) {
- rotationSession.set(i);
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
- if (!mWmState.isScreenPortrait() && isTablet()) {
- // Test minimize to the right only on tablets in landscape
- removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY,
- SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
- }
- removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
- }
- }
-
- @Test
- public void testRotationWhileDockMinimized() {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
-
- // Rotate device single steps (90°) 0-1-2-3.
- // Each time we compute the state we implicitly assert valid bounds in minimized mode.
- final RotationSession rotationSession = createManagedRotationSession();
- for (int i = 0; i < 4; i++) {
- rotationSession.set(i);
- mWmState.computeState(TEST_ACTIVITY);
- }
-
- // Double steps (180°) We ended the single step at 3. So, we jump directly to 1 for
- // double step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side in
- // minimized mode.
- rotationSession.set(ROTATION_90);
- mWmState.computeState(TEST_ACTIVITY);
- rotationSession.set(ROTATION_270);
- mWmState.computeState(TEST_ACTIVITY);
- rotationSession.set(ROTATION_0);
- mWmState.computeState(TEST_ACTIVITY);
- rotationSession.set(ROTATION_180);
- mWmState.computeState(TEST_ACTIVITY);
- rotationSession.set(ROTATION_0);
- mWmState.computeState(TEST_ACTIVITY);
- }
-
- @Test
- public void testMinimizeAndUnminimizeThenGoingHome() {
- // Rotate the screen to check that minimize, unminimize, dismiss the docked stack and then
- // going home has the correct app transition
- final RotationSession rotationSession = createManagedRotationSession();
- for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
- launchActivityInDockStackAndMinimize(DOCKED_ACTIVITY);
- // Set rotation after docked stack exists so the display can be rotated (home may
- // be fixed-orientation if it is fullscreen).
- rotationSession.set(rotation);
-
- if (mIsHomeRecentsComponent) {
- launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- } else {
- // Unminimize the docked stack
- pressAppSwitchButtonAndWaitForRecents();
- waitForDockNotMinimized();
- assertDockNotMinimized();
- }
-
- // Dismiss the dock stack
- setActivityTaskWindowingMode(DOCKED_ACTIVITY,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- mWmState.computeState(DOCKED_ACTIVITY);
-
- // Go home and check the app transition
- assertNotEquals(TRANSIT_WALLPAPER_OPEN,
- mWmState.getDefaultDisplayLastTransition());
- launchHomeActivity();
- mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
-
- assertEquals(TRANSIT_WALLPAPER_OPEN,
- mWmState.getDefaultDisplayLastTransition());
- }
- }
-
- @Test
- public void testDockedStackToMinimizeWhenUnlocked() {
- if (!mIsHomeRecentsComponent) {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
- } else {
- launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
- }
- mWmState.computeState(TEST_ACTIVITY);
- createManagedLockScreenSession().sleepDevice()
- .wakeUpDevice()
- .unlockDevice();
- mWmState.computeState(TEST_ACTIVITY);
- assertDockMinimized();
- }
-
- @Test
- public void testMinimizedStateWhenUnlockedAndUnMinimized() {
- launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
-
- createManagedLockScreenSession().sleepDevice()
- .wakeUpDevice()
- .unlockDevice();
- mWmState.computeState(TEST_ACTIVITY);
-
- // Unminimized back to splitscreen
- if (mIsHomeRecentsComponent) {
- launchActivity(RESIZEABLE_ACTIVITY,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
- } else {
- pressAppSwitchButtonAndWaitForRecents();
- }
- mWmState.computeState(TEST_ACTIVITY);
- }
-
/**
* Verify split screen mode visibility after stack resize occurs.
*/
@@ -651,42 +538,4 @@
assertThat("Recents stack should be on top of home stack",
recentsStackIndex, lessThan(homeStackIndex));
}
-
- private void launchActivityInDockStackAndMinimize(ComponentName activityName) {
- launchActivityInDockStackAndMinimize(activityName, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
- }
-
- private void launchActivityInDockStackAndMinimize(ComponentName activityName, int createMode) {
- launchActivityInSplitScreenWithRecents(activityName, createMode);
- launchHomeActivityNoWait();
- waitForAndAssertDockMinimized(activityName);
- }
-
- private void assertDockMinimized() {
- assertTrue(mWmState.isDockedStackMinimized());
- }
-
- private void waitForAndAssertDockMinimized(ComponentName activityName) {
- waitForDockMinimized();
- assertDockMinimized();
- mWmState.computeState(activityName);
- mWmState.assertContainsStack("Must contain docked stack.",
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
- mWmState.assertFocusedStack("Home activity should be focused in minimized mode",
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME);
- }
-
- private void assertDockNotMinimized() {
- assertFalse(mWmState.isDockedStackMinimized());
- }
-
- private void waitForDockMinimized() {
- mWmState.waitForWithAmState(state -> state.isDockedStackMinimized(),
- "Dock stack to be minimized");
- }
-
- private void waitForDockNotMinimized() {
- mWmState.waitForWithAmState(state -> !state.isDockedStackMinimized(),
- "Dock stack to not be minimized");
- }
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
index e4cb869..9ba003c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
@@ -17,7 +17,6 @@
package android.server.wm.intent;
import android.app.Activity;
-import android.os.Bundle;
/**
* A collection of activities with various launch modes used in the intent tests.
@@ -28,68 +27,60 @@
*/
public class Activities {
- private static class BaseActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setTitle(getClass().getSimpleName());
- }
+ public static class TrackerActivity extends Activity {
}
- public static class TrackerActivity extends BaseActivity {
+ public static class RegularActivity extends Activity {
}
- public static class RegularActivity extends BaseActivity {
+ public static class SingleTopActivity extends Activity {
}
- public static class SingleTopActivity extends BaseActivity {
+ public static class SingleInstanceActivity extends Activity {
}
- public static class SingleInstanceActivity extends BaseActivity {
+ public static class SingleInstanceActivity2 extends Activity {
}
- public static class SingleInstanceActivity2 extends BaseActivity {
+ public static class SingleTaskActivity extends Activity {
}
- public static class SingleTaskActivity extends BaseActivity {
+ public static class SingleTaskActivity2 extends Activity {
}
- public static class SingleTaskActivity2 extends BaseActivity {
+ public static class TaskAffinity1Activity extends Activity {
}
- public static class TaskAffinity1Activity extends BaseActivity {
+ public static class TaskAffinity1Activity2 extends Activity {
}
- public static class TaskAffinity1Activity2 extends BaseActivity {
+ public static class TaskAffinity2Activity extends Activity {
}
- public static class TaskAffinity2Activity extends BaseActivity {
+ public static class TaskAffinity3Activity extends Activity {
}
- public static class TaskAffinity3Activity extends BaseActivity {
+ public static class ClearTaskOnLaunchActivity extends Activity {
}
- public static class ClearTaskOnLaunchActivity extends BaseActivity {
+ public static class DocumentLaunchIntoActivity extends Activity {
}
- public static class DocumentLaunchIntoActivity extends BaseActivity {
+ public static class DocumentLaunchAlwaysActivity extends Activity {
}
- public static class DocumentLaunchAlwaysActivity extends BaseActivity {
+ public static class DocumentLaunchNeverActivity extends Activity {
}
- public static class DocumentLaunchNeverActivity extends BaseActivity {
+ public static class NoHistoryActivity extends Activity {
}
- public static class NoHistoryActivity extends BaseActivity {
+ public static class LauncherActivity extends Activity {
}
- public static class LauncherActivity extends BaseActivity {
+ public static class RelinquishTaskIdentityActivity extends Activity {
}
- public static class RelinquishTaskIdentityActivity extends BaseActivity {
- }
-
- public static class TaskAffinity1RelinquishTaskIdentityActivity extends BaseActivity {
+ public static class TaskAffinity1RelinquishTaskIdentityActivity extends Activity {
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
index 950047d..9e1d67a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
@@ -264,11 +264,6 @@
if (activity == null) {
return activityContext;
- } else if (startForResult && activityContext == activity) {
- // The result might have send back to caller activity and forced the caller activity
- // to resumed again, before the started activity actually resumed. Just wait for idle
- // for that case.
- getInstrumentation().waitForIdleSync();
} else {
waitAndAssertActivityLaunched(activity, intent);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
index 93ecabc..8acde84 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -352,7 +352,7 @@
waitForActivityTransitions(ConfigChangeHandlingActivity.class,
Arrays.asList(ON_TOP_POSITION_LOST, ON_MULTI_WINDOW_MODE_CHANGED));
LifecycleVerifier.assertOrder(getLifecycleLog(), ConfigChangeHandlingActivity.class,
- Arrays.asList(ON_TOP_POSITION_LOST, ON_MULTI_WINDOW_MODE_CHANGED),
+ Arrays.asList(ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST),
"moveToSplitScreen");
// Exit split-screen
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/LifecycleVerifier.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/LifecycleVerifier.java
index 2aecea9..f7b7e54 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/LifecycleVerifier.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/LifecycleVerifier.java
@@ -302,7 +302,7 @@
? Arrays.asList(
ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE,
ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
- ON_TOP_POSITION_LOST, ON_PAUSE, ON_MULTI_WINDOW_MODE_CHANGED)
+ ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST, ON_PAUSE)
: Arrays.asList(
ON_PAUSE, ON_STOP, ON_DESTROY, PRE_ON_CREATE, ON_CREATE, ON_START,
ON_RESUME, ON_PAUSE);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index b7352fe..d49f11f 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -101,6 +101,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static java.lang.Integer.toHexString;
@@ -529,9 +530,18 @@
}
protected ComponentName getDefaultSecondaryHomeComponent() {
+ assumeTrue(supportsMultiDisplay());
int resId = Resources.getSystem().getIdentifier(
- "config_secondaryHomeComponent", "string", "android");
- return ComponentName.unflattenFromString(mContext.getResources().getString(resId));
+ "config_secondaryHomePackage", "string", "android");
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
+ intent.setPackage(mContext.getResources().getString(resId));
+ final ResolveInfo resolveInfo =
+ mContext.getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY);
+ assertNotNull("Should have default secondary home activity", resolveInfo);
+
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
}
/**
@@ -750,15 +760,11 @@
* {@code false}.
*/
protected void launchActivityInSplitScreenWithRecents(ComponentName activityName) {
- launchActivityInSplitScreenWithRecents(activityName, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
- }
-
- protected void launchActivityInSplitScreenWithRecents(ComponentName activityName,
- int createMode) {
SystemUtil.runWithShellPermissionIdentity(() -> {
launchActivity(activityName);
final int taskId = mWmState.getTaskByActivity(activityName).mTaskId;
- mAtm.setTaskWindowingModeSplitScreenPrimary(taskId, createMode,
+ mAtm.setTaskWindowingModeSplitScreenPrimary(taskId,
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
true /* onTop */, false /* animate */,
null /* initialBounds */, true /* showRecents */);
@@ -902,12 +908,6 @@
new Rect(0, 0, taskWidth, taskHeight)));
}
- protected void resizePinnedStack(
- int stackId, int stackLeft, int stackTop, int stackWidth, int stackHeight) {
- SystemUtil.runWithShellPermissionIdentity(() -> mAtm.resizePinnedStack(stackId,
- new Rect(stackLeft, stackTop, stackWidth, stackHeight), false /* animate */));
- }
-
protected void pressAppSwitchButtonAndWaitForRecents() {
pressAppSwitchButton();
mWmState.waitForRecentsActivityVisible();
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
index 61c3a380..d747155 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerState.java
@@ -135,7 +135,6 @@
private String mTopResumedActivityRecord = null;
final List<String> mResumedActivitiesInStacks = new ArrayList<>();
final List<String> mResumedActivitiesInDisplays = new ArrayList<>();
- private boolean mIsDockedStackMinimized;
private Rect mDefaultPinnedStackBounds = new Rect();
private Rect mPinnedStackMovementBounds = new Rect();
private String mInputMethodWindowAppToken = null;
@@ -364,7 +363,6 @@
mKeyguardControllerState = null;
mIsHomeRecentsComponent = null;
mPendingActivities.clear();
- mIsDockedStackMinimized = false;
mDefaultPinnedStackBounds.setEmpty();
mPinnedStackMovementBounds.setEmpty();
mInputMethodWindowAppToken = null;
@@ -876,10 +874,6 @@
return mWindowStates.size() - mWindowStates.indexOf(w);
}
- public boolean isDockedStackMinimized() {
- return mIsDockedStackMinimized;
- }
-
ActivityTask getStandardRootTaskByWindowingMode(int windowingMode) {
for (ActivityTask task : mRootTasks) {
if (task.getActivityType() != ACTIVITY_TYPE_STANDARD) {
@@ -985,9 +979,6 @@
mAppTransitionState = appStateToString(appState);
mLastTransition = appTransitionToString(lastTransition);
- if (proto.dockedStackDividerController != null) {
- amState.mIsDockedStackMinimized = proto.dockedStackDividerController.minimizedDock;
- }
PinnedStackControllerProto pinnedStackProto = proto.pinnedStackController;
if (pinnedStackProto != null) {
amState.mDefaultPinnedStackBounds = extract(pinnedStackProto.defaultBounds);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionInfoTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionInfoTest.java
index fc8e56c..b234bd4 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionInfoTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionInfoTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.assertTrue;
import android.os.Parcel;
import android.util.Size;
@@ -42,21 +43,32 @@
public void testNullInlinePresentationSpecThrowsException() {
assertThrows(NullPointerException.class,
() -> InlineSuggestionInfo.newInlineSuggestionInfo(/* presentationSpec */ null,
- InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""}));
+ InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION, /* isPinned */ false));
}
@Test
public void testNullSourceThrowsException() {
assertThrows(IllegalArgumentException.class,
() -> InlineSuggestionInfo.newInlineSuggestionInfo(
- mInlinePresentationSpec, /* source */null, new String[]{""}));
+ mInlinePresentationSpec, /* source */null, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION, /* isPinned */ false));
+ }
+
+ @Test
+ public void testNullTypeThrowsException() {
+ assertThrows(IllegalArgumentException.class,
+ () -> InlineSuggestionInfo.newInlineSuggestionInfo(
+ mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL,
+ new String[]{""}, /* type */ null, /* isPinned */ false));
}
@Test
public void testInlineSuggestionInfoValues() {
InlineSuggestionInfo info =
InlineSuggestionInfo.newInlineSuggestionInfo(mInlinePresentationSpec,
- InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{"password"});
+ InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{"password"},
+ InlineSuggestionInfo.TYPE_SUGGESTION, /* isPinned */ true);
assertThat(info.getSource()).isEqualTo(InlineSuggestionInfo.SOURCE_AUTOFILL);
assertThat(info.getPresentationSpec()).isNotNull();
@@ -64,12 +76,14 @@
assertThat(info.getAutofillHints().length).isEqualTo(1);
assertThat(info.getAutofillHints()[0]).isEqualTo("password");
assertThat(info.getType()).isEqualTo(InlineSuggestionInfo.TYPE_SUGGESTION);
+ assertTrue(info.isPinned());
}
@Test
public void testInlineSuggestionInfoParcelizeDeparcelize() {
InlineSuggestionInfo info = InlineSuggestionInfo.newInlineSuggestionInfo(
- mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""});
+ mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION, /* isPinned */ false);
Parcel p = Parcel.obtain();
info.writeToParcel(p, 0);
p.setDataPosition(0);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
index a0cc196..90f9132 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
@@ -114,7 +114,8 @@
private InlineSuggestion createInlineSuggestion() {
InlineSuggestionInfo info = InlineSuggestionInfo.newInlineSuggestionInfo(
- mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""});
+ mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""},
+ InlineSuggestionInfo.TYPE_SUGGESTION, /* isPinned */ false);
return InlineSuggestion.newInlineSuggestion(info);
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
index c5629fb..d8db007 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionsRequestTest.java
@@ -32,6 +32,7 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import android.os.LocaleList;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -60,16 +61,21 @@
public void testInlineSuggestionsRequestValues() {
final int suggestionCount = 3;
ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
+ LocaleList localeList = LocaleList.forLanguageTags("fa-IR");
InlineSuggestionsRequest request =
new InlineSuggestionsRequest.Builder(presentationSpecs)
.addPresentationSpecs(
new InlinePresentationSpec.Builder(new Size(100, 100),
new Size(400, 100)).build())
+ .setSupportedLocales(LocaleList.forLanguageTags("fa-IR"))
+ .setExtras(/* value */ null)
.setMaxSuggestionCount(suggestionCount).build();
assertThat(request.getMaxSuggestionCount()).isEqualTo(suggestionCount);
assertThat(request.getPresentationSpecs()).isNotNull();
assertThat(request.getPresentationSpecs().size()).isEqualTo(1);
+ assertThat(request.getExtras()).isNull();
+ assertThat(request.getSupportedLocales()).isEqualTo(localeList);
}
@Test
diff --git a/tests/quickaccesswallet/AndroidManifest.xml b/tests/quickaccesswallet/AndroidManifest.xml
index 2765dd2..3d2ad69 100755
--- a/tests/quickaccesswallet/AndroidManifest.xml
+++ b/tests/quickaccesswallet/AndroidManifest.xml
@@ -20,8 +20,6 @@
android:targetSandboxVersion="2">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- Required to update Secure Settings to set default payment app -->
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<!-- Required for HostApduService -->
<uses-permission android:name="android.permission.NFC"/>
<!-- Required to test QuickAccessWalletClient feature availability -->
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
index 7130765..e7bf721 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
@@ -44,6 +44,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.compatibility.common.util.SettingsUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -66,22 +68,19 @@
private static final GetWalletCardsRequest GET_WALLET_CARDS_REQUEST =
new GetWalletCardsRequest(700, 440, 64, 5);
- private static final int SETTING_DISABLED = 0;
- private static final int SETTING_ENABLED = 1;
+ private static final String SETTING_DISABLED = "0";
+ private static final String SETTING_ENABLED = "1";
private Context mContext;
private String mDefaultPaymentApp;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
// Save current default payment app
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- ContentResolver cr = mContext.getContentResolver();
- mDefaultPaymentApp = Settings.Secure.getString(cr,
- Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
-
+ mDefaultPaymentApp = SettingsUtils.get(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
ComponentName component =
ComponentName.createRelative(mContext, TestHostApduService.class.getName());
- Settings.Secure.putString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+ SettingsUtils.syncSet(mContext, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
component.flattenToString());
TestQuickAccessWalletService.resetStaticFields();
}
@@ -90,7 +89,7 @@
public void tearDown() {
// Restore saved default payment app
ContentResolver cr = mContext.getContentResolver();
- Settings.Secure.putString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+ SettingsUtils.syncSet(mContext, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
mDefaultPaymentApp);
// Return all services to default state
@@ -112,43 +111,44 @@
@Test
public void testIsWalletFeatureAvailableWhenDeviceLocked_checksSecureSettings() {
- ContentResolver cr = mContext.getContentResolver();
QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
- int showNotif = Settings.Secure.getInt(
- cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
- int allowPriv = Settings.Secure.getInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+
+ String showNotificationsSetting = SettingsUtils.getSecureSetting(
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+ String allowPrivateNotificationsSetting = SettingsUtils.get(
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
try {
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_ENABLED);
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_ENABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ SETTING_ENABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SETTING_ENABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isTrue();
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_ENABLED);
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ SETTING_ENABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SETTING_DISABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_ENABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ SETTING_DISABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SETTING_ENABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ SETTING_DISABLED);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SETTING_DISABLED);
assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
} finally {
// return settings to original values
- Settings.Secure.putInt(cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, showNotif);
- Settings.Secure.putInt(
- cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, allowPriv);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ showNotificationsSetting);
+ SettingsUtils.syncSet(mContext, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ allowPrivateNotificationsSetting);
}
}
diff --git a/tests/signature/TEST_MAPPING b/tests/signature/TEST_MAPPING
index c1c9d61..810f3f7 100644
--- a/tests/signature/TEST_MAPPING
+++ b/tests/signature/TEST_MAPPING
@@ -37,6 +37,9 @@
"name": "CtsHiddenApiKillswitchWildcardTestCases"
},
{
+ "name": "CtsSystemApiAnnotationTestCases"
+ },
+ {
"name": "CtsSystemApiSignatureTestCases"
},
{
diff --git a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
index 9c3741e..3bed2ac 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ReflectionHelper.java
@@ -34,6 +34,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Uses reflection to obtain runtime representations of elements in the API.
@@ -421,11 +423,25 @@
}
}
+ private final static Pattern REPEATING_ANNOTATION_PATTERN =
+ Pattern.compile("@.*\\(value=\\[(.*)\\]\\)");
+
public static boolean hasMatchingAnnotation(AnnotatedElement elem, String annotationSpec) {
for (Annotation a : elem.getAnnotations()) {
if (a.toString().equals(annotationSpec)) {
return true;
}
+ // It could be a repeating annotation. In that case, a.toString() returns
+ // "@MyAnnotation$Container(value=[@MyAnnotation(A), @MyAnnotation(B)])"
+ // Then, iterate over @MyAnnotation(A) and @MyAnnotation(B).
+ Matcher m = REPEATING_ANNOTATION_PATTERN.matcher(a.toString());
+ if (m.matches()) {
+ for (String token : m.group(1).split(", ")) {
+ if (token.equals(annotationSpec)) {
+ return true;
+ }
+ }
+ }
}
return false;
}
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
index ab44335..afae17e 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
@@ -22,12 +22,15 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.app.UiModeManager;
+import android.content.res.Configuration;
import android.os.PowerManager;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.BatteryUtils;
+import com.android.compatibility.common.util.SettingsUtils;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.Test;
@@ -91,4 +94,57 @@
assertFalse(manager.isPowerSaveMode());
});
}
+
+ /** Tests that Battery Saver exemptions activate when car mode is active. */
+ @Test
+ public void testCarModeExceptions() throws Exception {
+ UiModeManager uiModeManager = getContext().getSystemService(UiModeManager.class);
+ uiModeManager.disableCarMode(0);
+
+ final PowerManager powerManager = BatteryUtils.getPowerManager();
+
+ try {
+ runDumpsysBatteryUnplug();
+
+ SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants",
+ "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+ + ",enable_night_mode=true");
+
+ enableBatterySaver(true);
+
+ // Allow time for UI change.
+ Thread.sleep(1000);
+ assertTrue(powerManager.isPowerSaveMode());
+ assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+ powerManager.getLocationPowerSaveMode());
+ assertEquals(Configuration.UI_MODE_NIGHT_YES,
+ getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK);
+
+ uiModeManager.enableCarMode(0);
+ // Allow time for UI change.
+ Thread.sleep(1000);
+
+ final int locationPowerSaveMode = powerManager.getLocationPowerSaveMode();
+ assertTrue("Location power save mode didn't change from " + locationPowerSaveMode,
+ locationPowerSaveMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY
+ || locationPowerSaveMode == PowerManager.LOCATION_MODE_NO_CHANGE);
+ assertEquals(Configuration.UI_MODE_NIGHT_NO,
+ getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK);
+
+ uiModeManager.disableCarMode(0);
+ // Allow time for UI change.
+ Thread.sleep(1000);
+
+ assertEquals(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+ powerManager.getLocationPowerSaveMode());
+ assertEquals(Configuration.UI_MODE_NIGHT_YES,
+ getContext().getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK);
+ } finally {
+ uiModeManager.disableCarMode(0);
+ SettingsUtils.delete(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants");
+ }
+ }
}
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 583ff7c..1a27bf0 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -26,7 +26,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import android.content.Context;
@@ -215,4 +217,62 @@
PARTIALLY_DIRECT_BOOT_AWARE_PACKAGE_NAME, 0);
assertTrue(applicationInfo.isEncryptionAware());
}
+
+ @Test
+ public void testWriteToParcelDontSquash() throws Exception {
+ // Make sure ApplicationInfo.writeToParcel() doesn't do the "squashing",
+ // because Parcel.allowSquashing() isn't called.
+
+ mApplicationInfo = getContext().getPackageManager().getApplicationInfo(mPackageName, 0);
+
+ final Parcel p = Parcel.obtain();
+ mApplicationInfo.writeToParcel(p, 0);
+ mApplicationInfo.writeToParcel(p, 0);
+
+ // Don't call Parcel.allowSquashing()
+
+ p.setDataPosition(0);
+ final ApplicationInfo copy1 = ApplicationInfo.CREATOR.createFromParcel(p);
+ final ApplicationInfo copy2 = ApplicationInfo.CREATOR.createFromParcel(p);
+
+ p.recycle();
+
+ assertNotSame(mApplicationInfo, copy1);
+
+ // writeToParcel() doesn't do the squashing, so copy1 and copy2 will be different.
+ assertNotSame(copy1, copy2);
+
+ // Check several fields to make sure they're properly copied.
+ assertEquals(mApplicationInfo.packageName, copy2.packageName);
+ assertEquals(copy1.packageName, copy2.packageName);
+
+ assertEquals(mApplicationInfo.flags, copy2.flags);
+ assertEquals(copy1.flags, copy2.flags);
+ }
+
+ @Test
+ public void testWriteToParcelSquash() throws Exception {
+ // Make sure ApplicationInfo.writeToParcel() does the "squashing", after
+ // Parcel.allowSquashing() is called.
+
+ mApplicationInfo = getContext().getPackageManager().getApplicationInfo(mPackageName, 0);
+
+ final Parcel p = Parcel.obtain();
+
+ final boolean prevSquashing = p.allowSquashing(); // Allow squashing.
+
+ mApplicationInfo.writeToParcel(p, 0);
+ mApplicationInfo.writeToParcel(p, 0);
+
+ p.setDataPosition(0);
+ final ApplicationInfo copy1 = ApplicationInfo.CREATOR.createFromParcel(p);
+ final ApplicationInfo copy2 = ApplicationInfo.CREATOR.createFromParcel(p);
+
+ p.recycle();
+
+ assertNotSame(mApplicationInfo, copy1);
+ assertSame(copy1, copy2); //
+
+ p.restoreAllowSquashing(prevSquashing);
+ }
}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
index b2aae0d..8cfab20 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageInfoTest.java
@@ -18,6 +18,7 @@
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
@@ -63,6 +64,19 @@
p.recycle();
}
+ public void testApplicationInfoSame() {
+ ApplicationInfo ai = mPackageInfo.applicationInfo;
+
+ // Make sure all the components in it has the same ApplicationInfo.
+ for (ComponentInfo[] ar : new ComponentInfo[][]{
+ mPackageInfo.activities, mPackageInfo.services, mPackageInfo.providers,
+ mPackageInfo.receivers}) {
+ for (ComponentInfo ci : ar) {
+ assertSame("component=" + ci.getComponentName(), ai, ci.applicationInfo);
+ }
+ }
+ }
+
private void checkPkgInfoSame(PackageInfo expected, PackageInfo actual) {
assertEquals(expected.packageName, actual.packageName);
assertEquals(expected.getLongVersionCode(), actual.getLongVersionCode());
diff --git a/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java b/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java
new file mode 100644
index 0000000..2578058
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/ProviderInfoListTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.content.pm.cts;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ProviderInfoList;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ProviderInfoListTest extends AndroidTestCase {
+ private static final String PACKAGE_NAME = "android.content.cts";
+
+ public void testApplicationInfoSquashed() throws Exception {
+ final PackageManager pm = getContext().getPackageManager();
+ final PackageInfo pi = pm.getPackageInfo(PACKAGE_NAME,
+ PackageManager.GET_PROVIDERS | PackageManager.GET_UNINSTALLED_PACKAGES);
+
+ // Make sure the package contains more than 1 providers.
+ assertNotNull(pi);
+ assertNotNull(pi.providers);
+ assertTrue(pi.providers.length > 1);
+
+ final List<ProviderInfo> providers = new ArrayList<>();
+ Collections.addAll(providers, pi.providers);
+
+ // Create a target list.
+ final ProviderInfoList source = ProviderInfoList.fromList(providers);
+
+ // Parcel it and uparcel
+ final Parcel p = Parcel.obtain();
+ source.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ final ProviderInfoList dest = ProviderInfoList.CREATOR.createFromParcel(p);
+ p.recycle();
+
+ final List<ProviderInfo> destList = dest.getList();
+ assertEquals(source.getList().size(), destList.size());
+ for (int i = 0; i < destList.size(); i++) {
+ assertEquals(destList.get(0).applicationInfo, destList.get(i).applicationInfo);
+ }
+ }
+}
diff --git a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
index 44a9cc2..d5361d7 100644
--- a/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
+++ b/tests/tests/net/src/android/net/wifi/rtt/cts/WifiRttTest.java
@@ -163,7 +163,7 @@
// Analyze results
assertTrue("Wi-Fi RTT failure rate exceeds threshold: FAIL=" + numFailures + ", ITERATIONS="
- + NUM_OF_RTT_ITERATIONS,
+ + NUM_OF_RTT_ITERATIONS + ", AP RSSI=" + testAp.level,
numFailures <= NUM_OF_RTT_ITERATIONS * MAX_FAILURE_RATE_PERCENT / 100);
if (numFailures != NUM_OF_RTT_ITERATIONS) {
double distanceAvg = distanceSum / (NUM_OF_RTT_ITERATIONS - numFailures);
diff --git a/tests/tests/provider/OWNERS b/tests/tests/provider/OWNERS
index fea932d..ed13f6fa 100644
--- a/tests/tests/provider/OWNERS
+++ b/tests/tests/provider/OWNERS
@@ -5,3 +5,5 @@
tgunn@google.com
nicksauer@google.com
nona@google.com
+nandana@google.com
+zezeozue@google.com
diff --git a/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java
index ad85ac2..da2145c 100755
--- a/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java
+++ b/tests/tests/secure_element/access_control/AccessControlApp1/src/android/omapi/accesscontrol1/cts/AccessControlTest.java
@@ -159,7 +159,17 @@
private boolean supportsHardware() {
final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
- return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
+ return !lowRamDevice || pm.hasSystemFeature("android.hardware.type.watch")
+ || hasSecureElementPackage(pm);
+ }
+
+ private boolean hasSecureElementPackage(PackageManager pm) {
+ try {
+ pm.getPackageInfo("com.android.se", 0 /* flags*/);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
private boolean supportOMAPIReaders() {
diff --git a/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java
index 8bce22b..0080446 100755
--- a/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java
+++ b/tests/tests/secure_element/access_control/AccessControlApp2/src/android/omapi/accesscontrol2/cts/AccessControlTest.java
@@ -158,7 +158,17 @@
private boolean supportsHardware() {
final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
- return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
+ return !lowRamDevice || pm.hasSystemFeature("android.hardware.type.watch")
+ || hasSecureElementPackage(pm);
+ }
+
+ private boolean hasSecureElementPackage(PackageManager pm) {
+ try {
+ pm.getPackageInfo("com.android.se", 0 /* flags*/);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
private boolean supportOMAPIReaders() {
diff --git a/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java b/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java
index e6dc5f0..24e0cac 100755
--- a/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java
+++ b/tests/tests/secure_element/access_control/AccessControlApp3/src/android/omapi/accesscontrol3/cts/AccessControlTest.java
@@ -168,7 +168,17 @@
private boolean supportsHardware() {
final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
- return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
+ return !lowRamDevice || pm.hasSystemFeature("android.hardware.type.watch")
+ || hasSecureElementPackage(pm);
+ }
+
+ private boolean hasSecureElementPackage(PackageManager pm) {
+ try {
+ pm.getPackageInfo("com.android.se", 0 /* flags*/);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
private boolean supportOMAPIReaders() {
diff --git a/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java b/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java
index d634fee..9a862d7 100644
--- a/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java
+++ b/tests/tests/secure_element/omapi/src/android/omapi/cts/OmapiTest.java
@@ -155,7 +155,17 @@
private boolean supportsHardware() {
final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
- return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
+ return !lowRamDevice || pm.hasSystemFeature("android.hardware.type.watch")
+ || hasSecureElementPackage(pm);
+ }
+
+ private boolean hasSecureElementPackage(PackageManager pm) {
+ try {
+ pm.getPackageInfo("com.android.se", 0 /* flags*/);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
}
private boolean supportUICCReaders() {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index de40198..476166eb 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -2483,28 +2483,6 @@
}
@Test
- public void testSetPolicyDataEnabled() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- return;
- }
- // test without permission: verify SecurityException
- try {
- mTelephonyManager.setPolicyDataEnabled(true);
- fail("testSetPolicyDataEnabled: SecurityException expected");
- } catch (SecurityException se) {
- // expected
- }
- // test with permission
- try {
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- (tm) -> tm.setPolicyDataEnabled(true));
- } catch (SecurityException se) {
- fail("testSetPolicyDataEnabled: SecurityException not expected");
- }
- }
-
- @Test
public void testSetAllowedNetworkTypes() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 7419858..94b2c1e 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -245,9 +245,7 @@
return;
}
- // TODO(b/148840827): Uncomment default value assertion when a new version of WebView
- // where the change happened is dropped in master.
- // assertFalse("File access should be off by default", mSettings.getAllowFileAccess());
+ assertFalse("File access should be off by default", mSettings.getAllowFileAccess());
mSettings.setAllowFileAccess(true);
assertTrue("Explicitly setting file access to true should work",