blob: 6b3b7846be1f2a4765bc1a550be7f40a1c6787fb [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view.cts;
import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase2;
import android.view.FocusFinder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class FocusFinderTest extends ActivityInstrumentationTestCase2<FocusFinderCtsActivity> {
private FocusFinder mFocusFinder;
private ViewGroup mLayout;
private Button mTopLeft;
private Button mTopRight;
private Button mBottomLeft;
private Button mBottomRight;
public FocusFinderTest() {
super("android.view.cts", FocusFinderCtsActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mFocusFinder = FocusFinder.getInstance();
mLayout = getActivity().layout;
mTopLeft = getActivity().topLeftButton;
mTopRight = getActivity().topRightButton;
mBottomLeft = getActivity().bottomLeftButton;
mBottomRight = getActivity().bottomRightButton;
mTopLeft.setNextFocusLeftId(View.NO_ID);
mTopRight.setNextFocusLeftId(View.NO_ID);
mBottomLeft.setNextFocusLeftId(View.NO_ID);
mBottomRight.setNextFocusLeftId(View.NO_ID);
}
public void testGetInstance() {
mFocusFinder = null;
mFocusFinder = FocusFinder.getInstance();
assertNotNull(mFocusFinder);
}
public void testFindNextFocus() {
/*
* Go clockwise around the buttons from the top left searching for focus.
*
* +---+---+
* | 1 | 2 |
* +---+---+
* | 3 | 4 |
* +---+---+
*/
assertNextFocus(mTopLeft, View.FOCUS_RIGHT, mTopRight);
assertNextFocus(mTopRight, View.FOCUS_DOWN, mBottomRight);
assertNextFocus(mBottomRight, View.FOCUS_LEFT, mBottomLeft);
assertNextFocus(mBottomLeft, View.FOCUS_UP, mTopLeft);
assertNextFocus(null, View.FOCUS_RIGHT, mTopLeft);
assertNextFocus(null, View.FOCUS_DOWN, mTopLeft);
assertNextFocus(null, View.FOCUS_LEFT, mBottomRight);
assertNextFocus(null, View.FOCUS_UP, mBottomRight);
}
private void assertNextFocus(View currentFocus, int direction, View expectedNextFocus) {
View actualNextFocus = mFocusFinder.findNextFocus(mLayout, currentFocus, direction);
assertEquals(expectedNextFocus, actualNextFocus);
}
public void testFindNextFocusFromRect() {
/*
* Create a small rectangle on the border between the top left and top right buttons.
*
* +---+---+
* | [ ] |
* +---+---+
* | | |
* +---+---+
*/
Rect rect = new Rect();
mTopLeft.getDrawingRect(rect);
rect.offset(mTopLeft.getWidth() / 2, 0);
rect.inset(mTopLeft.getWidth() / 4, mTopLeft.getHeight() / 4);
assertNextFocusFromRect(rect, View.FOCUS_LEFT, mTopLeft);
assertNextFocusFromRect(rect, View.FOCUS_RIGHT, mTopRight);
/*
* Create a small rectangle on the border between the top left and bottom left buttons.
*
* +---+---+
* | | |
* +[ ]+---+
* | | |
* +---+---+
*/
mTopLeft.getDrawingRect(rect);
rect.offset(0, mTopRight.getHeight() / 2);
rect.inset(mTopLeft.getWidth() / 4, mTopLeft.getHeight() / 4);
assertNextFocusFromRect(rect, View.FOCUS_UP, mTopLeft);
assertNextFocusFromRect(rect, View.FOCUS_DOWN, mBottomLeft);
}
private void assertNextFocusFromRect(Rect rect, int direction, View expectedNextFocus) {
View actualNextFocus = mFocusFinder.findNextFocusFromRect(mLayout, rect, direction);
assertEquals(expectedNextFocus, actualNextFocus);
}
public void testFindNearestTouchable() {
/*
* Table layout with two rows and coordinates are relative to those parent rows.
* Lines outside the box signify touch points used in the tests.
* |
* +---+---+
* | 1 | 2 |--
* +---+---+
* --| 3 | 4 |
* +---+---+
* |
*/
// 1
int x = mTopLeft.getWidth() / 2 - 5;
int y = 0;
int[] deltas = new int[2];
View view = mFocusFinder.findNearestTouchable(mLayout, x, y, View.FOCUS_DOWN, deltas);
assertEquals(mTopLeft, view);
assertEquals(0, deltas[0]);
assertEquals(0, deltas[1]);
// 2
deltas = new int[2];
x = mTopRight.getRight();
y = mTopRight.getBottom() / 2;
view = mFocusFinder.findNearestTouchable(mLayout, x, y, View.FOCUS_LEFT, deltas);
assertEquals(mTopRight, view);
assertEquals(-1, deltas[0]);
assertEquals(0, deltas[1]);
// 3
deltas = new int[2];
x = 0;
y = mTopLeft.getBottom() + mBottomLeft.getHeight() / 2;
view = mFocusFinder.findNearestTouchable(mLayout, x, y, View.FOCUS_RIGHT, deltas);
assertEquals(mBottomLeft, view);
assertEquals(0, deltas[0]);
assertEquals(0, deltas[1]);
// 4
deltas = new int[2];
x = mBottomRight.getRight();
y = mTopRight.getBottom() + mBottomRight.getBottom();
view = mFocusFinder.findNearestTouchable(mLayout, x, y, View.FOCUS_UP, deltas);
assertEquals(mBottomRight, view);
assertEquals(0, deltas[0]);
assertEquals(-1, deltas[1]);
}
public void testFindNextAndPrevFocusAvoidingChain() {
mBottomRight.setNextFocusForwardId(mBottomLeft.getId());
mBottomLeft.setNextFocusForwardId(mTopRight.getId());
// Follow the chain
assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mBottomLeft);
assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
assertNextFocus(mTopRight, View.FOCUS_BACKWARD, mBottomLeft);
assertNextFocus(mBottomLeft, View.FOCUS_BACKWARD, mBottomRight);
// Now go to the one not in the chain
assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
assertNextFocus(mBottomRight, View.FOCUS_BACKWARD, mTopLeft);
// Now go back to the top of the chain
assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mBottomRight);
assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mTopRight);
// Now make the chain a circle -- this is the pathological case
mTopRight.setNextFocusForwardId(mBottomRight.getId());
// Fall back to the next one in a chain.
assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mBottomRight);
//Now do branching focus changes
mTopRight.setNextFocusForwardId(View.NO_ID);
mBottomRight.setNextFocusForwardId(mTopRight.getId());
assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mTopRight);
assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
// From the tail, it jumps out of the chain
assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
// Back from the head of a tree goes out of the tree
// We don't know which is the head of the focus chain since it is branching.
View prevFocus1 = mFocusFinder.findNextFocus(mLayout, mBottomLeft, View.FOCUS_BACKWARD);
View prevFocus2 = mFocusFinder.findNextFocus(mLayout, mBottomRight, View.FOCUS_BACKWARD);
assertTrue(prevFocus1 == mTopLeft || prevFocus2 == mTopLeft);
// From outside, it chooses an arbitrary head of the chain
View nextFocus = mFocusFinder.findNextFocus(mLayout, mTopLeft, View.FOCUS_FORWARD);
assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
// Going back from the tail of the split chain, it chooses an arbitrary head
nextFocus = mFocusFinder.findNextFocus(mLayout, mTopRight, View.FOCUS_BACKWARD);
assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
}
}