BaseKeyEventsTestCase.java revision 2f769dc974bd526d945efe8a644f3f89112e08fe
1/*
2 * Copyright (C) 2015 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
17package android.support.v7.app;
18
19import org.junit.Test;
20
21import android.support.v7.appcompat.test.R;
22import android.support.v7.view.ActionMode;
23import android.view.KeyEvent;
24import android.view.Menu;
25import android.view.MenuItem;
26
27import java.util.concurrent.atomic.AtomicBoolean;
28
29public abstract class BaseKeyEventsTestCase<A extends BaseTestActivity>
30        extends BaseInstrumentationTestCase<A> {
31
32    protected BaseKeyEventsTestCase(Class<A> activityClass) {
33        super(activityClass);
34    }
35
36    @Test
37    public void testBackDismissesActionMode() {
38        final AtomicBoolean destroyed = new AtomicBoolean();
39
40        getActivity().runOnUiThread(new Runnable() {
41            @Override
42            public void run() {
43                getActivity().startSupportActionMode(new ActionMode.Callback() {
44                    @Override
45                    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
46                        mode.getMenuInflater().inflate(R.menu.sample_actions, menu);
47                        return true;
48                    }
49
50                    @Override
51                    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
52                        return false;
53                    }
54
55                    @Override
56                    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
57                        return false;
58                    }
59
60                    @Override
61                    public void onDestroyActionMode(ActionMode mode) {
62                        destroyed.set(true);
63                    }
64                });
65            }
66        });
67
68        getInstrumentation().waitForIdleSync();
69        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
70        getInstrumentation().waitForIdleSync();
71
72        assertFalse("Activity was not destroyed", getActivity().isDestroyed());
73        assertTrue("ActionMode was destroyed", destroyed.get());
74    }
75
76    @Test
77    public void testBackCollapsesSearchView() throws InterruptedException {
78        // First expand the SearchView
79        getActivity().runOnUiThread(new Runnable() {
80            @Override
81            public void run() {
82                assertTrue("SearchView expanded", getActivity().expandSearchView());
83            }
84        });
85        getInstrumentation().waitForIdleSync();
86
87        // Now send a back press
88        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
89        getInstrumentation().waitForIdleSync();
90
91        if (getActivity().isSearchViewExpanded()) {
92            // If the SearchView is still expanded, it's probably because it had focus and the
93            // first back removed the focus. Send another.
94            getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
95            getInstrumentation().waitForIdleSync();
96        }
97
98        // Check that the Activity is still running and the SearchView is not expanded
99        assertFalse("Activity was not destroyed", getActivity().isDestroyed());
100        assertFalse("SearchView was collapsed", getActivity().isSearchViewExpanded());
101    }
102
103    @Test
104    public void testMenuPressInvokesPanelCallbacks() throws InterruptedException {
105        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
106        getInstrumentation().waitForIdleSync();
107        assertTrue("onMenuOpened called", getActivity().wasOnMenuOpenedCalled());
108
109        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
110        getInstrumentation().waitForIdleSync();
111        assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
112    }
113
114    @Test
115    public void testBackPressWithMenuInvokesOnPanelClosed() throws InterruptedException {
116        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
117        getInstrumentation().waitForIdleSync();
118
119        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
120        getInstrumentation().waitForIdleSync();
121        assertTrue("onPanelClosed called", getActivity().wasOnPanelClosedCalled());
122    }
123
124    @Test
125    public void testBackPressWithEmptyMenuDestroysActivity() throws InterruptedException {
126        repopulateWithEmptyMenu();
127
128        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
129        getInstrumentation().waitForIdleSync();
130
131        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
132        waitAssertDestroyed();
133    }
134
135    @Test
136    public void testDelKeyEventReachesActivity() {
137        // First send the event
138        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DEL);
139        getInstrumentation().waitForIdleSync();
140
141        KeyEvent downEvent = getActivity().getInvokedKeyDownEvent();
142        assertNotNull("onKeyDown called", downEvent);
143        assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_DEL, downEvent.getKeyCode());
144
145        KeyEvent upEvent = getActivity().getInvokedKeyUpEvent();
146        assertNotNull("onKeyUp called", upEvent);
147        assertEquals("onKeyUp event matches", KeyEvent.KEYCODE_DEL, upEvent.getKeyCode());
148    }
149
150    @Test
151    public void testMenuKeyEventReachesActivity() throws InterruptedException {
152        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
153        getInstrumentation().waitForIdleSync();
154
155        KeyEvent downEvent = getActivity().getInvokedKeyDownEvent();
156        assertNotNull("onKeyDown called", downEvent);
157        assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, downEvent.getKeyCode());
158
159        KeyEvent upEvent = getActivity().getInvokedKeyUpEvent();
160        assertNotNull("onKeyUp called", upEvent);
161        assertEquals("onKeyDown event matches", KeyEvent.KEYCODE_MENU, upEvent.getKeyCode());
162    }
163
164    private void waitAssertDestroyed() throws InterruptedException {
165        int count = 0;
166        while (count++ < 10) {
167            if (!getActivity().isDestroyed()) {
168                Thread.sleep(50);
169            } else {
170                break;
171            }
172        }
173        assertTrue("Activity destroyed", getActivity().isDestroyed());
174    }
175
176    private void repopulateWithEmptyMenu() throws InterruptedException {
177        int count = 0;
178        getActivity().setShouldPopulateOptionsMenu(false);
179        while (count++ < 10) {
180            Menu menu = getActivity().getMenu();
181            if (menu == null || menu.size() != 0) {
182                Thread.sleep(50);
183            } else {
184                return;
185            }
186        }
187    }
188}
189