Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2008 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;
     18 
     19 import android.graphics.Rect;
     20 import android.test.AndroidTestCase;
     21 import android.test.suitebuilder.annotation.SmallTest;
     22 
     23 public class FocusFinderTest extends AndroidTestCase {
     24 
     25     private FocusFinderHelper mFocusFinder;
     26 
     27     @Override
     28     protected void setUp() throws Exception {
     29         super.setUp();
     30 
     31         mFocusFinder = new FocusFinderHelper(FocusFinder.getInstance());
     32     }
     33 
     34     @SmallTest
     35     public void testPreconditions() {
     36         assertNotNull("focus finder instance", mFocusFinder);
     37     }
     38 
     39     @SmallTest
     40     public void testBelowNotCandidateForDirectionUp() {
     41         assertIsNotCandidate(View.FOCUS_UP,
     42                 new Rect(0, 30, 10, 40),  // src  (left, top, right, bottom)
     43                 new Rect(0, 50, 10, 60));  // dest (left, top, right, bottom)
     44     }
     45 
     46     @SmallTest
     47     public void testAboveShareEdgeEdgeOkForDirectionUp() {
     48         final Rect src = new Rect(0, 30, 10, 40);
     49 
     50         final Rect dest = new Rect(src);
     51         dest.offset(0, -src.height());
     52         assertEquals(src.top, dest.bottom);
     53 
     54         assertDirectionIsCandidate(View.FOCUS_UP, src, dest);
     55     }
     56 
     57     @SmallTest
     58     public void testCompletelyContainedNotCandidate() {
     59         assertIsNotCandidate(
     60                 View.FOCUS_DOWN,
     61                 //       L  T   R   B
     62                 new Rect(0, 0,  50, 50),
     63                 new Rect(0, 1,  50, 49));
     64     }
     65 
     66     @SmallTest
     67     public void testContinaedWithCommonBottomNotCandidate() {
     68         assertIsNotCandidate(
     69                 View.FOCUS_DOWN,
     70                 //       L  T   R   B
     71                 new Rect(0, 0,  50, 50),
     72                 new Rect(0, 1,  50, 50));
     73     }
     74 
     75     @SmallTest
     76     public void testOverlappingIsCandidateWhenBothEdgesAreInDirection() {
     77         assertDirectionIsCandidate(
     78                 View.FOCUS_DOWN,
     79                 //       L  T   R   B
     80                 new Rect(0, 0,  50, 50),
     81                 new Rect(0, 1,  50, 51));
     82     }
     83 
     84     @SmallTest
     85     public void testTopEdgeOfDestAtOrAboveTopOfSrcNotCandidateForDown() {
     86         assertIsNotCandidate(
     87                 View.FOCUS_DOWN,
     88                 //       L  T   R   B
     89                 new Rect(0, 0,  50, 50),
     90                 new Rect(0, 0,  50, 51));
     91         assertIsNotCandidate(
     92                 View.FOCUS_DOWN,
     93                 //       L  T   R   B
     94                 new Rect(0, 0,  50, 50),
     95                 new Rect(0, -1, 50, 51));
     96     }
     97 
     98     @SmallTest
     99     public void testSameRectBeamsOverlap() {
    100         final Rect rect = new Rect(0, 0, 20, 20);
    101 
    102         assertBeamsOverlap(View.FOCUS_LEFT, rect, rect);
    103         assertBeamsOverlap(View.FOCUS_RIGHT, rect, rect);
    104         assertBeamsOverlap(View.FOCUS_UP, rect, rect);
    105         assertBeamsOverlap(View.FOCUS_DOWN, rect, rect);
    106     }
    107 
    108     @SmallTest
    109     public void testOverlapBeamsRightLeftUpToEdge() {
    110         final Rect rect1 = new Rect(0, 0, 20, 20);
    111         final Rect rect2 = new Rect(rect1);
    112 
    113         // just below bottom edge
    114         rect2.offset(0, rect1.height() - 1);
    115         assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
    116         assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
    117 
    118         // at edge
    119         rect2.offset(0, 1);
    120         assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
    121         assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
    122 
    123         // just beyond
    124         rect2.offset(0, 1);
    125         assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
    126         assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
    127 
    128         // just below top edge
    129         rect2.set(rect1);
    130         rect2.offset(0, -(rect1.height() - 1));
    131         assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
    132         assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
    133 
    134         // at top edge
    135         rect2.offset(0, -1);
    136         assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
    137         assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
    138 
    139         // just beyond top edge
    140         rect2.offset(0, -1);
    141         assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
    142         assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
    143     }
    144 
    145     @SmallTest
    146     public void testOverlapBeamsUpDownUpToEdge() {
    147         final Rect rect1 = new Rect(0, 0, 20, 20);
    148         final Rect rect2 = new Rect(rect1);
    149 
    150         // just short of right edge
    151         rect2.offset(rect1.width() - 1, 0);
    152         assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
    153         assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
    154 
    155         // at edge
    156         rect2.offset(1, 0);
    157         assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
    158         assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
    159 
    160         // just beyond
    161         rect2.offset(1, 0);
    162         assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
    163         assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
    164 
    165         // just short of left edge
    166         rect2.set(rect1);
    167         rect2.offset(-(rect1.width() - 1), 0);
    168         assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
    169         assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
    170 
    171         // at edge
    172         rect2.offset(-1, 0);
    173         assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
    174         assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
    175 
    176         // just beyond edge
    177         rect2.offset(-1, 0);
    178         assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
    179         assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
    180     }
    181 
    182     @SmallTest
    183     public void testDirectlyAboveTrumpsAboveLeft() {
    184         Rect src = new Rect(0, 50, 20, 70);  // src (left, top, right, bottom)
    185 
    186         Rect directlyAbove = new Rect(src);
    187         directlyAbove.offset(0, -(1 + src.height()));
    188 
    189         Rect aboveLeft = new Rect(src);
    190         aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
    191 
    192         assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
    193     }
    194 
    195     @SmallTest
    196     public void testAboveInBeamTrumpsSlightlyCloserOutOfBeam() {
    197         Rect src = new Rect(0, 50, 20, 70);  // src (left, top, right, bottom)
    198 
    199         Rect directlyAbove = new Rect(src);
    200         directlyAbove.offset(0, -(1 + src.height()));
    201 
    202         Rect aboveLeft = new Rect(src);
    203         aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
    204 
    205         // offset directly above a little further up
    206         directlyAbove.offset(0, -5);
    207         assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
    208     }
    209 
    210     @SmallTest
    211     public void testOutOfBeamBeatsInBeamUp() {
    212 
    213         Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
    214 
    215         Rect aboveLeftOfBeam = new Rect(src);
    216         aboveLeftOfBeam.offset(-(src.width() + 1), -src.height());
    217         assertBeamsDontOverlap(View.FOCUS_UP, src, aboveLeftOfBeam);
    218 
    219         Rect aboveInBeam = new Rect(src);
    220         aboveInBeam.offset(0, -src.height());
    221         assertBeamsOverlap(View.FOCUS_UP, src, aboveInBeam);
    222 
    223         // in beam wins
    224         assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
    225 
    226         // still wins while aboveInBeam's bottom edge is < out of beams' top
    227         aboveInBeam.offset(0, -(aboveLeftOfBeam.height() - 1));
    228         assertTrue("aboveInBeam.bottom > aboveLeftOfBeam.top", aboveInBeam.bottom > aboveLeftOfBeam.top);
    229         assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
    230 
    231         // cross the threshold: the out of beam prevails
    232         aboveInBeam.offset(0, -1);
    233         assertEquals(aboveInBeam.bottom, aboveLeftOfBeam.top);
    234         assertBetterCandidate(View.FOCUS_UP, src, aboveLeftOfBeam, aboveInBeam);
    235     }
    236 
    237     /**
    238      * A non-candidate (even a much closer one) is always a worse choice
    239      * than a real candidate.
    240      */
    241     @SmallTest
    242     public void testSomeCandidateBetterThanNonCandidate() {
    243         Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
    244 
    245         Rect nonCandidate = new Rect(src);
    246         nonCandidate.offset(src.width() + 1, 0);
    247 
    248         assertIsNotCandidate(View.FOCUS_LEFT, src, nonCandidate);
    249 
    250         Rect candidate = new Rect(src);
    251         candidate.offset(-(4 * src.width()), 0);
    252         assertDirectionIsCandidate(View.FOCUS_LEFT, src, candidate);
    253 
    254         assertBetterCandidate(View.FOCUS_LEFT, src, candidate, nonCandidate);
    255     }
    256 
    257     /**
    258      * Grabbed from {@link android.widget.focus.VerticalFocusSearchTest#testSearchFromMidLeft()}
    259      */
    260     @SmallTest
    261     public void testVerticalFocusSearchScenario() {
    262         assertBetterCandidate(View.FOCUS_DOWN,
    263                 //       L    T    R    B
    264                 new Rect(0,   109, 153, 169),   // src
    265                 new Rect(166, 169, 319, 229),  // expectedbetter
    266                 new Rect(0,   229, 320, 289)); // expectedworse
    267 
    268         // failing test 4/10/2008, the values were tweaked somehow in functional
    269         // test...
    270         assertBetterCandidate(View.FOCUS_DOWN,
    271                 //       L    T    R    B
    272                 new Rect(0,   91, 153, 133),   // src
    273                 new Rect(166, 133, 319, 175),  // expectedbetter
    274                 new Rect(0,   175, 320, 217)); // expectedworse
    275 
    276     }
    277 
    278     /**
    279      * Example: going down from a thin button all the way to the left of a
    280      * screen where, just below, is a very wide button, and just below that,
    281      * is an equally skinny button all the way to the left.  want to make
    282      * sure any minor axis factor doesn't override the fact that the one below
    283      * in vertical beam should be next focus
    284      */
    285     @SmallTest
    286     public void testBeamsOverlapMajorAxisCloserMinorAxisFurther() {
    287         assertBetterCandidate(View.FOCUS_DOWN,
    288                 //       L   T    R    B
    289                 new Rect(0,  0,   100,  100),  // src
    290                 new Rect(0,  100, 480,  200),  // expectedbetter
    291                 new Rect(0,  200, 100,  300)); // expectedworse
    292     }
    293 
    294     /**
    295      * Real scenario grabbed from song playback screen.
    296      */
    297     @SmallTest
    298     public void testMusicPlaybackScenario() {
    299         assertBetterCandidate(View.FOCUS_LEFT,
    300                 //       L    T    R    B
    301                 new Rect(227, 185, 312, 231),   // src
    302                 new Rect(195, 386, 266, 438),   // expectedbetter
    303                 new Rect(124, 386, 195, 438));  // expectedworse
    304     }
    305 
    306     /**
    307      * more generalized version of {@link #testMusicPlaybackScenario()}
    308      */
    309     @SmallTest
    310     public void testOutOfBeamOverlapBeatsOutOfBeamFurtherOnMajorAxis() {
    311         assertBetterCandidate(View.FOCUS_DOWN,
    312                 //       L    T    R    B
    313                 new Rect(0,   0,   50,  50),   // src
    314                 new Rect(60,  40,  110, 90),   // expectedbetter
    315                 new Rect(60,  70,  110, 120));  // expectedworse
    316     }
    317 
    318     /**
    319      * Make sure that going down prefers views that are actually
    320      * down (and not those next to but still a candidate because
    321      * they are overlapping on the major axis)
    322      */
    323     @SmallTest
    324     public void testInBeamTrumpsOutOfBeamOverlapping() {
    325         assertBetterCandidate(View.FOCUS_DOWN,
    326                 //       L    T    R    B
    327                 new Rect(0,   0,   50,  50),   // src
    328                 new Rect(0,   60,  50,  110),  // expectedbetter
    329                 new Rect(51,  1,   101, 51)); // expectedworse
    330     }
    331 
    332     @SmallTest
    333     public void testOverlappingBeatsNonOverlapping() {
    334         assertBetterCandidate(View.FOCUS_DOWN,
    335                 //       L    T    R    B
    336                 new Rect(0,   0,   50,  50),   // src
    337                 new Rect(0,   40,  50,  90),   // expectedbetter
    338                 new Rect(0,   75,  50,  125)); // expectedworse
    339     }
    340 
    341     @SmallTest
    342     public void testEditContactScenarioLeftFromDiscardChangesGoesToSaveContactInLandscape() {
    343         assertBetterCandidate(View.FOCUS_LEFT,
    344                 //       L    T    R    B
    345                 new Rect(357, 258, 478, 318),  // src
    346                 new Rect(2,   258, 100, 318),  // better
    347                 new Rect(106, 120, 424, 184)); // worse
    348     }
    349 
    350     /**
    351      * A dial pad with 9 squares arranged in a grid.  no padding, so
    352      * the edges are equal.  see {@link android.widget.focus.LinearLayoutGrid}
    353      */
    354     @SmallTest
    355     public void testGridWithTouchingEdges() {
    356         assertBetterCandidate(View.FOCUS_DOWN,
    357                 //       L    T    R    B
    358                 new Rect(106, 49,  212, 192),  // src
    359                 new Rect(106, 192, 212, 335),  // better
    360                 new Rect(0,   192, 106, 335)); // worse
    361 
    362         assertBetterCandidate(View.FOCUS_DOWN,
    363                 //       L    T    R    B
    364                 new Rect(106, 49,  212, 192),  // src
    365                 new Rect(106, 192, 212, 335),  // better
    366                 new Rect(212, 192, 318, 335)); // worse
    367     }
    368 
    369     @SmallTest
    370     public void testSearchFromEmptyRect() {
    371         assertBetterCandidate(View.FOCUS_DOWN,
    372                 //       L   T    R    B
    373                 new Rect(0,  0,   0,   0),    // src
    374                 new Rect(0,  0,   320, 45),   // better
    375                 new Rect(0,  45,  320, 545)); // worse
    376     }
    377 
    378     /**
    379      * Reproduce bug 1124559, drilling down to actual bug
    380      * (majorAxisDistance was wrong for direction left)
    381      */
    382     @SmallTest
    383     public void testGmailReplyButtonsScenario() {
    384         assertBetterCandidate(View.FOCUS_LEFT,
    385                 //       L    T    R    B
    386                 new Rect(223, 380, 312, 417),  // src
    387                 new Rect(102, 380, 210, 417),  // better
    388                 new Rect(111, 443, 206, 480)); // worse
    389 
    390         assertBeamBeats(View.FOCUS_LEFT,
    391             //       L    T    R    B
    392             new Rect(223, 380, 312, 417),  // src
    393             new Rect(102, 380, 210, 417),  // better
    394             new Rect(111, 443, 206, 480)); // worse
    395 
    396         assertBeamsOverlap(View.FOCUS_LEFT,
    397                 //       L    T    R    B
    398                 new Rect(223, 380, 312, 417),
    399                 new Rect(102, 380, 210, 417));
    400 
    401         assertBeamsDontOverlap(View.FOCUS_LEFT,
    402                 //       L    T    R    B
    403                 new Rect(223, 380, 312, 417),
    404                 new Rect(111, 443, 206, 480));
    405 
    406         assertTrue(
    407                 "major axis distance less than major axis distance to "
    408                         + "far edge",
    409                 FocusFinderHelper.majorAxisDistance(View.FOCUS_LEFT,
    410                         //       L    T    R    B
    411                         new Rect(223, 380, 312, 417),
    412                         new Rect(102, 380, 210, 417)) <
    413                 FocusFinderHelper.majorAxisDistanceToFarEdge(View.FOCUS_LEFT,
    414                         //       L    T    R    B
    415                         new Rect(223, 380, 312, 417),
    416                         new Rect(111, 443, 206, 480)));
    417     }
    418 
    419     @SmallTest
    420     public void testGmailScenarioBug1203288() {
    421         assertBetterCandidate(View.FOCUS_DOWN,
    422                 //       L    T    R    B
    423                 new Rect(0,   2,   480, 82),   // src
    424                 new Rect(344, 87,  475, 124),  // better
    425                 new Rect(0,   130, 480, 203)); // worse
    426     }
    427 
    428     @SmallTest
    429     public void testHomeShortcutScenarioBug1295354() {
    430         assertBetterCandidate(View.FOCUS_RIGHT,
    431                 //       L    T    R    B
    432                 new Rect(3, 338, 77, 413),   // src
    433                 new Rect(163, 338, 237, 413),  // better
    434                 new Rect(83, 38, 157, 113)); // worse
    435     }
    436 
    437     @SmallTest
    438     public void testBeamAlwaysBeatsHoriz() {
    439         assertBetterCandidate(View.FOCUS_RIGHT,
    440                 //       L    T    R    B
    441                 new Rect(0,   0,   50,  50),   // src
    442                 new Rect(150, 0,   200, 50),   // better, (way further, but in beam)
    443                 new Rect(60,  51,  110, 101)); // worse, even though it is closer
    444 
    445         assertBetterCandidate(View.FOCUS_LEFT,
    446                 //       L    T    R    B
    447                 new Rect(150, 0,   200,  50),   // src
    448                 new Rect(0,   50,  50,   50),   // better, (way further, but in beam)
    449                 new Rect(49,  99,  149,  101)); // worse, even though it is closer
    450     }
    451 
    452     @SmallTest
    453     public void testIsCandidateOverlappingEdgeFromEmptyRect() {
    454         assertDirectionIsCandidate(View.FOCUS_DOWN,
    455                 //       L   T    R    B
    456                 new Rect(0,  0,   0,   0),   // src
    457                 new Rect(0,  0,   20,  1));  // candidate
    458 
    459         assertDirectionIsCandidate(View.FOCUS_UP,
    460                 //       L   T    R    B
    461                 new Rect(0,  0,   0,   0),   // src
    462                 new Rect(0,  -1,  20,  0));  // candidate
    463 
    464         assertDirectionIsCandidate(View.FOCUS_LEFT,
    465                 //       L   T    R    B
    466                 new Rect(0,  0,   0,   0),    // src
    467                 new Rect(-1,  0,  0,   20));  // candidate
    468 
    469         assertDirectionIsCandidate(View.FOCUS_RIGHT,
    470                 //       L   T    R    B
    471                 new Rect(0,  0,   0,   0),    // src
    472                 new Rect(0,  0,   1,   20));  // candidate
    473     }
    474 
    475     private void assertBeamsOverlap(int direction, Rect rect1, Rect rect2) {
    476         String directionStr = validateAndGetStringFor(direction);
    477         String assertMsg = String.format("Expected beams to overlap in direction %s "
    478                 + "for rectangles %s and %s", directionStr, rect1, rect2);
    479         assertTrue(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
    480     }
    481 
    482     private void assertBeamsDontOverlap(int direction, Rect rect1, Rect rect2) {
    483         String directionStr = validateAndGetStringFor(direction);
    484         String assertMsg = String.format("Expected beams not to overlap in direction %s "
    485                 + "for rectangles %s and %s", directionStr, rect1, rect2);
    486         assertFalse(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
    487     }
    488 
    489     /**
    490      * Assert that particular rect is a better focus search candidate from a
    491      * source rect than another.
    492      * @param direction The direction of focus search.
    493      * @param srcRect The src rectangle.
    494      * @param expectedBetter The candidate that should be better.
    495      * @param expectedWorse The candidate that should be worse.
    496      */
    497     private void assertBetterCandidate(int direction, Rect srcRect,
    498             Rect expectedBetter, Rect expectedWorse) {
    499 
    500         String directionStr = validateAndGetStringFor(direction);
    501         String assertMsg = String.format(
    502                 "expected %s to be a better focus search candidate than "
    503                         + "%s when searching "
    504                         + "from %s in direction %s",
    505                 expectedBetter, expectedWorse, srcRect, directionStr);
    506 
    507         assertTrue(assertMsg,
    508                 mFocusFinder.isBetterCandidate(direction, srcRect,
    509                         expectedBetter, expectedWorse));
    510 
    511         assertMsg = String.format(
    512                 "expected %s to not be a better focus search candidate than "
    513                         + "%s when searching "
    514                         + "from %s in direction %s",
    515                 expectedWorse, expectedBetter, srcRect, directionStr);
    516 
    517         assertFalse(assertMsg,
    518                 mFocusFinder.isBetterCandidate(direction, srcRect,
    519                         expectedWorse, expectedBetter));
    520     }
    521 
    522     private void assertIsNotCandidate(int direction, Rect src, Rect dest) {
    523         String directionStr = validateAndGetStringFor(direction);
    524 
    525         final String assertMsg = String.format(
    526                 "expected going from %s to %s in direction %s to be an invalid "
    527                         + "focus search candidate",
    528                 src, dest, directionStr);
    529         assertFalse(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
    530     }
    531 
    532     private void assertBeamBeats(int direction, Rect srcRect,
    533             Rect rect1, Rect rect2) {
    534 
    535         String directionStr = validateAndGetStringFor(direction);
    536         String assertMsg = String.format(
    537                 "expecting %s to beam beat %s w.r.t %s in direction %s",
    538                 rect1, rect2, srcRect, directionStr);
    539         assertTrue(assertMsg, mFocusFinder.beamBeats(direction, srcRect, rect1, rect2));
    540     }
    541 
    542 
    543     private void assertDirectionIsCandidate(int direction, Rect src, Rect dest) {
    544         String directionStr = validateAndGetStringFor(direction);
    545 
    546         final String assertMsg = String.format(
    547                 "expected going from %s to %s in direction %s to be a valid "
    548                         + "focus search candidate",
    549                 src, dest, directionStr);
    550         assertTrue(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
    551     }
    552 
    553     private String validateAndGetStringFor(int direction) {
    554         String directionStr = "??";
    555         switch(direction) {
    556             case View.FOCUS_UP:
    557                 directionStr = "FOCUS_UP";
    558                 break;
    559             case View.FOCUS_DOWN:
    560                 directionStr = "FOCUS_DOWN";
    561                 break;
    562             case View.FOCUS_LEFT:
    563                 directionStr = "FOCUS_LEFT";
    564                 break;
    565             case View.FOCUS_RIGHT:
    566                 directionStr = "FOCUS_RIGHT";
    567                 break;
    568             default:
    569                 fail("passed in unknown direction, ya blewit!");
    570         }
    571         return directionStr;
    572     }
    573 
    574 
    575 }
    576