blob: 17177637e3d731d4d6355da68b0ad52666926f6b [file] [log] [blame]
/*
* Copyright (C) 2016 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.android.compatibility.common.util.CtsTouchUtils;
import com.android.compatibility.common.util.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test {@link View}.
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TooltipTest {
private static final String LOG_TAG = "TooltipTest";
private static final long TIMEOUT_DELTA = 10000;
private static final long WAIT_MARGIN = 100;
private Instrumentation mInstrumentation;
private Activity mActivity;
private ViewGroup mTopmostView;
private ViewGroup mGroupView;
private View mNoTooltipView;
private View mTooltipView;
private View mNoTooltipView2;
private View mEmptyGroup;
@Rule
public ActivityTestRule<TooltipActivity> mActivityRule =
new ActivityTestRule<>(TooltipActivity.class);
@Rule
public ActivityTestRule<CtsActivity> mCtsActivityRule =
new ActivityTestRule<>(CtsActivity.class, false, false);
@Before
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
mTopmostView = (ViewGroup) mActivity.findViewById(R.id.tooltip_layout);
mGroupView = (ViewGroup) mActivity.findViewById(R.id.tooltip_group);
mNoTooltipView = mActivity.findViewById(R.id.no_tooltip);
mTooltipView = mActivity.findViewById(R.id.has_tooltip);
mNoTooltipView2 = mActivity.findViewById(R.id.no_tooltip2);
mEmptyGroup = mActivity.findViewById(R.id.empty_group);
PollingCheck.waitFor(TIMEOUT_DELTA, mActivity::hasWindowFocus);
}
private void waitOut(long msDelay) {
try {
Thread.sleep(msDelay + WAIT_MARGIN);
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Wait interrupted. Test may fail!", e);
}
}
private void setTooltipText(View view, CharSequence tooltipText) throws Throwable {
mActivityRule.runOnUiThread(() -> view.setTooltipText(tooltipText));
}
private boolean hasTooltip(View view) {
final View tooltipView = view.getTooltipView();
return tooltipView != null && tooltipView.getParent() != null;
}
private void addView(ViewGroup parent, View view) throws Throwable {
mActivityRule.runOnUiThread(() -> parent.addView(view));
mInstrumentation.waitForIdleSync();
}
private void removeView(View view) throws Throwable {
mActivityRule.runOnUiThread(() -> ((ViewGroup) (view.getParent())).removeView(view));
mInstrumentation.waitForIdleSync();
}
private void setVisibility(View view, int visibility) throws Throwable {
mActivityRule.runOnUiThread(() -> view.setVisibility(visibility));
}
private void setClickable(View view) throws Throwable {
mActivityRule.runOnUiThread(() -> view.setClickable(true));
}
private void setLongClickable(View view) throws Throwable {
mActivityRule.runOnUiThread(() -> view.setLongClickable(true));
}
private void setContextClickable(View view) throws Throwable {
mActivityRule.runOnUiThread(() -> view.setContextClickable(true));
}
private void callPerformLongClick(View view) throws Throwable {
mActivityRule.runOnUiThread(() -> view.performLongClick(0, 0));
}
private void requestLowProfileSystemUi() throws Throwable {
final int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
mActivityRule.runOnUiThread(() -> mTooltipView.setSystemUiVisibility(flag));
PollingCheck.waitFor(TIMEOUT_DELTA,
() -> (mTooltipView.getWindowSystemUiVisibility() & flag) == flag);
}
private void injectKeyPress(View target, int keyCode, int duration) throws Throwable {
if (target != null) {
mActivityRule.runOnUiThread(() -> {
target.setFocusableInTouchMode(true);
target.requestFocus();
});
mInstrumentation.waitForIdleSync();
assertTrue(target.isFocused());
}
mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
waitOut(duration);
mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
}
private void injectArbitraryShortKeyPress() throws Throwable {
injectKeyPress(null, KeyEvent.KEYCODE_0, 0);
}
private void injectLongKeyPress(View target, int keyCode) throws Throwable {
injectKeyPress(target, keyCode, ViewConfiguration.getLongPressTimeout());
}
private void injectLongEnter(View target) throws Throwable {
injectLongKeyPress(target, KeyEvent.KEYCODE_ENTER);
}
private void injectShortClick(View target) {
CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, target);
}
private void injectLongClick(View target) {
CtsTouchUtils.emulateLongPressOnView(mInstrumentation, target,
target.getWidth() / 2, target.getHeight() / 2);
}
private void injectMotionEvent(MotionEvent event) {
mInstrumentation.sendPointerSync(event);
}
private void injectHoverMove(View target, int offsetX, int offsetY) {
injectMotionEvent(obtainMouseEvent(
target, MotionEvent.ACTION_HOVER_MOVE, offsetX, offsetY));
}
private void injectHoverMove(View target) {
injectHoverMove(target, 0, 0);
}
private void injectLongHoverMove(View target) {
injectHoverMove(target);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
}
private static MotionEvent obtainMouseEvent(View target, int action, int offsetX, int offsetY) {
final long eventTime = SystemClock.uptimeMillis();
final int[] xy = new int[2];
target.getLocationOnScreen(xy);
MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action,
xy[0] + target.getWidth() / 2 + offsetX, xy[1] + target.getHeight() / 2 + offsetY,
0);
event.setSource(InputDevice.SOURCE_MOUSE);
return event;
}
@Test
public void testGetSetTooltip() throws Throwable {
// No tooltip set in resource
assertEquals(null, mNoTooltipView.getTooltipText());
// Set the tooltip, read it back
final String tooltipText1 = "new tooltip";
setTooltipText(mNoTooltipView, tooltipText1);
assertEquals(tooltipText1, mNoTooltipView.getTooltipText());
// Clear the tooltip.
setTooltipText(mNoTooltipView, null);
assertEquals(null, mNoTooltipView.getTooltipText());
// Check the tooltip set in resource
assertEquals("tooltip text", mTooltipView.getTooltipText());
// Clear the tooltip set in resource
setTooltipText(mTooltipView, null);
assertEquals(null, mTooltipView.getTooltipText());
// Set the tooltip again, read it back
final String tooltipText2 = "new tooltip 2";
setTooltipText(mTooltipView, tooltipText2);
assertEquals(tooltipText2, mTooltipView.getTooltipText());
}
@Test
public void testNoTooltipWhenNotSet() throws Throwable {
callPerformLongClick(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
injectLongClick(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
injectLongEnter(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
injectLongHoverMove(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
}
@Test
public void testNoTooltipOnDisabledView() throws Throwable {
mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
injectLongClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
injectLongEnter(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
injectLongHoverMove(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testUpdateOpenTooltip() throws Throwable {
callPerformLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
setTooltipText(mTooltipView, "updated tooltip");
assertTrue(hasTooltip(mTooltipView));
setTooltipText(mTooltipView, null);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testTooltipHidesOnActivityFocusChange() throws Throwable {
callPerformLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
CtsActivity activity = mCtsActivityRule.launchActivity(null);
PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mActivity.hasWindowFocus());
assertFalse(hasTooltip(mTooltipView));
activity.finish();
}
@Test
public void testTooltipHidesOnWindowFocusChange() throws Throwable {
callPerformLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Show a context menu on another widget.
mActivity.registerForContextMenu(mNoTooltipView);
mActivityRule.runOnUiThread(() -> mNoTooltipView.showContextMenu(0, 0));
PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mTooltipView.hasWindowFocus());
mInstrumentation.waitForIdleSync();
assertFalse(hasTooltip(mTooltipView));
}
// Tests for tooltips triggered by long click.
@Test
public void testShortClickDoesNotShowTooltip() throws Throwable {
injectShortClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testPerformLongClickShowsTooltipImmediately() throws Throwable {
callPerformLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipBlockedByLongClickListener() throws Throwable {
mTooltipView.setOnLongClickListener(v -> true);
injectLongClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipBlockedByContextMenu() throws Throwable {
mActivity.registerForContextMenu(mTooltipView);
injectLongClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipOnNonClickableView() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipOnClickableView() throws Throwable {
setClickable(mTooltipView);
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipOnLongClickableView() throws Throwable {
setLongClickable(mTooltipView);
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipOnContextClickableView() throws Throwable {
setContextClickable(mTooltipView);
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipStaysOnMouseMove() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Tooltip stays while the mouse moves over the widget.
injectHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Long-click-triggered tooltip stays while the mouse to another widget.
injectHoverMove(mNoTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipHidesAfterUp() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Long-click-triggered tooltip hides after ACTION_UP (with a delay).
waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipHidesOnClick() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipHidesOnClickElsewhere() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongClickTooltipHidesOnKey() throws Throwable {
injectLongClick(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectArbitraryShortKeyPress();
assertFalse(hasTooltip(mTooltipView));
}
// Tests for tooltips triggered by long key press.
@Test
public void testShortKeyPressDoesNotShowTooltip() throws Throwable {
injectKeyPress(null, KeyEvent.KEYCODE_ENTER, 0);
assertFalse(hasTooltip(mTooltipView));
injectKeyPress(mTooltipView, KeyEvent.KEYCODE_ENTER, 0);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongArbitraryKeyPressDoesNotShowTooltip() throws Throwable {
injectLongKeyPress(mTooltipView, KeyEvent.KEYCODE_0);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressWithoutFocusDoesNotShowTooltip() throws Throwable {
injectLongEnter(null);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressOnAnotherViewDoesNotShowTooltip() throws Throwable {
injectLongEnter(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipOnNonClickableView() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipOnClickableView() throws Throwable {
setClickable(mTooltipView);
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipOnLongClickableView() throws Throwable {
setLongClickable(mTooltipView);
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipOnContextClickableView() throws Throwable {
setContextClickable(mTooltipView);
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipStaysOnMouseMove() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Tooltip stays while the mouse moves over the widget.
injectHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Long-keypress-triggered tooltip stays while the mouse to another widget.
injectHoverMove(mNoTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipHidesAfterUp() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Long-keypress-triggered tooltip hides after ACTION_UP (with a delay).
waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipHidesOnClick() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipHidesOnClickElsewhere() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testLongKeyPressTooltipHidesOnKey() throws Throwable {
injectLongEnter(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectArbitraryShortKeyPress();
assertFalse(hasTooltip(mTooltipView));
}
// Tests for tooltips triggered by mouse hover.
@Test
public void testMouseClickDoesNotShowTooltip() throws Throwable {
injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_DOWN, 0, 0));
injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_PRESS, 0, 0));
injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_RELEASE, 0, 0));
injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_UP, 0, 0));
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverDoesNotShowTooltipImmediately() throws Throwable {
injectHoverMove(mTooltipView, 0, 0);
assertFalse(hasTooltip(mTooltipView));
injectHoverMove(mTooltipView, 1, 1);
assertFalse(hasTooltip(mTooltipView));
injectHoverMove(mTooltipView, 2, 2);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverExitCancelsPendingTooltip() throws Throwable {
injectHoverMove(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
injectLongHoverMove(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipOnClickableView() throws Throwable {
setClickable(mTooltipView);
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipOnLongClickableView() throws Throwable {
setLongClickable(mTooltipView);
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipOnContextClickableView() throws Throwable {
setContextClickable(mTooltipView);
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipStaysOnMouseMove() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Tooltip stays while the mouse moves over the widget.
injectHoverMove(mTooltipView, 1, 1);
assertTrue(hasTooltip(mTooltipView));
injectHoverMove(mTooltipView, 2, 2);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnExit() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
// Tooltip hides once the mouse moves out of the widget.
injectHoverMove(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnClick() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnClickOnElsewhere() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mNoTooltipView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnKey() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
injectArbitraryShortKeyPress();
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnTimeout() throws Throwable {
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
waitOut(ViewConfiguration.getHoverTooltipHideTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipHidesOnShortTimeout() throws Throwable {
requestLowProfileSystemUi();
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
waitOut(ViewConfiguration.getHoverTooltipHideShortTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipWithHoverListener() throws Throwable {
mTooltipView.setOnHoverListener((v, event) -> true);
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipUnsetWhileHovering() throws Throwable {
injectHoverMove(mTooltipView);
setTooltipText(mTooltipView, null);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipDisableWhileHovering() throws Throwable {
injectHoverMove(mTooltipView);
mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipFromParent() throws Throwable {
// Hover listeners should not interfere with tooltip dispatch.
mNoTooltipView.setOnHoverListener((v, event) -> true);
mTooltipView.setOnHoverListener((v, event) -> true);
setTooltipText(mTopmostView, "tooltip");
// Hover over a child with a tooltip works normally.
injectLongHoverMove(mTooltipView);
assertFalse(hasTooltip(mTopmostView));
assertTrue(hasTooltip(mTooltipView));
injectShortClick(mTopmostView);
assertFalse(hasTooltip(mTooltipView));
// Hover over a child with no tooltip triggers a tooltip on its parent.
injectLongHoverMove(mNoTooltipView2);
assertFalse(hasTooltip(mNoTooltipView2));
assertTrue(hasTooltip(mTopmostView));
injectShortClick(mTopmostView);
assertFalse(hasTooltip(mTopmostView));
// Same but the child is and empty view group.
injectLongHoverMove(mEmptyGroup);
assertFalse(hasTooltip(mEmptyGroup));
assertTrue(hasTooltip(mTopmostView));
injectShortClick(mTopmostView);
assertFalse(hasTooltip(mTopmostView));
// Hover over a grandchild with no tooltip triggers a tooltip on its grandparent.
injectLongHoverMove(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
assertTrue(hasTooltip(mTopmostView));
// Move to another child one level up, the tooltip stays.
injectHoverMove(mNoTooltipView2);
assertTrue(hasTooltip(mTopmostView));
injectShortClick(mTopmostView);
assertFalse(hasTooltip(mTopmostView));
// Set a tooltip on the intermediate parent, now it is showing tooltips.
setTooltipText(mGroupView, "tooltip");
injectLongHoverMove(mNoTooltipView);
assertFalse(hasTooltip(mNoTooltipView));
assertFalse(hasTooltip(mTopmostView));
assertTrue(hasTooltip(mGroupView));
// Move out of this group, the tooltip is now back on the grandparent.
injectLongHoverMove(mNoTooltipView2);
assertFalse(hasTooltip(mGroupView));
assertTrue(hasTooltip(mTopmostView));
injectShortClick(mTopmostView);
assertFalse(hasTooltip(mTopmostView));
}
@Test
public void testMouseHoverTooltipRemoveWhileWaiting() throws Throwable {
// Remove the view while hovering.
injectHoverMove(mTooltipView);
removeView(mTooltipView);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
addView(mGroupView, mTooltipView);
// Remove and re-add the view while hovering.
injectHoverMove(mTooltipView);
removeView(mTooltipView);
addView(mGroupView, mTooltipView);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
// Remove the view's parent while hovering.
injectHoverMove(mTooltipView);
removeView(mGroupView);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
addView(mTopmostView, mGroupView);
// Remove and re-add view's parent while hovering.
injectHoverMove(mTooltipView);
removeView(mGroupView);
addView(mTopmostView, mGroupView);
waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverTooltipRemoveWhileShowing() throws Throwable {
// Remove the view while showing the tooltip.
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
removeView(mTooltipView);
assertFalse(hasTooltip(mTooltipView));
addView(mGroupView, mTooltipView);
assertFalse(hasTooltip(mTooltipView));
// Remove the view's parent while showing the tooltip.
injectLongHoverMove(mTooltipView);
assertTrue(hasTooltip(mTooltipView));
removeView(mGroupView);
assertFalse(hasTooltip(mTooltipView));
addView(mTopmostView, mGroupView);
assertFalse(hasTooltip(mTooltipView));
}
@Test
public void testMouseHoverOverlap() throws Throwable {
final View parent = mActivity.findViewById(R.id.overlap_group);
final View child1 = mActivity.findViewById(R.id.overlap1);
final View child2 = mActivity.findViewById(R.id.overlap2);
final View child3 = mActivity.findViewById(R.id.overlap3);
injectLongHoverMove(parent);
assertTrue(hasTooltip(child3));
setVisibility(child3, View.GONE);
injectLongHoverMove(parent);
assertTrue(hasTooltip(child2));
setTooltipText(child2, null);
injectLongHoverMove(parent);
assertTrue(hasTooltip(child1));
setVisibility(child1, View.INVISIBLE);
injectLongHoverMove(parent);
assertTrue(hasTooltip(parent));
}
@Test
public void testTooltipInPopup() throws Throwable {
TextView popupContent = new TextView(mActivity);
mActivityRule.runOnUiThread(() -> {
popupContent.setText("Popup view");
popupContent.setTooltipText("Tooltip");
PopupWindow popup = new PopupWindow(popupContent,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popup.showAtLocation(mGroupView, Gravity.CENTER, 0, 0);
});
mInstrumentation.waitForIdleSync();
injectLongClick(popupContent);
assertTrue(hasTooltip(popupContent));
}
}