1 /* 2 * Copyright (C) 2009 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.view.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 26 import android.app.Activity; 27 import android.app.Instrumentation; 28 import android.support.test.InstrumentationRegistry; 29 import android.support.test.annotation.UiThreadTest; 30 import android.support.test.filters.MediumTest; 31 import android.support.test.rule.ActivityTestRule; 32 import android.support.test.runner.AndroidJUnit4; 33 import android.view.KeyEvent; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.ViewRootImpl; 37 import android.widget.Button; 38 import android.widget.FrameLayout; 39 import android.widget.LinearLayout; 40 41 import org.junit.Assume; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 46 @MediumTest 47 @RunWith(AndroidJUnit4.class) 48 public class View_FocusHandlingTest { 49 @Rule 50 public ActivityTestRule<FocusHandlingCtsActivity> mActivityRule = 51 new ActivityTestRule<>(FocusHandlingCtsActivity.class); 52 53 @UiThreadTest 54 @Test testFocusHandling()55 public void testFocusHandling() { 56 Activity activity = mActivityRule.getActivity(); 57 58 View v1 = activity.findViewById(R.id.view1); 59 View v2 = activity.findViewById(R.id.view2); 60 View v3 = activity.findViewById(R.id.view3); 61 View v4 = activity.findViewById(R.id.view4); 62 63 assertNotNull(v1); 64 assertNotNull(v2); 65 assertNotNull(v3); 66 assertNotNull(v4); 67 68 // test isFocusable and setFocusable 69 assertFalse(v1.isFocusable()); 70 assertFalse(v2.isFocusable()); 71 assertFalse(v3.isFocusable()); 72 assertFalse(v4.isFocusable()); 73 74 v1.setFocusable(true); 75 v2.setFocusable(true); 76 v3.setFocusable(true); 77 v4.setFocusable(true); 78 79 assertTrue(v1.isFocusable()); 80 assertTrue(v2.isFocusable()); 81 assertTrue(v3.isFocusable()); 82 assertTrue(v4.isFocusable()); 83 84 v1.setNextFocusRightId(R.id.view2); 85 v1.setNextFocusDownId(R.id.view3); 86 87 v2.setNextFocusLeftId(R.id.view1); 88 v2.setNextFocusDownId(R.id.view4); 89 90 v3.setNextFocusRightId(R.id.view4); 91 v3.setNextFocusUpId(R.id.view1); 92 93 v4.setNextFocusLeftId(R.id.view3); 94 v4.setNextFocusUpId(R.id.view2); 95 96 // test getNextFocus***Id 97 assertEquals(R.id.view2, v1.getNextFocusRightId()); 98 assertEquals(R.id.view3, v1.getNextFocusDownId()); 99 100 assertEquals(R.id.view1, v2.getNextFocusLeftId()); 101 assertEquals(R.id.view4, v2.getNextFocusDownId()); 102 103 assertEquals(R.id.view1, v3.getNextFocusUpId()); 104 assertEquals(R.id.view4, v3.getNextFocusRightId()); 105 106 assertEquals(R.id.view2, v4.getNextFocusUpId()); 107 assertEquals(R.id.view3, v4.getNextFocusLeftId()); 108 109 // test focusSearch 110 assertSame(v2, v1.focusSearch(View.FOCUS_RIGHT)); 111 assertSame(v3, v1.focusSearch(View.FOCUS_DOWN)); 112 113 assertSame(v1, v2.focusSearch(View.FOCUS_LEFT)); 114 assertSame(v4, v2.focusSearch(View.FOCUS_DOWN)); 115 116 assertSame(v1, v3.focusSearch(View.FOCUS_UP)); 117 assertSame(v4, v3.focusSearch(View.FOCUS_RIGHT)); 118 119 assertSame(v2, v4.focusSearch(View.FOCUS_UP)); 120 assertSame(v3, v4.focusSearch(View.FOCUS_LEFT)); 121 122 assertTrue(v1.requestFocus()); 123 assertTrue(v1.hasFocus()); 124 assertFalse(v2.hasFocus()); 125 assertFalse(v3.hasFocus()); 126 assertFalse(v4.hasFocus()); 127 128 v1.setVisibility(View.INVISIBLE); 129 assertFalse(v1.hasFocus()); 130 assertTrue(v2.hasFocus()); 131 assertFalse(v3.hasFocus()); 132 assertFalse(v4.hasFocus()); 133 134 v2.setVisibility(View.INVISIBLE); 135 assertFalse(v1.hasFocus()); 136 assertFalse(v2.hasFocus()); 137 assertTrue(v3.hasFocus()); 138 assertFalse(v4.hasFocus()); 139 140 v3.setVisibility(View.INVISIBLE); 141 assertFalse(v1.isFocused()); 142 assertFalse(v2.isFocused()); 143 assertFalse(v3.isFocused()); 144 assertTrue(v4.isFocused()); 145 146 v4.setVisibility(View.INVISIBLE); 147 assertFalse(v1.isFocused()); 148 assertFalse(v2.isFocused()); 149 assertFalse(v3.isFocused()); 150 assertFalse(v4.isFocused()); 151 152 v1.setVisibility(View.VISIBLE); 153 v2.setVisibility(View.VISIBLE); 154 v3.setVisibility(View.VISIBLE); 155 v4.setVisibility(View.VISIBLE); 156 assertEquals(ViewRootImpl.sAlwaysAssignFocus, v1.isFocused()); 157 assertFalse(v2.isFocused()); 158 assertFalse(v3.isFocused()); 159 assertFalse(v4.isFocused()); 160 161 v1.requestFocus(); 162 assertTrue(v1.isFocused()); 163 164 // test scenario: a view will not actually take focus if it is not focusable 165 v2.setFocusable(false); 166 v3.setFocusable(false); 167 168 assertTrue(v1.isFocusable()); 169 assertFalse(v2.isFocusable()); 170 assertFalse(v3.isFocusable()); 171 assertTrue(v4.isFocusable()); 172 173 v1.setVisibility(View.INVISIBLE); 174 assertFalse(v1.hasFocus()); 175 assertFalse(v2.hasFocus()); 176 assertFalse(v3.hasFocus()); 177 assertTrue(v4.hasFocus()); 178 179 // compare isFocusable and hasFocusable 180 assertTrue(v1.isFocusable()); 181 assertFalse(v1.hasFocusable()); 182 183 // test requestFocus 184 v1.setVisibility(View.VISIBLE); 185 v2.setFocusable(true); 186 v3.setFocusable(true); 187 188 assertTrue(v1.hasFocusable()); 189 assertTrue(v2.hasFocusable()); 190 assertTrue(v3.hasFocusable()); 191 assertTrue(v4.hasFocusable()); 192 193 assertTrue(v2.requestFocus(View.FOCUS_UP)); 194 assertFalse(v1.hasFocus()); 195 assertTrue(v2.hasFocus()); 196 assertFalse(v3.hasFocus()); 197 assertFalse(v4.hasFocus()); 198 199 assertTrue(v1.requestFocus(View.FOCUS_LEFT, null)); 200 assertTrue(v1.hasFocus()); 201 assertFalse(v2.hasFocus()); 202 assertFalse(v3.hasFocus()); 203 assertFalse(v4.hasFocus()); 204 205 assertTrue(v3.requestFocus()); 206 assertFalse(v1.hasFocus()); 207 assertFalse(v2.hasFocus()); 208 assertTrue(v3.hasFocus()); 209 assertFalse(v4.hasFocus()); 210 211 assertTrue(v4.requestFocusFromTouch()); 212 assertFalse(v1.hasFocus()); 213 assertFalse(v2.hasFocus()); 214 assertFalse(v3.hasFocus()); 215 assertTrue(v4.hasFocus()); 216 217 // test clearFocus 218 v4.clearFocus(); 219 assertTrue(v1.hasFocus()); 220 assertFalse(v2.hasFocus()); 221 assertFalse(v3.hasFocus()); 222 assertFalse(v4.hasFocus()); 223 224 assertSame(v1, v1.findFocus()); 225 assertNull(v2.findFocus()); 226 assertNull(v3.findFocus()); 227 assertNull(v4.findFocus()); 228 } 229 230 @UiThreadTest 231 @Test testFocusAuto()232 public void testFocusAuto() { 233 Activity activity = mActivityRule.getActivity(); 234 235 activity.getLayoutInflater().inflate(R.layout.focus_handling_auto_layout, 236 (ViewGroup) activity.findViewById(R.id.auto_test_area)); 237 238 View def = activity.findViewById(R.id.focusabledefault); 239 View auto = activity.findViewById(R.id.focusableauto); 240 View click = activity.findViewById(R.id.onlyclickable); 241 View clickNotFocus = activity.findViewById(R.id.clickablenotfocusable); 242 243 assertEquals(View.FOCUSABLE_AUTO, auto.getFocusable()); 244 assertFalse(auto.isFocusable()); 245 assertFalse(def.isFocusable()); 246 assertTrue(click.isFocusable()); 247 assertFalse(clickNotFocus.isFocusable()); 248 249 View test = new View(activity); 250 assertFalse(test.isFocusable()); 251 test.setClickable(true); 252 assertTrue(test.isFocusable()); 253 test.setFocusable(View.NOT_FOCUSABLE); 254 assertFalse(test.isFocusable()); 255 test.setFocusable(View.FOCUSABLE_AUTO); 256 assertTrue(test.isFocusable()); 257 test.setClickable(false); 258 assertFalse(test.isFocusable()); 259 260 // Make sure setFocusable(boolean) unsets FOCUSABLE_AUTO. 261 auto.setFocusable(true); 262 assertSame(View.FOCUSABLE, auto.getFocusable()); 263 auto.setFocusable(View.FOCUSABLE_AUTO); 264 assertSame(View.FOCUSABLE_AUTO, auto.getFocusable()); 265 auto.setFocusable(false); 266 assertSame(View.NOT_FOCUSABLE, auto.getFocusable()); 267 } 268 269 @UiThreadTest 270 @Test testFocusableInTouchMode()271 public void testFocusableInTouchMode() { 272 final Activity activity = mActivityRule.getActivity(); 273 View singleView = new View(activity); 274 assertFalse("Must not be focusable by default", singleView.isFocusable()); 275 singleView.setFocusableInTouchMode(true); 276 assertSame("setFocusableInTouchMode(true) must imply explicit focusable", 277 View.FOCUSABLE, singleView.getFocusable()); 278 279 activity.getLayoutInflater().inflate(R.layout.focus_handling_auto_layout, 280 (ViewGroup) activity.findViewById(R.id.auto_test_area)); 281 View focusTouchModeView = activity.findViewById(R.id.focusabletouchmode); 282 assertSame("focusableInTouchMode=\"true\" must imply explicit focusable", 283 View.FOCUSABLE, focusTouchModeView.getFocusable()); 284 } 285 286 @UiThreadTest 287 @Test testHasFocusable()288 public void testHasFocusable() { 289 final Activity activity = mActivityRule.getActivity(); 290 final ViewGroup group = (ViewGroup) activity.findViewById(R.id.auto_test_area); 291 292 View singleView = new View(activity); 293 group.addView(singleView); 294 295 testHasFocusable(singleView); 296 297 group.removeView(singleView); 298 299 View groupView = new FrameLayout(activity); 300 group.addView(groupView); 301 302 testHasFocusable(groupView); 303 } 304 testHasFocusable(View view)305 private void testHasFocusable(View view) { 306 assertEquals("single view was not auto-focusable", View.FOCUSABLE_AUTO, 307 view.getFocusable()); 308 assertFalse("single view unexpectedly hasFocusable", view.hasFocusable()); 309 assertFalse("single view unexpectedly hasExplicitFocusable", view.hasExplicitFocusable()); 310 311 view.setClickable(true); 312 assertTrue("single view doesn't hasFocusable", view.hasFocusable()); 313 assertFalse("single view unexpectedly hasExplicitFocusable", view.hasExplicitFocusable()); 314 315 view.setClickable(false); 316 assertFalse("single view unexpectedly hasFocusable", view.hasFocusable()); 317 assertFalse("single view unexpectedly hasExplicitFocusable", view.hasExplicitFocusable()); 318 319 view.setFocusable(View.NOT_FOCUSABLE); 320 assertFalse("single view unexpectedly hasFocusable", view.hasFocusable()); 321 assertFalse("single view unexpectedly hasExplicitFocusable", view.hasExplicitFocusable()); 322 323 view.setFocusable(View.FOCUSABLE); 324 assertTrue("single view doesn't hasFocusable", view.hasFocusable()); 325 assertTrue("single view doesn't hasExplicitFocusable", view.hasExplicitFocusable()); 326 327 view.setFocusable(View.FOCUSABLE_AUTO); 328 view.setFocusableInTouchMode(true); 329 assertTrue("single view doesn't hasFocusable", view.hasFocusable()); 330 assertTrue("single view doesn't hasExplicitFocusable", view.hasExplicitFocusable()); 331 } 332 getInitialAndFirstFocus(int res)333 private View[] getInitialAndFirstFocus(int res) throws Throwable { 334 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 335 instrumentation.setInTouchMode(false); 336 final Activity activity = mActivityRule.getActivity(); 337 mActivityRule.runOnUiThread(() -> activity.getLayoutInflater().inflate(res, 338 (ViewGroup) activity.findViewById(R.id.auto_test_area))); 339 instrumentation.waitForIdleSync(); 340 View root = activity.findViewById(R.id.main_view); 341 View initial = root.findFocus(); 342 instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_TAB); 343 View first = root.findFocus(); 344 return new View[]{initial, first}; 345 } 346 347 @Test testNoInitialFocus()348 public void testNoInitialFocus() throws Throwable { 349 Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus); 350 Activity activity = mActivityRule.getActivity(); 351 View[] result = getInitialAndFirstFocus(R.layout.focus_handling_focusables); 352 assertNull(result[0]); 353 assertSame(result[1], activity.findViewById(R.id.focusable1)); 354 } 355 356 @Test testDefaultFocus()357 public void testDefaultFocus() throws Throwable { 358 Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus); 359 Activity activity = mActivityRule.getActivity(); 360 View[] result = getInitialAndFirstFocus(R.layout.focus_handling_default_focus); 361 assertNull(result[0]); 362 assertSame(result[1], activity.findViewById(R.id.focusable2)); 363 } 364 365 @Test testInitialFocus()366 public void testInitialFocus() throws Throwable { 367 Assume.assumeFalse(ViewRootImpl.sAlwaysAssignFocus); 368 Activity activity = mActivityRule.getActivity(); 369 View[] result = getInitialAndFirstFocus(R.layout.focus_handling_initial_focus); 370 assertSame(result[0], activity.findViewById(R.id.focusable3)); 371 } 372 373 @UiThreadTest 374 @Test testFocusAfterDescendantsTransfer()375 public void testFocusAfterDescendantsTransfer() throws Throwable { 376 final Activity activity = mActivityRule.getActivity(); 377 final ViewGroup group = (ViewGroup) activity.findViewById(R.id.auto_test_area); 378 ViewGroup root = (ViewGroup) activity.findViewById(R.id.main_view); 379 group.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 380 group.setFocusableInTouchMode(true); 381 group.setKeyboardNavigationCluster(true); 382 group.requestFocus(); 383 assertTrue(group.isFocused()); 384 385 LinearLayout mid = new LinearLayout(activity); 386 Button but = new Button(activity); 387 but.setFocusableInTouchMode(true); 388 but.setVisibility(View.INVISIBLE); 389 mid.addView(but, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 390 391 group.addView(mid, ViewGroup.LayoutParams.WRAP_CONTENT, 392 ViewGroup.LayoutParams.WRAP_CONTENT); 393 but.setVisibility(View.VISIBLE); 394 assertSame(root.findFocus(), but); 395 assertFalse(group.isFocused()); 396 397 assertFalse(root.restoreFocusNotInCluster()); 398 assertSame(root.findFocus(), but); 399 } 400 } 401