[go: nahoru, domu]

blob: e830b1ecfb14a8168d4aad521cd63f2e270c8318 [file] [log] [blame]
/*
* Copyright (C) 2015 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 androidx.appcompat.app;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
import android.content.Context;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.test.R;
import androidx.core.view.ViewCompat;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
public class KeyEventsTestCaseWithWindowDecor extends BaseKeyEventsTestCase<WindowDecorAppCompatActivity> {
public KeyEventsTestCaseWithWindowDecor() {
super(WindowDecorAppCompatActivity.class);
}
@Test
@LargeTest
public void testUnhandledKeys() throws Throwable {
final ViewGroup container = mActivityTestRule.getActivity().findViewById(R.id.test_content);
final MockUnhandledKeyListener listener = new MockUnhandledKeyListener();
final View mockView1 = new HandlerView(mActivityTestRule.getActivity());
final HandlerView mockView2 = new HandlerView(mActivityTestRule.getActivity());
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
// Validity check: should work before any unhandled stuff is used. This just needs to run
// without causing a crash
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
container.addView(mockView2);
mockView2.setFocusableInTouchMode(true);
mockView2.requestFocus();
}
});
instrumentation.waitForIdleSync();
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
// check that we're fine if a view consumes a down but not an up.
mockView2.respondToDown = true;
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertTrue(mockView2.gotDown);
mockView2.reset();
ViewCompat.addOnUnhandledKeyEventListener(mockView1, listener);
// Before the view is attached, it shouldn't respond to anything
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertFalse(listener.fired());
// Once attached, it should start receiving fallback events
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
container.addView(mockView1);
}
});
instrumentation.waitForIdleSync();
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertTrue(listener.fired());
listener.reset();
// Views should still take precedence
mockView2.respondToDown = true;
mockView2.respondToUp = true;
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
mockView2.requestFocus();
}
});
instrumentation.waitForIdleSync();
assertTrue(mockView2.isFocused());
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertTrue(mockView2.gotDown);
assertFalse(listener.fired());
// Still receives fallback with focused view
mockView2.reset();
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertTrue(listener.fired());
listener.reset();
// Receives events before Window.Callback (eg BACK)
listener.mReturnVal = true;
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
assertTrue(listener.fired());
assertFalse(mActivityTestRule.getActivity().wasOnBackPressedCalled());
listener.mReturnVal = false;
listener.reset();
// If removed, it should not receive fallbacks anymore
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
ViewCompat.removeOnUnhandledKeyEventListener(mockView1, listener);
}
});
instrumentation.waitForIdleSync();
instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B);
assertFalse(listener.fired());
}
private static class MockUnhandledKeyListener implements
ViewCompat.OnUnhandledKeyEventListenerCompat {
public View mLastView = null;
public boolean mGotUp = false;
public boolean mReturnVal = false;
@Override
public boolean onUnhandledKeyEvent(View v, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mLastView = v;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
mGotUp = true;
}
return mReturnVal;
}
public void reset() {
mLastView = null;
mGotUp = false;
}
public boolean fired() {
return mLastView != null && mGotUp;
}
}
/**
* A View which can be set to consume or not consume key events.
*/
private static class HandlerView extends View {
HandlerView(Context ctx) {
super(ctx);
}
public boolean respondToDown = false;
public boolean respondToUp = false;
public boolean gotDown = false;
public void reset() {
respondToUp = respondToDown = gotDown = false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent evt) {
if (evt.getAction() == KeyEvent.ACTION_DOWN && respondToDown) {
gotDown = true;
return true;
} else if (evt.getAction() == KeyEvent.ACTION_UP && respondToUp) {
return true;
}
return super.dispatchKeyEvent(evt);
}
}
}