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