123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// found in the LICENSE file.
423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)package org.chromium.chrome.browser.appmenu;
623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.app.Activity;
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.content.pm.ActivityInfo;
923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.test.suitebuilder.annotation.SmallTest;
1023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.view.KeyEvent;
1123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.view.MenuItem;
1223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.view.View;
1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.widget.ListPopupWindow;
1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.widget.ListView;
1523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.base.ThreadUtils;
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.base.test.util.Feature;
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.chrome.shell.ChromeShellActivity;
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.chrome.shell.ChromeShellActivity.AppMenuHandlerFactory;
2023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.chrome.shell.ChromeShellTestBase;
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.chrome.shell.R;
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.content.browser.test.util.Criteria;
2323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.content.browser.test.util.CriteriaHelper;
2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)/**
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * Tests AppMenu popup
2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */
2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)public class AppMenuTest extends ChromeShellTestBase {
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private AppMenu mAppMenu;
3023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private AppMenuHandlerForTest mAppMenuHandler;
3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
3323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * AppMenuHandler that will be used to intercept item selections for testing.
3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public static class AppMenuHandlerForTest extends AppMenuHandler {
3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int mLastSelectedItemId = -1;
3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        /**
3923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         * AppMenuHandler for intercepting options item selections.
4023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         */
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        public AppMenuHandlerForTest(Activity activity, AppMenuPropertiesDelegate delegate,
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                int menuResourceId) {
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            super(activity, delegate, menuResourceId);
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
4523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        @Override
4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        void onOptionsItemSelected(MenuItem item) {
4823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            mLastSelectedItemId = item.getItemId();
4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Override
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    protected void setUp() throws Exception {
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        super.setUp();
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ChromeShellActivity.setAppMenuHandlerFactory(new AppMenuHandlerFactory() {
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            @Override
5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            public AppMenuHandler getAppMenuHandler(Activity activity,
5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    AppMenuPropertiesDelegate delegate, int menuResourceId) {
6023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                mAppMenuHandler = new AppMenuHandlerForTest(activity, delegate, menuResourceId);
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                return mAppMenuHandler;
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            }
6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        });
6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        launchChromeShellWithBlankPage();
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        showAppMenuAndAssertMenuShown();
6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        mAppMenu = getActivity().getAppMenuHandler().getAppMenu();
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ThreadUtils.runOnUiThread(new Runnable() {
7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            @Override
7123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            public void run() {
7223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                mAppMenu.getPopup().getListView().setSelection(0);
7323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            }
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        });
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            @Override
7723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            public boolean isSatisfied() {
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                return getCurrentFocusedRow() == 0;
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            }
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }));
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        getInstrumentation().waitForIdleSync();
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test bounds when accessing the menu through the keyboard.
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Make sure that the menu stays open when trying to move past the first and last items.
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardMenuBoundaries() throws InterruptedException {
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(false, true);
9223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(getCount() - 1, getCurrentFocusedRow());
9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(true, true);
9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(0, getCurrentFocusedRow());
9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(false, true);
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(getCount() - 1, getCurrentFocusedRow());
9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
10023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test that typing ENTER immediately opening the menu works.
10123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
10323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardMenuEnterOnOpen() throws InterruptedException {
10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hitEnterAndAssertAppMenuDismissed();
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test that hitting ENTER past the top item doesn't crash Chrome.
11023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardEnterAfterMovePastTopItem() throws InterruptedException {
11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(true, true);
11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(0, getCurrentFocusedRow());
11623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hitEnterAndAssertAppMenuDismissed();
11723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
11823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test that hitting ENTER past the bottom item doesn't crash Chrome.
12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Catches regressions for http://crbug.com/181067
12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardEnterAfterMovePastBottomItem() throws InterruptedException {
12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(false, true);
12723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(getCount() - 1, getCurrentFocusedRow());
12823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hitEnterAndAssertAppMenuDismissed();
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test that hitting ENTER on the top item actually triggers the top item.
13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Catches regressions for https://crbug.com/191239 for shrunken menus.
13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
13523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardMenuEnterOnTopItemLandscape() throws InterruptedException {
13823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        showAppMenuAndAssertMenuShown();
14023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(true, false);
14123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(0, getCurrentFocusedRow());
14223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hitEnterAndAssertAppMenuDismissed();
14323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
14423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    /**
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     * Test that hitting ENTER on the top item doesn't crash Chrome.
14723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)     */
14823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @SmallTest
14923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    @Feature({"Browser", "Main"})
15023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    public void testKeyboardMenuEnterOnTopItemPortrait() throws InterruptedException {
15123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        showAppMenuAndAssertMenuShown();
15323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        moveToBoundary(true, false);
15423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertEquals(0, getCurrentFocusedRow());
15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        hitEnterAndAssertAppMenuDismissed();
15623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
15723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    /**
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)     * Test that changing orientation hides the menu.
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)     */
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    @SmallTest
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    @Feature({"Browser", "Main"})
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    public void testChangingOrientationHidesMenu() throws InterruptedException {
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        showAppMenuAndAssertMenuShown();
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        assertTrue("AppMenu did not dismiss",
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                CriteriaHelper.pollForCriteria(new Criteria() {
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    @Override
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    public boolean isSatisfied() {
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        return !mAppMenuHandler.isAppMenuShowing();
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    }
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                }));
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private void showAppMenuAndAssertMenuShown() throws InterruptedException {
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        final View menuButton = getActivity().findViewById(R.id.menu_button);
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        ThreadUtils.runOnUiThread(new Runnable() {
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            @Override
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            public void run() {
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                menuButton.performClick();
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            }
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        });
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        assertTrue("AppMenu did not show",
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                CriteriaHelper.pollForCriteria(new Criteria() {
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    @Override
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    public boolean isSatisfied() {
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        return mAppMenuHandler.isAppMenuShowing();
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    }
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                }));
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private void hitEnterAndAssertAppMenuDismissed() throws InterruptedException {
19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        getInstrumentation().waitForIdleSync();
19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        pressKey(KeyEvent.KEYCODE_ENTER);
19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertTrue("AppMenu did not dismiss",
19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                CriteriaHelper.pollForCriteria(new Criteria() {
19823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    @Override
19923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    public boolean isSatisfied() {
20023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        return !mAppMenuHandler.isAppMenuShowing();
20123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    }
20223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                }));
20323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
20423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
20523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private void moveToBoundary(boolean towardsTop, boolean movePast) throws InterruptedException {
20623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // Move to the boundary.
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        final int end = towardsTop ? 0 : getCount() - 1;
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        int increment = towardsTop ? -1 : 1;
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        for (int index = getCurrentFocusedRow(); index != end; index += increment) {
21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            final int expectedPosition = index + increment;
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            assertTrue("Focus did not move to the next menu item",
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    CriteriaHelper.pollForCriteria(new Criteria() {
21423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        @Override
21523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        public boolean isSatisfied() {
21623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            return getCurrentFocusedRow() == expectedPosition;
21723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        }
21823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    }));
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
22123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // Try moving past it by one.
22223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (movePast) {
22323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
22423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            assertTrue("Focus moved past the edge menu item",
22523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    CriteriaHelper.pollForCriteria(new Criteria() {
22623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        @Override
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        public boolean isSatisfied() {
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            return getCurrentFocusedRow() == end;
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        }
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                    }));
23123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
23223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
23323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        // The menu should stay open.
23423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        assertTrue(mAppMenu.isShowing());
23523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
23623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private void pressKey(final int keycode) {
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        final View view = mAppMenu.getPopup().getListView();
239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        ThreadUtils.runOnUiThread(new Runnable() {
240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            @Override
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            public void run() {
242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode));
243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keycode));
244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            }
245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        });
24623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        getInstrumentation().waitForIdleSync();
24723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
24823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
24923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private int getCurrentFocusedRow() {
25023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ListPopupWindow popup = mAppMenu.getPopup();
25123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (popup == null || popup.getListView() == null) return ListView.INVALID_POSITION;
25223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ListView listView = popup.getListView();
25323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        return listView.getSelectedItemPosition();
25423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private int getCount() {
25723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        ListPopupWindow popup = mAppMenu.getPopup();
25823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        if (popup == null || popup.getListView() == null) return 0;
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        return popup.getListView().getCount();
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
26123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
262