blob: 03361bad854c302f8d1dd2324c89a0dfe4b85b51 [file] [log] [blame]
/*
* Copyright (C) 2023 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.contentcaptureservice.cts;
import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
import static android.contentcaptureservice.cts.Helper.newImportantView;
import android.content.ComponentName;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.view.View;
import android.view.contentcapture.ContentCaptureSessionId;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.test.core.app.ActivityScenario;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.TestRule;
import java.util.concurrent.atomic.AtomicReference;
@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
public class PartialNotImportantActivityTest extends
AbstractContentCaptureIntegrationTest {
private static final String TAG = PartialNotImportantActivityTest.class.getSimpleName();
ActivityScenario<PartialNotImportantActivity> mScenario;
@NotNull
@Override
protected TestRule getMainTestRule() {
return (base, description) -> base;
}
@Before
@After
public void resetActivityStaticState() {
if (mScenario != null) {
mScenario.close();
mScenario = null;
}
PartialNotImportantActivity.onRootView((activity, view) -> { /* do nothing */ });
}
private ComponentName getComponentName() {
return new ComponentName(
PartialNotImportantActivity.class.getPackageName(),
PartialNotImportantActivity.class.getName());
}
@Test
public void testAddAndRemoveNoImportantChild() throws Exception {
final CtsContentCaptureService service = enableService();
// Child must be created inside the lambda because it needs to use the Activity context.
final AtomicReference<TextView> childRef = new AtomicReference<>();
final AtomicReference<LinearLayout> containerRef = new AtomicReference<>();
PartialNotImportantActivity.onRootView((activity, container) -> {
final TextView child = new TextView(activity);
child.setText("VIEW, Y U NO IMPORTANT?");
child.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO);
childRef.set(child);
container.addView(child);
containerRef.set(container);
});
mScenario = ActivityScenario.launch(PartialNotImportantActivity.class);
// Remove view
final LinearLayout container = containerRef.get();
final TextView child = childRef.get();
mScenario.onActivity((activity) -> container.removeView(child));
// Don't use mScenario.moveToState(State.DESTROYED) because InstrumentationActivityInvoker
// will start an empty activity to stop the activity before calling Activity#finish()
// as a workaround for the framework bug where the framework may not call #onStop and
// #onDestroy if you call Activity#finish() while it is resumed. A new session is started
// for the empty activity.
mScenario.onActivity((activity) -> activity.finish());
final Session session = service.getOnlyFinishedSession();
final ContentCaptureSessionId sessionId = session.id;
Log.v(TAG, "session id: " + sessionId);
assertRightActivity(session, sessionId, getComponentName());
// Assert just the relevant events
// This test case will doesn't have an event for the view that
// id is parent_not_important before the textView.
new EventsAssertor(session.getEvents())
.assertNoEvent(child)
.assertNoEvent(container);
}
@Test
public void testAddAndRemoveImportantChild() throws Exception {
final CtsContentCaptureService service = enableService();
// Child must be created inside the lambda because it needs to use the Activity context.
final AtomicReference<TextView> childRef = new AtomicReference<>();
final AtomicReference<LinearLayout> containerRef = new AtomicReference<>();
PartialNotImportantActivity.onRootView((activity, container) -> {
final TextView text = newImportantView(activity, "Important I am");
childRef.set(text);
container.addView(text);
containerRef.set(container);
});
mScenario = ActivityScenario.launch(PartialNotImportantActivity.class);
// Remove view
final LinearLayout container = containerRef.get();
final TextView child = childRef.get();
mScenario.onActivity((activity) -> container.removeView(child));
mScenario.onActivity((activity) -> activity.finish());
final Session session = service.getOnlyFinishedSession();
final ContentCaptureSessionId sessionId = session.id;
Log.v(TAG, "session id: " + sessionId);
assertRightActivity(session, sessionId, getComponentName());
final View decorView = container.getRootView();
final View root = decorView.findViewById(R.id.root_view);
final View notImportantParentView = decorView.findViewById(R.id.parent_not_important);
// Assert just the relevant events
// Because the child view is important for Content Capture, then its parent
// is also become important for Content Capture. So the view that id is
// parent_not_important should have an appeared event.
new EventsAssertor(session.getEvents())
.assertViewTreeStarted()
.assertViewAppeared(notImportantParentView, root.getAutofillId())
.assertViewAppeared(container, notImportantParentView.getAutofillId())
.assertViewAppeared(child, container.getAutofillId())
.assertViewDisappeared(child.getAutofillId());
}
@Test
public void testAddImportantChildAfterSessionStarted() throws Exception {
final CtsContentCaptureService service = enableService();
// Child must be created inside the lambda because it needs to use the Activity context.
final AtomicReference<TextView> childRef = new AtomicReference<>();
final AtomicReference<LinearLayout> containerRef = new AtomicReference<>();
PartialNotImportantActivity.onRootView((activity, container) -> {
containerRef.set(container);
});
mScenario = ActivityScenario.launch(PartialNotImportantActivity.class);
final LinearLayout container = containerRef.get();
mScenario.onActivity((activity) -> {
final TextView child = newImportantView(activity, "Important I am");
childRef.set(child);
container.addView(child);
});
mScenario.onActivity((activity) -> activity.finish());
// Add an important view
final TextView child = childRef.get();
final Session session = service.getOnlyFinishedSession();
final ContentCaptureSessionId sessionId = session.id;
Log.v(TAG, "session id: " + sessionId);
assertRightActivity(session, sessionId, getComponentName());
final View decorView = container.getRootView();
final View root = decorView.findViewById(R.id.root_view);
final View notImportantParentView = decorView.findViewById(R.id.parent_not_important);
// Assert just the relevant events
new EventsAssertor(session.getEvents())
.assertViewTreeStarted()
.assertViewTreeFinished()
.assertViewTreeStarted()
.assertViewAppeared(notImportantParentView, root.getAutofillId())
.assertViewAppeared(container, notImportantParentView.getAutofillId())
.assertViewAppeared(child, container.getAutofillId());
}
}