• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.server.wm;
18 
19 import static android.server.wm.WindowManagerState.STATE_RESUMED;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
22 import static android.window.BackNavigationInfo.TYPE_CALLBACK;
23 import static android.window.BackNavigationInfo.TYPE_CROSS_ACTIVITY;
24 import static android.window.BackNavigationInfo.TYPE_CROSS_TASK;
25 import static android.window.BackNavigationInfo.TYPE_DIALOG_CLOSE;
26 import static android.window.BackNavigationInfo.TYPE_RETURN_TO_HOME;
27 
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.assertTrue;
30 
31 import android.app.Activity;
32 import android.app.AlertDialog;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.graphics.Color;
36 import android.os.Bundle;
37 import android.platform.test.annotations.Presubmit;
38 import android.view.Gravity;
39 import android.view.ViewGroup;
40 import android.view.inputmethod.InputMethodManager;
41 import android.widget.EditText;
42 import android.widget.FrameLayout;
43 import android.widget.LinearLayout;
44 import android.widget.PopupWindow;
45 
46 import androidx.annotation.Nullable;
47 
48 import org.junit.Before;
49 import org.junit.Test;
50 
51 /**
52  * Integration test for back navigation mode
53  *
54  *  <p>Build/Install/Run:
55  *      atest CtsWindowManagerDeviceTestCases:BackGestureInvokedTest
56  */
57 @Presubmit
58 @android.server.wm.annotation.Group1
59 public class BackGestureInvokedTest extends ActivityManagerTestBase {
60     private TestActivitySession<BackInvokedActivity> mActivitySession;
61     private BackInvokedActivity mActivity;
62 
63     @Before
setUp()64     public void setUp() throws Exception {
65         super.setUp();
66         enableAndAssumeGestureNavigationMode();
67 
68         mActivitySession = createManagedTestActivitySession();
69         mActivitySession.launchTestActivityOnDisplaySync(
70                 BackInvokedActivity.class, DEFAULT_DISPLAY);
71         mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
72         mActivity = mActivitySession.getActivity();
73         mWmState.waitForActivityState(mActivity.getComponentName(), STATE_RESUMED);
74         mWmState.assertVisibility(mActivity.getComponentName(), true);
75     }
76 
77     @Test
popupWindowDismissedOnBackGesture()78     public void popupWindowDismissedOnBackGesture() {
79         mActivitySession.runOnMainSyncAndWait(mActivity::addPopupWindow);
80         mWmState.waitAndAssertWindowShown(TYPE_APPLICATION_PANEL, true);
81         triggerBackEventByGesture(DEFAULT_DISPLAY);
82 
83         assertTrue("Popup window must be removed",
84                 mWmState.waitForWithAmState(
85                         state -> state.getMatchingWindowType(TYPE_APPLICATION_PANEL).isEmpty(),
86                         "popup window to dismiss"));
87 
88         // activity remain focused
89         mWmState.assertFocusedActivity("Top activity must be focused",
90                 mActivity.getComponentName());
91         final String windowName = ComponentNameUtils.getWindowName(mActivity.getComponentName());
92         mWmState.assertFocusedWindow(
93                 "Top activity window must be focused window.", windowName);
94     }
95 
96     @Test
testBackToHome()97     public void testBackToHome() {
98         triggerBackEventByGesture(DEFAULT_DISPLAY);
99         mWmState.waitAndAssertActivityRemoved(mActivity.getComponentName());
100 
101         assertEquals(TYPE_RETURN_TO_HOME, mWmState.getBackNavigationState().getLastBackType());
102     }
103 
104     @Test
testBackToTask()105     public void testBackToTask() {
106         final ComponentName
107                 componentName = new ComponentName(mContext, NewTaskActivity.class);
108         launchActivityInNewTask(componentName);
109         mWmState.waitForActivityState(componentName, STATE_RESUMED);
110         mWmState.assertVisibility(componentName, true);
111         mWmState.waitForFocusedActivity("Wait for launched activity to be in front.",
112                 componentName);
113         triggerBackEventByGesture(DEFAULT_DISPLAY);
114 
115         assertEquals(TYPE_CROSS_TASK, mWmState.getBackNavigationState().getLastBackType());
116     }
117 
118     @Test
testBackToActivity()119     public void testBackToActivity() {
120         final ComponentName componentName = new ComponentName(mContext, SecondActivity.class);
121         launchActivity(componentName);
122         mWmState.waitForActivityState(componentName, STATE_RESUMED);
123         mWmState.assertVisibility(componentName, true);
124         mWmState.waitForFocusedActivity("Wait for launched activity to be in front.",
125                 componentName);
126         triggerBackEventByGesture(DEFAULT_DISPLAY);
127 
128         assertEquals(TYPE_CROSS_ACTIVITY, mWmState.getBackNavigationState().getLastBackType());
129     }
130 
131     @Test
testDialogDismissed()132     public void testDialogDismissed() {
133         mInstrumentation.runOnMainSync(() -> {
134             new AlertDialog.Builder(mActivity)
135                     .setTitle("Dialog")
136                     .show();
137         });
138         mInstrumentation.waitForIdleSync();
139 
140         triggerBackEventByGesture(DEFAULT_DISPLAY);
141 
142         // activity remain focused
143         mWmState.assertFocusedActivity("Top activity must be focused",
144                 mActivity.getComponentName());
145 
146         assertEquals(TYPE_DIALOG_CLOSE, mWmState.getBackNavigationState().getLastBackType());
147     }
148 
149     @Test
testImeDismissed()150     public void testImeDismissed() {
151         ComponentName componentName = new ComponentName(mContext, ImeTestActivity.class);
152         launchActivity(componentName);
153         mWmState.waitForActivityState(componentName, STATE_RESUMED);
154         mWmState.assertVisibility(componentName, true);
155         mWmState.waitAndAssertImeWindowShownOnDisplay(DEFAULT_DISPLAY);
156 
157         triggerBackEventByGesture(DEFAULT_DISPLAY);
158 
159         assertEquals(TYPE_CALLBACK, mWmState.getBackNavigationState().getLastBackType());
160     }
161 
162     public static class BackInvokedActivity extends Activity {
163 
164         private FrameLayout mContentView;
165 
getContentView()166         private FrameLayout getContentView() {
167             return mContentView;
168         }
169 
170         @Override
onCreate(@ullable Bundle savedInstanceState)171         protected void onCreate(@Nullable Bundle savedInstanceState) {
172             super.onCreate(savedInstanceState);
173             mContentView = new FrameLayout(this);
174             setContentView(mContentView);
175         }
176 
addPopupWindow()177         public void addPopupWindow() {
178             FrameLayout contentView = new FrameLayout(this);
179             contentView.setBackgroundColor(Color.RED);
180             PopupWindow popup = new PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT,
181                     ViewGroup.LayoutParams.MATCH_PARENT);
182 
183             // Ensure the window can get the focus by marking the views as focusable
184             popup.setFocusable(true);
185             contentView.setFocusable(true);
186             popup.showAtLocation(getContentView(), Gravity.FILL, 0, 0);
187         }
188     }
189 
190     public static class NewTaskActivity extends Activity {
191         private FrameLayout mContentView;
192 
193         @Override
onCreate(@ullable Bundle savedInstanceState)194         protected void onCreate(@Nullable Bundle savedInstanceState) {
195             super.onCreate(savedInstanceState);
196             mContentView = new FrameLayout(this);
197             mContentView.setBackgroundColor(Color.GREEN);
198             setContentView(mContentView);
199         }
200     }
201 
202     public static class SecondActivity extends Activity {
203         private FrameLayout mContentView;
204 
205         @Override
onCreate(@ullable Bundle savedInstanceState)206         protected void onCreate(@Nullable Bundle savedInstanceState) {
207             super.onCreate(savedInstanceState);
208             mContentView = new FrameLayout(this);
209             mContentView.setBackgroundColor(Color.BLUE);
210             setContentView(mContentView);
211         }
212     }
213 
214     public static class ImeTestActivity extends Activity {
215         EditText mEditText;
216 
217         @Override
onCreate(Bundle icicle)218         protected void onCreate(Bundle icicle) {
219             super.onCreate(icicle);
220             mEditText = new EditText(this);
221             final LinearLayout layout = new LinearLayout(this);
222             layout.setOrientation(LinearLayout.VERTICAL);
223             layout.addView(mEditText);
224             if (mEditText.requestFocus()) {
225                 InputMethodManager imm = (InputMethodManager)
226                         getSystemService(Context.INPUT_METHOD_SERVICE);
227                 imm.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
228             }
229             setContentView(layout);
230         }
231     }
232 }
233