Commit af8ff5d4 authored by Theresa Wellington's avatar Theresa Wellington Committed by Commit Bot

Add more tests for app menu tests to increase coverage

Adds a suite of tests to cover functionality in AppMenuButtonHelperImpl.
Also adds more tests for AppMenu click, long-press and key event
handling and a variety of tests to boost coverage of app menu classes.

BUG=966644

Change-Id: I132b095cf576567052cacce7f7b60dbb8327c7f5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1900653
Commit-Queue: Theresa  <twellington@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714224}
parent f31159e3
......@@ -15,6 +15,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java",
"junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java",
"junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java",
"junit/src/org/chromium/chrome/browser/appmenu/AppMenuPopupPositionTest.java",
"junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java",
"junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskSchedulerTest.java",
"junit/src/org/chromium/chrome/browser/background_sync/BackgroundSyncBackgroundTaskTest.java",
......
......@@ -267,8 +267,10 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
int popupHeight = setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight,
sizingPadding, footerHeight, headerHeight, anchorView);
int[] popupPosition = getPopupPosition(mCurrentScreenRotation, visibleDisplayFrame,
sizingPadding, anchorView, popupWidth, popupHeight, showFromBottom);
int[] popupPosition = getPopupPosition(mTempLocation, mIsByPermanentButton,
mNegativeSoftwareVerticalOffset, mNegativeVerticalOffsetNotTopAnchored,
mCurrentScreenRotation, visibleDisplayFrame, sizingPadding, anchorView, popupWidth,
popupHeight, showFromBottom, anchorView.getRootView().getLayoutDirection());
mPopup.setContentView(contentView);
mPopup.showAtLocation(
......@@ -298,16 +300,19 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
}
}
private int[] getPopupPosition(int screenRotation, Rect appRect, Rect padding, View anchorView,
int popupWidth, int popupHeight, boolean isAnchorAtBottom) {
anchorView.getLocationInWindow(mTempLocation);
int anchorViewX = mTempLocation[0];
int anchorViewY = mTempLocation[1];
@VisibleForTesting
static int[] getPopupPosition(int[] tempLocation, boolean isByPermanentButton,
int negativeSoftwareVerticalOffset, int negativeVerticalOffsetNotTopAnchored,
int screenRotation, Rect appRect, Rect padding, View anchorView, int popupWidth,
int popupHeight, boolean isAnchorAtBottom, int viewLayoutDirection) {
anchorView.getLocationInWindow(tempLocation);
int anchorViewX = tempLocation[0];
int anchorViewY = tempLocation[1];
int[] offsets = new int[2];
// If we have a hardware menu button, locate the app menu closer to the estimated
// hardware menu button location.
if (mIsByPermanentButton) {
if (isByPermanentButton) {
int horizontalOffset = -anchorViewX;
switch (screenRotation) {
case Surface.ROTATION_0:
......@@ -328,21 +333,21 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
// padding of the background.
offsets[1] = -padding.bottom;
} else {
offsets[1] = -mNegativeSoftwareVerticalOffset;
offsets[1] = -negativeSoftwareVerticalOffset;
// If the anchor is at the bottom of the screen, align the popup with the bottom of the
// anchor. The anchor may not be fully visible, so
// (appRect.bottom - anchorViewLocationOnScreenY) is used to determine the visible
// bottom edge of the anchor view.
if (isAnchorAtBottom) {
anchorView.getLocationOnScreen(mTempLocation);
int anchorViewLocationOnScreenY = mTempLocation[1];
anchorView.getLocationOnScreen(tempLocation);
int anchorViewLocationOnScreenY = tempLocation[1];
offsets[1] += appRect.bottom - anchorViewLocationOnScreenY - popupHeight;
offsets[1] -= mNegativeVerticalOffsetNotTopAnchored;
if (!mIsByPermanentButton) offsets[1] += padding.bottom;
offsets[1] -= negativeVerticalOffsetNotTopAnchored;
offsets[1] += padding.bottom;
}
if (anchorView.getRootView().getLayoutDirection() != View.LAYOUT_DIRECTION_RTL) {
if (viewLayoutDirection != View.LAYOUT_DIRECTION_RTL) {
offsets[0] = anchorView.getWidth() - popupWidth;
}
}
......@@ -364,10 +369,15 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
@Override
public boolean onItemLongClick(MenuItem menuItem, View view) {
if (!menuItem.isEnabled()) return false;
Context context = ContextUtils.getApplicationContext();
CharSequence titleCondensed = menuItem.getTitleCondensed();
CharSequence message =
TextUtils.isEmpty(titleCondensed) ? menuItem.getTitle() : titleCondensed;
return showToastForItem(message, view);
}
@VisibleForTesting
boolean showToastForItem(CharSequence message, View view) {
Context context = ContextUtils.getApplicationContext();
return Toast.showAnchoredToast(context, view, message);
}
......@@ -545,4 +555,9 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
void finishAnimationsForTests() {
if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.end();
}
@VisibleForTesting
AppMenuAdapter getAdapterForTests() {
return mAdapter;
}
}
......@@ -13,6 +13,8 @@ import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
/** A UI coordinator the app menu. */
class AppMenuCoordinatorImpl implements AppMenuCoordinator {
private static Boolean sHasPermanentMenuKeyForTesting;
/**
* Factory which creates the AppMenuHandlerImpl.
*/
......@@ -79,7 +81,9 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator {
public void showAppMenuForKeyboardEvent() {
if (mAppMenuHandler == null || !mAppMenuHandler.shouldShowAppMenu()) return;
boolean hasPermanentMenuKey = ViewConfiguration.get(mContext).hasPermanentMenuKey();
boolean hasPermanentMenuKey = sHasPermanentMenuKeyForTesting != null
? sHasPermanentMenuKeyForTesting.booleanValue()
: ViewConfiguration.get(mContext).hasPermanentMenuKey();
mAppMenuHandler.showAppMenu(
hasPermanentMenuKey ? null : mButtonDelegate.getMenuButtonView(), false,
mButtonDelegate.isMenuFromBottom());
......@@ -111,4 +115,13 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator {
AppMenuHandlerImpl getAppMenuHandlerImplForTesting() {
return mAppMenuHandler;
}
/**
* @param hasPermanentMenuKey Overrides {@link ViewConfiguration#hasPermanentMenuKey()} for
* testing. Pass null to reset.
*/
@VisibleForTesting
static void setHasPermanentMenuKeyForTesting(Boolean hasPermanentMenuKey) {
sHasPermanentMenuKeyForTesting = hasPermanentMenuKey;
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="21"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent" >
<ImageButton
android:id="@+id/top_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="@drawable/test_ic_more_vert_black_24dp"
android:layout_gravity="top|end"
tools:ignore="ContentDescription" />
<ImageButton
android:id="@+id/bottom_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="@drawable/test_ic_more_vert_black_24dp"
android:layout_gravity="bottom|end"
tools:ignore="ContentDescription" />
<View
android:id="@+id/menu_anchor_stub"
android:layout_width="0px"
android:layout_height="0px"
android:layout_gravity="bottom|start" />
</FrameLayout>
\ No newline at end of file
......@@ -18,7 +18,8 @@
<item android:id="@+id/icon_one"
android:title="Icon One" />
<item android:id="@+id/icon_two"
android:title="Icon Two" />
android:title="Icon Two"
android:titleCondensed="2" />
<item android:id="@+id/icon_three"
android:title="Icon Three" />
</menu>
......
......@@ -310,6 +310,28 @@ public class AppMenuAdapterTest extends DummyUiActivityTestCase {
view5.getTag(R.id.menu_item_enter_anim_id));
}
@Test
@MediumTest
public void testTitleMenuItem_ToggleCheckbox() {
List<MenuItem> items = new ArrayList<>();
items.add(buildTitleMenuItem(1, 2, TITLE_1, 3, TITLE_2));
AppMenuAdapter adapter = new AppMenuAdapter(
mClickHandler, items, getActivity().getLayoutInflater(), 0, null);
ViewGroup parentView = getActivity().findViewById(android.R.id.content);
View view = adapter.getView(0, null, parentView);
AppMenuItemIcon checkbox = view.findViewById(R.id.checkbox);
Assert.assertFalse("Checkbox should be unchecked", checkbox.isChecked());
TestThreadUtils.runOnUiThreadBlocking(() -> checkbox.toggle());
Assert.assertTrue("Checkbox should be checked", checkbox.isChecked());
TestThreadUtils.runOnUiThreadBlocking(() -> checkbox.toggle());
Assert.assertFalse("Checkbox should be unchecked again", checkbox.isChecked());
}
static MenuItem buildMenuItem(int id, CharSequence title) {
return buildMenuItem(id, title, true);
}
......
......@@ -42,6 +42,8 @@ class TestAppMenuPropertiesDelegate implements AppMenuPropertiesDelegate {
@Override
public void prepareMenu(Menu menu, AppMenuHandler handler) {
menu.findItem(R.id.menu_item_two).setEnabled(false);
menu.findItem(R.id.icon_row_menu_id).setVisible(enableAppIconRow);
if (enableAppIconRow) {
menu.findItem(R.id.icon_one)
......@@ -53,6 +55,7 @@ class TestAppMenuPropertiesDelegate implements AppMenuPropertiesDelegate {
menu.findItem(R.id.icon_three)
.setIcon(AppCompatResources.getDrawable(ContextUtils.getApplicationContext(),
R.drawable.test_ic_arrow_forward_black_24dp));
menu.findItem(R.id.icon_three).setEnabled(false);
}
}
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.appmenu;
import android.graphics.Rect;
import android.view.Surface;
import android.view.View;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.test.support.DisableHistogramsRule;
/**
* Tests AppMenu#getPopupPosition.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class AppMenuPopupPositionTest {
@Rule
public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
private final int[] mTempLocation = new int[2];
private final int mAppWidth = 400;
private final int mAppHeight = 1000;
private final int mBgPadding = 10;
private final int mPopupWidth = 300;
private final int mPopupHeight = 500;
private final int mAnchorX = 100;
private final int mAnchorY = 300;
private final int mAnchorWidth = 40;
private final int mNegativeSoftwareVerticalOffset = 25;
private final int mNegativeSoftwareVerticalOffsetNotTopAnchored = 15;
private final View mAnchorView = Mockito.mock(View.class);
private final Rect mAppRect = new Rect(0, 0, mAppWidth, mAppHeight);
private final Rect mBgPaddingRect = new Rect(mBgPadding, mBgPadding, mBgPadding, mBgPadding);
@Before
public void setUp() {
Mockito.doAnswer((InvocationOnMock invocation) -> {
mTempLocation[0] = mAnchorX;
mTempLocation[1] = mAnchorY;
return null;
})
.when(mAnchorView)
.getLocationInWindow(mTempLocation);
Mockito.doAnswer((InvocationOnMock invocation) -> {
mTempLocation[0] = mAnchorX;
mTempLocation[1] = mAnchorY;
return null;
})
.when(mAnchorView)
.getLocationOnScreen(mTempLocation);
Mockito.when(mAnchorView.getWidth()).thenReturn(mAnchorWidth);
}
@Test
public void testPermanentButton_Portrait() {
// Popup should should be in the middle of the screen, anchored near the anchor view.
int expectedX = (mAppWidth - mPopupWidth) / 2;
int expectedY = mAnchorY - mBgPadding;
int[] results =
getPopupPosition(true, Surface.ROTATION_0, false, View.LAYOUT_DIRECTION_LTR);
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
results = getPopupPosition(true, Surface.ROTATION_180, false, View.LAYOUT_DIRECTION_LTR);
Assert.assertEquals("Incorrect popup x for rotation 180", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y for rotation 180", expectedY, results[1]);
}
@Test
public void testPermanentButton_Landscape() {
int[] results =
getPopupPosition(true, Surface.ROTATION_90, false, View.LAYOUT_DIRECTION_LTR);
// Popup should be positioned toward the right edge of the screen, anchored near the anchor
// view.
int expectedX = mAppWidth - mPopupWidth;
int expectedY = mAnchorY - mBgPadding;
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
// Popup should be positioned toward the left edge of the screen, anchored near the anchor
// view.
expectedX = 0;
results = getPopupPosition(true, Surface.ROTATION_270, false, View.LAYOUT_DIRECTION_LTR);
Assert.assertEquals("Incorrect popup x for rotation 180", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y for rotation 180", expectedY, results[1]);
}
@Test
public void testTopButton_LTR() {
int[] results =
getPopupPosition(false, Surface.ROTATION_0, false, View.LAYOUT_DIRECTION_LTR);
// The top right edge of the popup should be aligned with the top right edge of the button.
int expectedX = mAnchorX + mAnchorWidth - mPopupWidth;
int expectedY = mAnchorY - mNegativeSoftwareVerticalOffset;
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
}
@Test
public void testTopButton_RTL() {
int[] results =
getPopupPosition(false, Surface.ROTATION_0, false, View.LAYOUT_DIRECTION_RTL);
// The top left edge of the popup should be aligned with the top left edge of the button.
int expectedX = mAnchorX;
int expectedY = mAnchorY - mNegativeSoftwareVerticalOffset;
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
}
@Test
public void testBottomButton_LTR() {
int[] results =
getPopupPosition(false, Surface.ROTATION_0, true, View.LAYOUT_DIRECTION_LTR);
// The bottom popup menu positioning assumes the anchor is at the bottom of the screen. It
// aligns the popup based on the bottom of the screen plus offsets.
int expectedX = mAnchorX + mAnchorWidth - mPopupWidth;
int expectedY = mAppHeight - mPopupHeight - mNegativeSoftwareVerticalOffset
- mNegativeSoftwareVerticalOffsetNotTopAnchored + mBgPadding;
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
}
@Test
public void testBottomButton_RTL() {
int[] results =
getPopupPosition(false, Surface.ROTATION_0, true, View.LAYOUT_DIRECTION_RTL);
// The bottom popup menu positioning assumes the anchor is at the bottom of the screen. It
// aligns the popup based on the bottom of the screen plus offsets.
int expectedX = mAnchorX;
int expectedY = mAppHeight - mPopupHeight - mNegativeSoftwareVerticalOffset
- mNegativeSoftwareVerticalOffsetNotTopAnchored + mBgPadding;
Assert.assertEquals("Incorrect popup x", expectedX, results[0]);
Assert.assertEquals("Incorrect popup y", expectedY, results[1]);
}
private int[] getPopupPosition(boolean isByPermanentButton, int rotation,
boolean isAnchorAtBottom, int layoutDirection) {
return AppMenu.getPopupPosition(mTempLocation, isByPermanentButton,
mNegativeSoftwareVerticalOffset, mNegativeSoftwareVerticalOffsetNotTopAnchored,
rotation, mAppRect, mBgPaddingRect, mAnchorView, mPopupWidth, mPopupHeight,
isAnchorAtBottom, layoutDirection);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment