Merge "Add content capture performance test cases"
This commit is contained in:
committed by
Android (Google) Code Review
commit
9b77c6afb3
28
apct-tests/perftests/contentcapture/Android.bp
Normal file
28
apct-tests/perftests/contentcapture/Android.bp
Normal file
@@ -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 {
|
||||
name: "ContentCapturePerfTests",
|
||||
srcs: ["src/**/*.java"],
|
||||
resource_dirs: ["res"],
|
||||
static_libs: [
|
||||
"androidx.test.rules",
|
||||
"androidx.annotation_annotation",
|
||||
"apct-perftests-utils",
|
||||
"collector-device-lib-platform",
|
||||
"compatibility-device-util-axt",
|
||||
],
|
||||
platform_apis: true,
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
44
apct-tests/perftests/contentcapture/AndroidManifest.xml
Normal file
44
apct-tests/perftests/contentcapture/AndroidManifest.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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.perftests.contentcapture">
|
||||
|
||||
<uses-sdk android:targetSdkVersion="28" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<activity android:name="android.view.contentcapture.CustomTestActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="android.view.contentcapture.MyContentCaptureService"
|
||||
android:label="PERF ContentCaptureService"
|
||||
android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.contentcapture.ContentCaptureService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.perftests.contentcapture" />
|
||||
</manifest>
|
||||
27
apct-tests/perftests/contentcapture/AndroidTest.xml
Normal file
27
apct-tests/perftests/contentcapture/AndroidTest.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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.
|
||||
-->
|
||||
<configuration description="Runs ContentCapturePerfTests metric instrumentation.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-metric-instrumentation" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="ContentCapturePerfTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.perftests.contentcapture" />
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical" >
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Username" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/password_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.view.contentcapture;
|
||||
|
||||
import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_CUSTOM_VIEWS;
|
||||
import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_LAYOUT_ID;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.ContentCaptureOptions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.UserHandle;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import com.android.compatibility.common.util.ActivitiesWatcher;
|
||||
import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
|
||||
import com.android.perftests.contentcapture.R;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* Base class for all content capture tests.
|
||||
*/
|
||||
@LargeTest
|
||||
public abstract class AbstractContentCapturePerfTestCase {
|
||||
|
||||
private static final String TAG = AbstractContentCapturePerfTestCase.class.getSimpleName();
|
||||
private static final long GENERIC_TIMEOUT_MS = 10_000;
|
||||
|
||||
private static int sOriginalStayOnWhilePluggedIn;
|
||||
private static Context sContext = getInstrumentation().getTargetContext();
|
||||
|
||||
protected ActivitiesWatcher mActivitiesWatcher;
|
||||
|
||||
private MyContentCaptureService.ServiceWatcher mServiceWatcher;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<CustomTestActivity> mActivityRule =
|
||||
new ActivityTestRule<>(CustomTestActivity.class, false, false);
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
@Rule
|
||||
public TestRule mServiceDisablerRule = (base, description) -> {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
try {
|
||||
base.evaluate();
|
||||
} finally {
|
||||
Log.v(TAG, "@mServiceDisablerRule: safelyDisableService()");
|
||||
safelyDisableService();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
private void safelyDisableService() {
|
||||
try {
|
||||
resetService();
|
||||
MyContentCaptureService.resetStaticState();
|
||||
|
||||
if (mServiceWatcher != null) {
|
||||
mServiceWatcher.waitOnDestroy();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "error disabling service", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content capture service.
|
||||
*/
|
||||
private static void setService(@NonNull String service) {
|
||||
final int userId = getCurrentUserId();
|
||||
Log.d(TAG, "Setting service for user " + userId + " to " + service);
|
||||
// TODO(b/123540602): use @TestingAPI to get max duration constant
|
||||
runShellCommand("cmd content_capture set temporary-service %d %s 119000", userId, service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the content capture service.
|
||||
*/
|
||||
private static void resetService() {
|
||||
final int userId = getCurrentUserId();
|
||||
Log.d(TAG, "Resetting back user " + userId + " to default service");
|
||||
runShellCommand("cmd content_capture set temporary-service %d", userId);
|
||||
}
|
||||
|
||||
private static int getCurrentUserId() {
|
||||
return UserHandle.myUserId();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setStayAwake() {
|
||||
Log.v(TAG, "@BeforeClass: setStayAwake()");
|
||||
// Some test cases will restart the activity, and stay awake is necessary to ensure that
|
||||
// the test will not screen off during the test.
|
||||
// Keeping the activity screen on is not enough, screen off may occur between the activity
|
||||
// finished and the next start
|
||||
final int stayOnWhilePluggedIn = Settings.Global.getInt(sContext.getContentResolver(),
|
||||
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
|
||||
sOriginalStayOnWhilePluggedIn = -1;
|
||||
if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
|
||||
sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
|
||||
// Keep the device awake during testing.
|
||||
setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void resetStayAwake() {
|
||||
Log.v(TAG, "@AfterClass: resetStayAwake()");
|
||||
if (sOriginalStayOnWhilePluggedIn != -1) {
|
||||
setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setStayOnWhilePluggedIn(int value) {
|
||||
runShellCommand(String.format("settings put global %s %d",
|
||||
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value));
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setAllowSelf() {
|
||||
final ContentCaptureOptions options = new ContentCaptureOptions(null);
|
||||
Log.v(TAG, "@BeforeClass: setAllowSelf(): options=" + options);
|
||||
sContext.getApplicationContext().setContentCaptureOptions(options);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void unsetAllowSelf() {
|
||||
Log.v(TAG, "@AfterClass: unsetAllowSelf()");
|
||||
clearOptions();
|
||||
}
|
||||
|
||||
protected static void clearOptions() {
|
||||
sContext.getApplicationContext().setContentCaptureOptions(null);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void disableDefaultService() {
|
||||
Log.v(TAG, "@BeforeClass: disableDefaultService()");
|
||||
setDefaultServiceEnabled(false);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void enableDefaultService() {
|
||||
Log.v(TAG, "@AfterClass: enableDefaultService()");
|
||||
setDefaultServiceEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables / disables the default service.
|
||||
*/
|
||||
private static void setDefaultServiceEnabled(boolean enabled) {
|
||||
final int userId = getCurrentUserId();
|
||||
Log.d(TAG, "setDefaultServiceEnabled(user=" + userId + ", enabled= " + enabled + ")");
|
||||
runShellCommand("cmd content_capture set default-service-enabled %d %s", userId,
|
||||
Boolean.toString(enabled));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepareDevice() throws Exception {
|
||||
Log.v(TAG, "@Before: prepareDevice()");
|
||||
|
||||
// Unlock screen.
|
||||
runShellCommand("input keyevent KEYCODE_WAKEUP");
|
||||
|
||||
// Dismiss keyguard, in case it's set as "Swipe to unlock".
|
||||
runShellCommand("wm dismiss-keyguard");
|
||||
|
||||
// Collapse notifications.
|
||||
runShellCommand("cmd statusbar collapse");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void registerLifecycleCallback() {
|
||||
Log.v(TAG, "@Before: Registering lifecycle callback");
|
||||
final Application app = (Application) sContext.getApplicationContext();
|
||||
mActivitiesWatcher = new ActivitiesWatcher(GENERIC_TIMEOUT_MS);
|
||||
app.registerActivityLifecycleCallbacks(mActivitiesWatcher);
|
||||
}
|
||||
|
||||
@After
|
||||
public void unregisterLifecycleCallback() {
|
||||
Log.d(TAG, "@After: Unregistering lifecycle callback: " + mActivitiesWatcher);
|
||||
if (mActivitiesWatcher != null) {
|
||||
final Application app = (Application) sContext.getApplicationContext();
|
||||
app.unregisterActivityLifecycleCallbacks(mActivitiesWatcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link MyContentCaptureService} as the service for the current user and waits until
|
||||
* its created, then add the perf test package into allow list.
|
||||
*/
|
||||
public MyContentCaptureService enableService() throws InterruptedException {
|
||||
if (mServiceWatcher != null) {
|
||||
throw new IllegalStateException("There Can Be Only One!");
|
||||
}
|
||||
|
||||
mServiceWatcher = MyContentCaptureService.setServiceWatcher();
|
||||
setService(MyContentCaptureService.SERVICE_NAME);
|
||||
mServiceWatcher.setAllowSelf();
|
||||
return mServiceWatcher.waitOnCreate();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected ActivityWatcher startWatcher() {
|
||||
return mActivitiesWatcher.watch(CustomTestActivity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch test activity with default login layout
|
||||
*/
|
||||
protected CustomTestActivity launchActivity() {
|
||||
return launchActivity(R.layout.test_login_activity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch test activity with give layout and parameter
|
||||
*/
|
||||
protected CustomTestActivity launchActivity(int layoutId, int numViews) {
|
||||
final Intent intent = new Intent(sContext, CustomTestActivity.class);
|
||||
intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
|
||||
intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
|
||||
return mActivityRule.launchActivity(intent);
|
||||
}
|
||||
|
||||
protected void finishActivity() {
|
||||
try {
|
||||
mActivityRule.finishActivity();
|
||||
} catch (IllegalStateException e) {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.contentcapture;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.perftests.contentcapture.R;
|
||||
|
||||
/**
|
||||
* A simple activity used for testing, e.g. performance of activity switching, or as a base
|
||||
* container of testing view.
|
||||
*/
|
||||
public class CustomTestActivity extends Activity {
|
||||
public static final String INTENT_EXTRA_LAYOUT_ID = "layout_id";
|
||||
public static final String INTENT_EXTRA_CUSTOM_VIEWS = "custom_view_number";
|
||||
public static final int MAX_VIEWS = 500;
|
||||
private static final int CUSTOM_CONTAINER_LAYOUT_ID = R.layout.test_container_activity;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getIntent().hasExtra(INTENT_EXTRA_LAYOUT_ID)) {
|
||||
final int layoutId = getIntent().getIntExtra(INTENT_EXTRA_LAYOUT_ID,
|
||||
/* defaultValue= */0);
|
||||
setContentView(layoutId);
|
||||
if (layoutId == CUSTOM_CONTAINER_LAYOUT_ID) {
|
||||
createCustomViews(findViewById(R.id.root_view),
|
||||
getIntent().getIntExtra(INTENT_EXTRA_CUSTOM_VIEWS, MAX_VIEWS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createCustomViews(LinearLayout root, int number) {
|
||||
LinearLayout horizontalLayout = null;
|
||||
for (int i = 0; i < number; i++) {
|
||||
final int j = i % 8;
|
||||
if (horizontalLayout != null && j == 0) {
|
||||
root.addView(horizontalLayout);
|
||||
horizontalLayout = null;
|
||||
}
|
||||
if (horizontalLayout == null) {
|
||||
horizontalLayout = createHorizontalLayout();
|
||||
}
|
||||
horizontalLayout.addView(createItem(null, i));
|
||||
}
|
||||
if (horizontalLayout != null) {
|
||||
root.addView(horizontalLayout);
|
||||
}
|
||||
}
|
||||
|
||||
private LinearLayout createHorizontalLayout() {
|
||||
final LinearLayout layout = new LinearLayout(getApplicationContext());
|
||||
layout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
return layout;
|
||||
}
|
||||
|
||||
private LinearLayout createItem(Drawable drawable, int index) {
|
||||
final LinearLayout group = new LinearLayout(getApplicationContext());
|
||||
group.setOrientation(LinearLayout.VERTICAL);
|
||||
group.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, /* weight= */ 1.0f));
|
||||
|
||||
final TextView text = new TextView(this);
|
||||
text.setText("i = " + index);
|
||||
group.addView(text);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.view.contentcapture;
|
||||
|
||||
import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.CREATED;
|
||||
import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
|
||||
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
|
||||
import com.android.perftests.contentcapture.R;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class LoginTest extends AbstractContentCapturePerfTestCase {
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity() throws Throwable {
|
||||
enableService();
|
||||
|
||||
testActivityLaunchTime(R.layout.test_login_activity, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_contain100Views() throws Throwable {
|
||||
enableService();
|
||||
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_contain300Views() throws Throwable {
|
||||
enableService();
|
||||
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 300);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_contain500Views() throws Throwable {
|
||||
enableService();
|
||||
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 500);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_noService() throws Throwable {
|
||||
testActivityLaunchTime(R.layout.test_login_activity, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_noService_contain100Views() throws Throwable {
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_noService_contain300Views() throws Throwable {
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 300);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchActivity_noService_contain500Views() throws Throwable {
|
||||
testActivityLaunchTime(R.layout.test_container_activity, 500);
|
||||
}
|
||||
|
||||
private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
|
||||
final ActivityWatcher watcher = startWatcher();
|
||||
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
while (state.keepRunning()) {
|
||||
launchActivity(layoutId, numViews);
|
||||
|
||||
// Ignore the time to finish the activity
|
||||
state.pauseTiming();
|
||||
watcher.waitFor(CREATED);
|
||||
finishActivity();
|
||||
watcher.waitFor(DESTROYED);
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnVisibilityAggregated_visibleChanged() throws Throwable {
|
||||
enableService();
|
||||
final CustomTestActivity activity = launchActivity();
|
||||
final View root = activity.getWindow().getDecorView();
|
||||
final View username = root.findViewById(R.id.username);
|
||||
|
||||
testOnVisibilityAggregated(username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnVisibilityAggregated_visibleChanged_noService() throws Throwable {
|
||||
final CustomTestActivity activity = launchActivity();
|
||||
final View root = activity.getWindow().getDecorView();
|
||||
final View username = root.findViewById(R.id.username);
|
||||
|
||||
testOnVisibilityAggregated(username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnVisibilityAggregated_visibleChanged_noOptions() throws Throwable {
|
||||
enableService();
|
||||
clearOptions();
|
||||
final CustomTestActivity activity = launchActivity();
|
||||
final View root = activity.getWindow().getDecorView();
|
||||
final View username = root.findViewById(R.id.username);
|
||||
|
||||
testOnVisibilityAggregated(username);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnVisibilityAggregated_visibleChanged_notImportant() throws Throwable {
|
||||
enableService();
|
||||
final CustomTestActivity activity = launchActivity();
|
||||
final View root = activity.getWindow().getDecorView();
|
||||
final View username = root.findViewById(R.id.username);
|
||||
username.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO);
|
||||
|
||||
testOnVisibilityAggregated(username);
|
||||
}
|
||||
|
||||
private void testOnVisibilityAggregated(View view) throws Throwable {
|
||||
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
// Only count the time of onVisibilityAggregated()
|
||||
state.pauseTiming();
|
||||
mActivityRule.runOnUiThread(() -> {
|
||||
state.resumeTiming();
|
||||
view.onVisibilityAggregated(false);
|
||||
state.pauseTiming();
|
||||
});
|
||||
mActivityRule.runOnUiThread(() -> {
|
||||
state.resumeTiming();
|
||||
view.onVisibilityAggregated(true);
|
||||
state.pauseTiming();
|
||||
});
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.view.contentcapture;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.service.contentcapture.ActivityEvent;
|
||||
import android.service.contentcapture.ContentCaptureService;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MyContentCaptureService extends ContentCaptureService {
|
||||
|
||||
private static final String TAG = MyContentCaptureService.class.getSimpleName();
|
||||
private static final String MY_PACKAGE = "com.android.perftests.contentcapture";
|
||||
public static final String SERVICE_NAME = MY_PACKAGE + "/"
|
||||
+ MyContentCaptureService.class.getName();
|
||||
|
||||
private static ServiceWatcher sServiceWatcher;
|
||||
|
||||
@NonNull
|
||||
public static ServiceWatcher setServiceWatcher() {
|
||||
if (sServiceWatcher != null) {
|
||||
throw new IllegalStateException("There Can Be Only One!");
|
||||
}
|
||||
sServiceWatcher = new ServiceWatcher();
|
||||
return sServiceWatcher;
|
||||
}
|
||||
|
||||
public static void resetStaticState() {
|
||||
sServiceWatcher = null;
|
||||
}
|
||||
|
||||
public static void clearServiceWatcher() {
|
||||
if (sServiceWatcher != null) {
|
||||
if (sServiceWatcher.mReadyToClear) {
|
||||
sServiceWatcher.mService = null;
|
||||
sServiceWatcher = null;
|
||||
} else {
|
||||
sServiceWatcher.mReadyToClear = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected() {
|
||||
Log.i(TAG, "onConnected: sServiceWatcher=" + sServiceWatcher);
|
||||
|
||||
if (sServiceWatcher == null) {
|
||||
Log.e(TAG, "onConnected() without a watcher");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sServiceWatcher.mReadyToClear && sServiceWatcher.mService != null) {
|
||||
Log.e(TAG, "onConnected(): already created: " + sServiceWatcher);
|
||||
return;
|
||||
}
|
||||
|
||||
sServiceWatcher.mService = this;
|
||||
sServiceWatcher.mCreated.countDown();
|
||||
sServiceWatcher.mReadyToClear = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
Log.i(TAG, "onDisconnected: sServiceWatcher=" + sServiceWatcher);
|
||||
|
||||
if (sServiceWatcher == null) {
|
||||
Log.e(TAG, "onDisconnected() without a watcher");
|
||||
return;
|
||||
}
|
||||
if (sServiceWatcher.mService == null) {
|
||||
Log.e(TAG, "onDisconnected(): no service on " + sServiceWatcher);
|
||||
return;
|
||||
}
|
||||
|
||||
sServiceWatcher.mDestroyed.countDown();
|
||||
clearServiceWatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContentCaptureSession(ContentCaptureContext context,
|
||||
ContentCaptureSessionId sessionId) {
|
||||
Log.i(TAG, "onCreateContentCaptureSession(ctx=" + context + ", session=" + sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyContentCaptureSession(ContentCaptureSessionId sessionId) {
|
||||
Log.i(TAG, "onDestroyContentCaptureSession(session=" + sessionId + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContentCaptureEvent(ContentCaptureSessionId sessionId,
|
||||
ContentCaptureEvent event) {
|
||||
Log.i(TAG, "onContentCaptureEventsRequest(session=" + sessionId + "): " + event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityEvent(ActivityEvent event) {
|
||||
Log.i(TAG, "onActivityEvent(): " + event);
|
||||
}
|
||||
|
||||
public static final class ServiceWatcher {
|
||||
|
||||
private static final long GENERIC_TIMEOUT_MS = 10_000;
|
||||
private final CountDownLatch mCreated = new CountDownLatch(1);
|
||||
private final CountDownLatch mDestroyed = new CountDownLatch(1);
|
||||
private boolean mReadyToClear = true;
|
||||
private Pair<Set<String>, Set<ComponentName>> mAllowList;
|
||||
|
||||
private MyContentCaptureService mService;
|
||||
|
||||
@NonNull
|
||||
public MyContentCaptureService waitOnCreate() throws InterruptedException {
|
||||
await(mCreated, "not created");
|
||||
|
||||
if (mService == null) {
|
||||
throw new IllegalStateException("not created");
|
||||
}
|
||||
|
||||
if (mAllowList != null) {
|
||||
Log.d(TAG, "Allow after created: " + mAllowList);
|
||||
mService.setContentCaptureWhitelist(mAllowList.first, mAllowList.second);
|
||||
}
|
||||
|
||||
return mService;
|
||||
}
|
||||
|
||||
public void waitOnDestroy() throws InterruptedException {
|
||||
await(mDestroyed, "not destroyed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow just this package.
|
||||
*/
|
||||
public void setAllowSelf() {
|
||||
final ArraySet<String> pkgs = new ArraySet<>(1);
|
||||
pkgs.add(MY_PACKAGE);
|
||||
mAllowList = new Pair<>(pkgs, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "mService: " + mService + " created: " + (mCreated.getCount() == 0)
|
||||
+ " destroyed: " + (mDestroyed.getCount() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits for a latch to be counted down.
|
||||
*/
|
||||
private static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
|
||||
@Nullable Object... args)
|
||||
throws InterruptedException {
|
||||
final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
if (!called) {
|
||||
throw new IllegalStateException(String.format(fmt, args)
|
||||
+ " in " + GENERIC_TIMEOUT_MS + "ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user