1 /*
2  * Copyright (C) 2018 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 
17 package android.accessibilityservice.cts;
18 
19 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.AccessibilityEventTypeMatcher;
20 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.ContentChangesMatcher;
21 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
22 import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
23 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED;
24 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED;
25 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE;
26 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
27 
28 import static org.hamcrest.Matchers.both;
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNull;
31 
32 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
33 import android.accessibilityservice.cts.activities.AccessibilityEndToEndActivity;
34 import android.app.Activity;
35 import android.app.Instrumentation;
36 import android.app.UiAutomation;
37 import android.app.UiAutomation.AccessibilityEventFilter;
38 import android.platform.test.annotations.Presubmit;
39 import android.view.View;
40 import android.view.accessibility.AccessibilityNodeInfo;
41 
42 import androidx.test.InstrumentationRegistry;
43 import androidx.test.rule.ActivityTestRule;
44 import androidx.test.runner.AndroidJUnit4;
45 
46 import com.android.compatibility.common.util.CddTest;
47 
48 import org.junit.Before;
49 import org.junit.BeforeClass;
50 import org.junit.Rule;
51 import org.junit.Test;
52 import org.junit.rules.RuleChain;
53 import org.junit.runner.RunWith;
54 
55 /**
56  * Tests reporting of window-like views
57  */
58 @RunWith(AndroidJUnit4.class)
59 @CddTest(requirements = {"3.10/C-1-1,C-1-2"})
60 @Presubmit
61 public class AccessibilityPaneTest {
62     private static Instrumentation sInstrumentation;
63     private static UiAutomation sUiAutomation;
64 
65     private Activity mActivity;
66     private View mPaneView;
67 
68     private ActivityTestRule<AccessibilityEndToEndActivity> mActivityRule =
69             new ActivityTestRule<>(AccessibilityEndToEndActivity.class, false, false);
70 
71     private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
72             new AccessibilityDumpOnFailureRule();
73 
74     private final AccessibilityEventFilter mPaneAppearsFilter =
75             both(new AccessibilityEventTypeMatcher(TYPE_WINDOW_STATE_CHANGED)).and(
76                     new ContentChangesMatcher(CONTENT_CHANGE_TYPE_PANE_APPEARED))::matches;
77     private final AccessibilityEventFilter mPaneDisappearsFilter =
78             both(new AccessibilityEventTypeMatcher(TYPE_WINDOW_STATE_CHANGED)).and(
79                     new ContentChangesMatcher(CONTENT_CHANGE_TYPE_PANE_DISAPPEARED))::matches;
80 
81     @Rule
82     public final RuleChain mRuleChain = RuleChain
83             .outerRule(mActivityRule)
84             .around(mDumpOnFailureRule);
85 
86     @BeforeClass
oneTimeSetup()87     public static void oneTimeSetup() throws Exception {
88         sInstrumentation = InstrumentationRegistry.getInstrumentation();
89         sUiAutomation = sInstrumentation.getUiAutomation();
90     }
91 
92     @Before
setUp()93     public void setUp() throws Exception {
94         mActivity = launchActivityAndWaitForItToBeOnscreen(
95                 sInstrumentation, sUiAutomation, mActivityRule);
96         sInstrumentation.runOnMainSync(() ->  {
97             mPaneView = mActivity.findViewById(R.id.button);
98         });
99     }
100 
101     @Test
paneTitleFromXml_reportedToAccessibility()102     public void paneTitleFromXml_reportedToAccessibility() {
103         String paneTitle = sInstrumentation.getContext().getString(R.string.paneTitle);
104         assertEquals(paneTitle, mPaneView.getAccessibilityPaneTitle());
105         AccessibilityNodeInfo paneNode = getPaneNode();
106         assertEquals(paneTitle, paneNode.getPaneTitle());
107     }
108 
109     @Test
windowLikeViewSettersWork_andNewValuesReportedToAccessibility()110     public void windowLikeViewSettersWork_andNewValuesReportedToAccessibility() throws Exception {
111         final String newTitle = "Here's a new title";
112 
113         sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync(() -> {
114             mPaneView.setAccessibilityPaneTitle(newTitle);
115             assertEquals(newTitle, mPaneView.getAccessibilityPaneTitle());
116         }), (new ContentChangesMatcher(CONTENT_CHANGE_TYPE_PANE_TITLE))::matches,
117                 DEFAULT_TIMEOUT_MS);
118 
119         AccessibilityNodeInfo windowLikeNode = getPaneNode();
120         assertEquals(newTitle, windowLikeNode.getPaneTitle());
121 
122         // Disappear
123         sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync(() -> {
124             mPaneView.setAccessibilityPaneTitle(null);
125             assertNull(mPaneView.getAccessibilityPaneTitle());
126         }), mPaneDisappearsFilter, DEFAULT_TIMEOUT_MS);
127 
128         windowLikeNode.refresh();
129         assertNull(windowLikeNode.getPaneTitle());
130 
131         // Appear
132         sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync(() -> {
133             mPaneView.setAccessibilityPaneTitle(newTitle);
134             assertEquals(newTitle, mPaneView.getAccessibilityPaneTitle());
135         }), mPaneAppearsFilter, DEFAULT_TIMEOUT_MS);
136 
137         windowLikeNode.refresh();
138         assertEquals(newTitle, windowLikeNode.getPaneTitle());
139     }
140 
141     @Test
windowLikeViewVisibility_reportAsWindowStateChanges()142     public void windowLikeViewVisibility_reportAsWindowStateChanges() throws Exception {
143         sUiAutomation.executeAndWaitForEvent(setPaneViewVisibility(View.GONE),
144                 mPaneDisappearsFilter, DEFAULT_TIMEOUT_MS);
145 
146         sUiAutomation.executeAndWaitForEvent(setPaneViewVisibility(View.VISIBLE),
147                 mPaneAppearsFilter, DEFAULT_TIMEOUT_MS);
148 
149         sUiAutomation.executeAndWaitForEvent(setPaneViewParentVisibility(View.GONE),
150                 mPaneDisappearsFilter, DEFAULT_TIMEOUT_MS);
151 
152         sUiAutomation.executeAndWaitForEvent(setPaneViewParentVisibility(View.VISIBLE),
153                 mPaneAppearsFilter, DEFAULT_TIMEOUT_MS);
154     }
155 
getPaneNode()156     private AccessibilityNodeInfo getPaneNode() {
157         return sUiAutomation.getRootInActiveWindow().findAccessibilityNodeInfosByViewId(
158                 "android.accessibilityservice.cts:id/button").get(0);
159     }
160 
setPaneViewVisibility(int visibility)161     private Runnable setPaneViewVisibility(int visibility) {
162         return () -> sInstrumentation.runOnMainSync(
163                 () -> mPaneView.setVisibility(visibility));
164     }
165 
setPaneViewParentVisibility(int visibility)166     private Runnable setPaneViewParentVisibility(int visibility) {
167         return () -> sInstrumentation.runOnMainSync(
168                 () -> ((View) mPaneView.getParent()).setVisibility(visibility));
169     }
170 }
171