1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.contentcaptureservice.cts;
17 
18 import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
19 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
20 import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
21 import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
22 import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
23 import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
24 import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
25 import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
26 import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 
30 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
31 import android.os.Bundle;
32 import android.util.Log;
33 import android.view.View;
34 import android.view.ViewStructure;
35 import android.view.contentcapture.ContentCaptureEvent;
36 
37 import androidx.annotation.NonNull;
38 
39 import com.android.compatibility.common.util.DoubleVisitor;
40 import com.android.compatibility.common.util.Visitor;
41 
42 import java.util.List;
43 
44 public class CustomViewActivity extends AbstractContentCaptureActivity {
45 
46     private static final String TAG = CustomViewActivity.class.getSimpleName();
47 
48     private static DoubleVisitor<CustomView, ViewStructure> sCustomViewDelegate;
49     private static Visitor<CustomViewActivity> sRootViewVisitor;
50 
51     /**
52      * Mininum number of events generated when the activity starts.
53      *
54      * <p>Used on {@link #assertInitialViewsAppeared(Session, int)} and
55      * {@link #assertInitialViewsDisappeared(List, int)}.
56      */
57     public static final int MIN_EVENTS = 7;
58 
59     CustomView mCustomView;
60 
61     /**
62      * Sets a delegate that provides the behavior of
63      * {@link CustomView#onProvideContentCaptureStructure(ViewStructure, int)}.
64      */
setCustomViewDelegate(@onNull DoubleVisitor<CustomView, ViewStructure> delegate)65     static void setCustomViewDelegate(@NonNull DoubleVisitor<CustomView, ViewStructure> delegate) {
66         sCustomViewDelegate = delegate;
67     }
68 
onRootView(@onNull Visitor<CustomViewActivity> visitor)69     static void onRootView(@NonNull Visitor<CustomViewActivity> visitor) {
70         sRootViewVisitor = visitor;
71     }
72 
73     @Override
onCreate(Bundle savedInstanceState)74     protected void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         setContentView(R.layout.custom_view_activity);
77         mCustomView = findViewById(R.id.custom_view);
78         Log.d(TAG, "onCreate(): custom view id is " + mCustomView.getAutofillId());
79         if (sCustomViewDelegate != null) {
80             Log.d(TAG, "Setting delegate on " + mCustomView);
81             mCustomView.setContentCaptureDelegate(
82                     (structure) -> sCustomViewDelegate.visit(mCustomView, structure));
83         }
84         if (sRootViewVisitor != null) {
85             try {
86                 sRootViewVisitor.visit(this);
87             } finally {
88                 sRootViewVisitor = null;
89             }
90         }
91     }
92 
93     @Override
assertDefaultEvents(@onNull Session session)94     public void assertDefaultEvents(@NonNull Session session) {
95         assertRightActivity(session, session.id, this);
96         final int additionalEvents = 0;
97         final List<ContentCaptureEvent> events = assertInitialViewsAppeared(session,
98                 additionalEvents);
99         Log.v(TAG, "events(" + events.size() + "): " + events);
100         assertInitialViewsDisappeared(events, additionalEvents);
101     }
102 
103     /**
104      * Asserts the events generated when this activity was launched, up to the
105      * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event.
106      */
107     @NonNull
assertInitialViewsAppeared(Session session, int additionalEvents)108     public List<ContentCaptureEvent> assertInitialViewsAppeared(Session session,
109             int additionalEvents) {
110         return assertJustInitialViewsAppeared(session, additionalEvents);
111     }
112 
113     /**
114      * Asserts the events generated when this activity was launched, but without the
115      * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event.
116      */
117     @NonNull
assertJustInitialViewsAppeared(@onNull Session session, int additionalEvents)118     private List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session,
119             int additionalEvents) {
120         final View grandpa1 = (View) mCustomView.getParent();
121         final View grandpa2 = (View) grandpa1.getParent();
122         final View decorView = getDecorView();
123         Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
124                 + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
125                 + decorView.getAutofillId());
126 
127         final List<ContentCaptureEvent> events = session.getEvents();
128         Log.v(TAG, "events(" + events.size() + "): " + events);
129         assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
130 
131         // Assert just the relevant events
132         assertSessionResumed(events, 0);
133         assertViewTreeStarted(events, 1);
134         assertDecorViewAppeared(events, 2, getDecorView());
135         assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
136         assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
137         assertViewWithUnknownParentAppeared(events, 5, session.id, mCustomView);
138         assertViewTreeFinished(events, 6);
139 
140         return events;
141     }
142 
143     /**
144      * Asserts the initial views disappeared after the activity was finished.
145      */
146     // TODO(b/123540067, 122315042): fix and document or remove
assertInitialViewsDisappeared(@onNull List<ContentCaptureEvent> events, int additionalEvents)147     public void assertInitialViewsDisappeared(@NonNull List<ContentCaptureEvent> events,
148             int additionalEvents) {
149         if (true) return;     // TODO(b/123540067, 122315042): not really working
150         assertViewsOptionallyDisappeared(events, MIN_EVENTS + additionalEvents,
151                 getDecorView().getAutofillId(), mCustomView.getAutofillId());
152         assertSessionPaused(events, MIN_EVENTS + additionalEvents);
153     }
154 }
155