| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.contentcaptureservice.cts; |
| |
| import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared; |
| import static android.contentcaptureservice.cts.Assertions.assertRightActivity; |
| import static android.contentcaptureservice.cts.Assertions.assertSessionId; |
| import static android.contentcaptureservice.cts.Assertions.assertSessionResumed; |
| import static android.contentcaptureservice.cts.Assertions.assertViewAppeared; |
| import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished; |
| import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted; |
| import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.contentcaptureservice.cts.CtsContentCaptureService.Session; |
| import android.os.Bundle; |
| import android.util.Log; |
| import android.view.View; |
| import android.view.autofill.AutofillId; |
| import android.view.contentcapture.ContentCaptureEvent; |
| import android.view.contentcapture.ContentCaptureSessionId; |
| import android.widget.EditText; |
| import android.widget.TextView; |
| |
| import androidx.annotation.NonNull; |
| |
| import java.util.List; |
| |
| public class LoginActivity extends AbstractRootViewActivity { |
| |
| private static final String TAG = LoginActivity.class.getSimpleName(); |
| |
| /** |
| * Mininum number of events generated when the activity starts. |
| * |
| * <p>Used on {@link #assertInitialViewsAppeared(Session, int)} and |
| * {@link #assertInitialViewsDisappeared(List, int)}. |
| */ |
| public static final int MIN_EVENTS = 11; |
| |
| TextView mUsernameLabel; |
| EditText mUsername; |
| TextView mPasswordLabel; |
| EditText mPassword; |
| |
| @Override |
| protected void setContentViewOnCreate(Bundle savedInstanceState) { |
| setContentView(R.layout.login_activity); |
| |
| mUsernameLabel = findViewById(R.id.username_label); |
| mUsername = findViewById(R.id.username); |
| mPasswordLabel = findViewById(R.id.password_label); |
| mPassword = findViewById(R.id.password); |
| } |
| |
| @Override |
| public void assertDefaultEvents(@NonNull Session session) { |
| final int additionalEvents = 0; |
| final List<ContentCaptureEvent> events = assertInitialViewsAppeared(session, |
| additionalEvents); |
| assertInitialViewsDisappeared(events, additionalEvents); |
| } |
| |
| /** |
| * Asserts the events generated when this activity was launched, up to the |
| * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event. |
| */ |
| @NonNull |
| public List<ContentCaptureEvent> assertInitialViewsAppeared(@NonNull Session session, |
| int additionalEvents) { |
| final List<ContentCaptureEvent> events = assertJustInitialViewsAppeared(session, |
| additionalEvents); |
| assertViewTreeFinished(events, MIN_EVENTS - 1); |
| |
| return events; |
| } |
| |
| /** |
| * Asserts the events generated when this activity was launched, but without the |
| * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event. |
| */ |
| @NonNull |
| public List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session, |
| int additionalEvents) { |
| assertBaseInformation(session); |
| |
| final LoginActivity activity = this; |
| final ContentCaptureSessionId sessionId = session.id; |
| final List<ContentCaptureEvent> events = session.getEvents(); |
| Log.v(TAG, "events(" + events.size() + "): " + events); |
| // TODO(b/123540067): ideally it should be X so it reflects just the views defined |
| // in the layout - right now it's generating events for 2 intermediate parents |
| // (android:action_mode_bar_stub and android:content), we should try to create an |
| // activity without them |
| |
| final AutofillId rootId = activity.getRootView().getAutofillId(); |
| |
| assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents); |
| |
| // TODO(b/123540067): get rid of those intermediated parents |
| final View grandpa1 = activity.getGrandParent(); |
| final View grandpa2 = activity.getGrandGrandParent(); |
| final View decorView = activity.getDecorView(); |
| final View rootView = activity.getRootView(); |
| |
| assertSessionResumed(events, 0); |
| assertViewTreeStarted(events, 1); |
| assertDecorViewAppeared(events, 2, decorView); |
| assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId()); |
| assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId()); |
| assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId()); |
| assertViewAppeared(events, 6, sessionId, activity.mUsernameLabel, rootId); |
| assertViewAppeared(events, 7, sessionId, activity.mUsername, rootId); |
| assertViewAppeared(events, 8, sessionId, activity.mPasswordLabel, rootId); |
| assertViewAppeared(events, 9, sessionId, activity.mPassword, rootId); |
| |
| return events; |
| } |
| |
| /** |
| * Asserts the events generated when this activity was launched, up to the |
| * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event. |
| */ |
| @NonNull |
| public EventsAssertor assertInitialViewsAppeared(@NonNull Session session) { |
| assertBaseInformation(session); |
| |
| final LoginActivity activity = this; |
| final ContentCaptureSessionId sessionId = session.id; |
| final List<ContentCaptureEvent> events = session.getEvents(); |
| Log.v(TAG, "events(" + events.size() + "): " + events); |
| final AutofillId rootId = activity.getRootView().getAutofillId(); |
| final View grandpa1 = activity.getGrandParent(); |
| final View grandpa2 = activity.getGrandGrandParent(); |
| final View decorView = activity.getDecorView(); |
| final View rootView = activity.getRootView(); |
| |
| EventsAssertor assertor = new EventsAssertor(events); |
| assertor.isAtLeast(MIN_EVENTS) |
| .assertSessionResumed() |
| .assertViewTreeStarted() |
| .assertDecorViewAppeared(decorView) |
| .assertViewAppeared(grandpa2, decorView.getAutofillId()) |
| .assertViewAppeared(grandpa1, grandpa2.getAutofillId()) |
| .assertViewAppeared(sessionId, rootView, grandpa1.getAutofillId()) |
| .assertViewAppeared(sessionId, activity.mUsernameLabel, rootId) |
| .assertViewAppeared(sessionId, activity.mUsername, rootId) |
| .assertViewAppeared(sessionId, activity.mPasswordLabel, rootId) |
| .assertViewAppeared(sessionId, activity.mPassword, rootId) |
| .assertViewTreeFinished(); |
| |
| return assertor; |
| } |
| |
| private void assertBaseInformation(@NonNull Session session) { |
| final LoginActivity activity = this; |
| final ContentCaptureSessionId sessionId = session.id; |
| assertRightActivity(session, sessionId, activity); |
| |
| assertSessionId(sessionId, activity.mUsernameLabel); |
| assertSessionId(sessionId, activity.mUsername); |
| assertSessionId(sessionId, activity.mPassword); |
| assertSessionId(sessionId, activity.mPasswordLabel); |
| } |
| |
| /** |
| * Asserts the initial views disappeared after the activity was finished. |
| */ |
| public void assertInitialViewsDisappeared(@NonNull List<ContentCaptureEvent> events, |
| int additionalEvents) { |
| // TODO(b/122315042): this method is currently a mess, so let's disable for now and properly |
| // fix these assertions later... |
| if (true) return; |
| |
| final LoginActivity activity = this; |
| final AutofillId rootId = activity.getRootView().getAutofillId(); |
| final View decorView = activity.getDecorView(); |
| final View grandpa1 = activity.getGrandParent(); |
| final View grandpa2 = activity.getGrandGrandParent(); |
| |
| // Besides the additional events from the test case, we also need to account for the |
| final int i = MIN_EVENTS + additionalEvents; |
| |
| assertViewTreeStarted(events, i); |
| |
| // TODO(b/122315042): sometimes we get decor view disappareared events, sometimes we don't |
| // As we don't really care about those, let's fix it! |
| try { |
| assertViewsOptionallyDisappeared(events, i + 1, |
| rootId, |
| grandpa1.getAutofillId(), grandpa2.getAutofillId(), |
| activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(), |
| activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId()); |
| } catch (AssertionError e) { |
| Log.e(TAG, "Hack-ignoring assertion without decor view: " + e); |
| // Try again removing it... |
| assertViewsOptionallyDisappeared(events, i + 1, |
| rootId, |
| grandpa1.getAutofillId(), grandpa2.getAutofillId(), |
| decorView.getAutofillId(), |
| activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(), |
| activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId()); |
| } |
| |
| assertViewTreeFinished(events, i + 2); |
| } |
| |
| /** |
| * Asserts the initial views disappeared after the activity was finished. |
| */ |
| public void assertInitialViewsDisappeared(@NonNull EventsAssertor assertor) { |
| final LoginActivity activity = this; |
| final AutofillId rootId = activity.getRootView().getAutofillId(); |
| final View decorView = activity.getDecorView(); |
| final View grandpa1 = activity.getGrandParent(); |
| final View grandpa2 = activity.getGrandGrandParent(); |
| |
| assertor.assertViewTreeStarted() |
| .assertViewDisappeared( |
| rootId, grandpa1.getAutofillId(), grandpa2.getAutofillId(), |
| decorView.getAutofillId(), |
| activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(), |
| activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId()) |
| .assertViewTreeFinished(); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| |
| Log.d(TAG, "AutofillIds: " + "usernameLabel=" + mUsernameLabel.getAutofillId() |
| + ", username=" + mUsername.getAutofillId() |
| + ", passwordLabel=" + mPasswordLabel.getAutofillId() |
| + ", password=" + mPassword.getAutofillId()); |
| } |
| } |