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

[Android] Introduce AppMenuTest and AppMenuAdapterRenderTest

Adds an AppMenuTest for app menu integration tests
 - #testShowHideAppMenu
 - #testShowDestroyAppMenu
 - #testClickMenuItem
 - #testAppMenuBlockers
 - #testSetMenuHighlight_StandardItem
 - #testSetMenuHighlight_Icon
 - #testMenuItemContentChnaged
 - #testHeaderFooter
 - #testAppMenuHiddenOnStopWithNative
 - #testAppMenuHiddenOnConfigurationChange

Also adds a few more tests to AppMenuAdapterTest to shore up test
coverage and adds an AppMenuAdapterRenderTest that runs a suite of
render tests for the various types of menu items supported natively
by the app menu.

This patch includes an update to AnimationFrameTimeHistogram to allow
histogram recording to be disabled for tests.

BUG=966644

Change-Id: I035b10557a9e35ef0e86b315ccd926230bb18bf0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1893984
Commit-Queue: Theresa  <twellington@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712702}
parent 41c87dbd
...@@ -12,6 +12,7 @@ import android.animation.TimeAnimator.TimeListener; ...@@ -12,6 +12,7 @@ import android.animation.TimeAnimator.TimeListener;
import android.util.Log; import android.util.Log;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.RecordHistogram;
/** /**
* Record Android animation frame rate and save it to UMA histogram. This is mainly for monitoring * Record Android animation frame rate and save it to UMA histogram. This is mainly for monitoring
...@@ -72,7 +73,7 @@ public class AnimationFrameTimeHistogram { ...@@ -72,7 +73,7 @@ public class AnimationFrameTimeHistogram {
* successful. * successful.
*/ */
public void endRecording() { public void endRecording() {
if (mRecorder.endRecording()) { if (mRecorder.endRecording() && RecordHistogram.sDisabledBy == null) {
AnimationFrameTimeHistogramJni.get().saveHistogram( AnimationFrameTimeHistogramJni.get().saveHistogram(
mHistogramName, mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount()); mHistogramName, mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount());
} }
......
...@@ -29,7 +29,13 @@ import java.util.Map; ...@@ -29,7 +29,13 @@ import java.util.Map;
@JNINamespace("base::android") @JNINamespace("base::android")
@MainDex @MainDex
public class RecordHistogram { public class RecordHistogram {
private static Throwable sDisabledBy; /**
* Whether recording histograms is currently disabled for testing. Exposed for use in peer
* classes {e.g. AnimationFrameTimeHistogram}.
* Use {@link #setDisabledForTests(boolean)} to set this value.
*/
@VisibleForTesting
public static Throwable sDisabledBy;
private static Map<String, Long> sCache = private static Map<String, Long> sCache =
Collections.synchronizedMap(new HashMap<String, Long>()); Collections.synchronizedMap(new HashMap<String, Long>());
......
...@@ -823,6 +823,7 @@ android_library("chrome_test_java") { ...@@ -823,6 +823,7 @@ android_library("chrome_test_java") {
"//chrome/browser/ui/android/widget:java", "//chrome/browser/ui/android/widget:java",
"//chrome/browser/ui/android/widget:test_support_java", "//chrome/browser/ui/android/widget:test_support_java",
"//chrome/browser/util:java", "//chrome/browser/util:java",
"//chrome/lib/lifecycle/public/android:java",
"//chrome/test/android:chrome_java_test_support", "//chrome/test/android:chrome_java_test_support",
"//chrome/test/android/test_trusted_web_activity:test_trusted_web_activity_java", "//chrome/test/android/test_trusted_web_activity:test_trusted_web_activity_java",
"//components/autofill/android:autofill_java", "//components/autofill/android:autofill_java",
......
...@@ -47,7 +47,12 @@ chrome_test_java_sources = [ ...@@ -47,7 +47,12 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/accessibility/FontSizePrefsTest.java", "javatests/src/org/chromium/chrome/browser/accessibility/FontSizePrefsTest.java",
"javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java", "javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java",
"javatests/src/org/chromium/chrome/browser/appmenu/AppMenuAdapterTest.java", "javatests/src/org/chromium/chrome/browser/appmenu/AppMenuAdapterTest.java",
"javatests/src/org/chromium/chrome/browser/appmenu/AppMenuAdapterRenderTest.java",
"javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java",
"javatests/src/org/chromium/chrome/browser/appmenu/TabbedAppMenuTest.java", "javatests/src/org/chromium/chrome/browser/appmenu/TabbedAppMenuTest.java",
"javatests/src/org/chromium/chrome/browser/appmenu/TestAppMenuDelegate.java",
"javatests/src/org/chromium/chrome/browser/appmenu/TestAppMenuPropertiesDelegate.java",
"javatests/src/org/chromium/chrome/browser/appmenu/TestAppMenuObserver.java",
"javatests/src/org/chromium/chrome/browser/appmenu/DataSaverAppMenuTest.java", "javatests/src/org/chromium/chrome/browser/appmenu/DataSaverAppMenuTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java",
"javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java",
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
Use of this source code is governed by a BSD-style license that can be Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. found in the LICENSE file.
--> -->
<!-- TODO(twellington): Add an item for disabled state. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/light_active_color" /> <item android:state_checked="true" android:color="@color/light_active_color" />
<item android:color="@color/control_normal_color"/> <item android:color="@color/control_normal_color"/>
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
android:src="?android:attr/listChoiceIndicatorMultiple" /> android:src="?android:attr/listChoiceIndicatorMultiple" />
<!-- Displays an icon. --> <!-- Displays an icon. -->
<!-- TODO(twellington): Consider setting a default tint that adjusts when the item is disabled.
currently there are no menu items with icons that are visible but disabled so this behavior
is currently unused. -->
<org.chromium.ui.widget.ChromeImageButton <org.chromium.ui.widget.ChromeImageButton
android:id="@+id/button" android:id="@+id/button"
android:layout_width="56dp" android:layout_width="56dp"
......
...@@ -37,6 +37,7 @@ import org.chromium.base.AnimationFrameTimeHistogram; ...@@ -37,6 +37,7 @@ import org.chromium.base.AnimationFrameTimeHistogram;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.SysUtils; import org.chromium.base.SysUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ui.widget.highlight.ViewHighlighter; import org.chromium.chrome.browser.ui.widget.highlight.ViewHighlighter;
...@@ -297,14 +298,6 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl ...@@ -297,14 +298,6 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
} }
} }
/**
* @return The footer view for the menu or null if one has not been set.
*/
@Nullable
public View getFooterView() {
return mFooterView;
}
private int[] getPopupPosition(int screenRotation, Rect appRect, Rect padding, View anchorView, private int[] getPopupPosition(int screenRotation, Rect appRect, Rect padding, View anchorView,
int popupWidth, int popupHeight, boolean isAnchorAtBottom) { int popupWidth, int popupHeight, boolean isAnchorAtBottom) {
anchorView.getLocationInWindow(mTempLocation); anchorView.getLocationInWindow(mTempLocation);
...@@ -568,4 +561,9 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl ...@@ -568,4 +561,9 @@ class AppMenu implements OnItemClickListener, OnKeyListener, AppMenuAdapter.OnCl
return headerView.getMeasuredHeight(); return headerView.getMeasuredHeight();
} }
@VisibleForTesting
void finishAnimationsForTests() {
if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.end();
}
} }
...@@ -245,6 +245,7 @@ class AppMenuAdapter extends BaseAdapter { ...@@ -245,6 +245,7 @@ class AppMenuAdapter extends BaseAdapter {
holder.title.setEnabled(titleItem.isEnabled()); holder.title.setEnabled(titleItem.isEnabled());
holder.title.setFocusable(titleItem.isEnabled()); holder.title.setFocusable(titleItem.isEnabled());
holder.title.setOnClickListener(v -> mOnClickHandler.onItemClick(titleItem)); holder.title.setOnClickListener(v -> mOnClickHandler.onItemClick(titleItem));
if (TextUtils.isEmpty(titleItem.getTitleCondensed())) { if (TextUtils.isEmpty(titleItem.getTitleCondensed())) {
holder.title.setContentDescription(null); holder.title.setContentDescription(null);
} else { } else {
......
...@@ -25,11 +25,14 @@ public class AppMenuCoordinatorFactory { ...@@ -25,11 +25,14 @@ public class AppMenuCoordinatorFactory {
* @param appMenuDelegate The {@link AppMenuDelegate} for the containing activity. * @param appMenuDelegate The {@link AppMenuDelegate} for the containing activity.
* @param decorView The decor {@link View}, e.g. from Window#getDecorView(), for the containing * @param decorView The decor {@link View}, e.g. from Window#getDecorView(), for the containing
* activity. * activity.
* @param hardwareButtonAnchorView The {@link View} used as an anchor for the menu when it is
* displayed using a hardware butt
*/ */
public static AppMenuCoordinator createAppMenuCoordinator(Context context, public static AppMenuCoordinator createAppMenuCoordinator(Context context,
ActivityLifecycleDispatcher activityLifecycleDispatcher, ActivityLifecycleDispatcher activityLifecycleDispatcher,
MenuButtonDelegate buttonDelegate, AppMenuDelegate appMenuDelegate, View decorView) { MenuButtonDelegate buttonDelegate, AppMenuDelegate appMenuDelegate, View decorView,
return new AppMenuCoordinatorImpl( View hardwareButtonAnchorView) {
context, activityLifecycleDispatcher, buttonDelegate, appMenuDelegate, decorView); return new AppMenuCoordinatorImpl(context, activityLifecycleDispatcher, buttonDelegate,
appMenuDelegate, decorView, hardwareButtonAnchorView);
} }
} }
...@@ -8,7 +8,6 @@ import android.content.Context; ...@@ -8,7 +8,6 @@ import android.content.Context;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
...@@ -51,10 +50,13 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator { ...@@ -51,10 +50,13 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator {
* @param appMenuDelegate The {@link AppMenuDelegate} for the containing activity. * @param appMenuDelegate The {@link AppMenuDelegate} for the containing activity.
* @param decorView The decor {@link View}, e.g. from Window#getDecorView(), for the containing * @param decorView The decor {@link View}, e.g. from Window#getDecorView(), for the containing
* activity. * activity.
* @param hardwareButtonAnchorView The {@link View} used as an anchor for the menu when it is
* displayed using a hardware button.
*/ */
public AppMenuCoordinatorImpl(Context context, public AppMenuCoordinatorImpl(Context context,
ActivityLifecycleDispatcher activityLifecycleDispatcher, ActivityLifecycleDispatcher activityLifecycleDispatcher,
MenuButtonDelegate buttonDelegate, AppMenuDelegate appMenuDelegate, View decorView) { MenuButtonDelegate buttonDelegate, AppMenuDelegate appMenuDelegate, View decorView,
View hardwareButtonAnchorView) {
mContext = context; mContext = context;
mButtonDelegate = buttonDelegate; mButtonDelegate = buttonDelegate;
mAppMenuDelegate = appMenuDelegate; mAppMenuDelegate = appMenuDelegate;
...@@ -62,7 +64,7 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator { ...@@ -62,7 +64,7 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator {
mAppMenuHandler = new AppMenuHandlerImpl(mAppMenuPropertiesDelegate, mAppMenuDelegate, mAppMenuHandler = new AppMenuHandlerImpl(mAppMenuPropertiesDelegate, mAppMenuDelegate,
mAppMenuPropertiesDelegate.getAppMenuLayoutId(), decorView, mAppMenuPropertiesDelegate.getAppMenuLayoutId(), decorView,
activityLifecycleDispatcher); activityLifecycleDispatcher, hardwareButtonAnchorView);
} }
@Override @Override
...@@ -106,7 +108,7 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator { ...@@ -106,7 +108,7 @@ class AppMenuCoordinatorImpl implements AppMenuCoordinator {
// Testing methods // Testing methods
@VisibleForTesting @VisibleForTesting
public AppMenuHandlerImpl getAppMenuHandlerImplForTesting() { AppMenuHandlerImpl getAppMenuHandlerImplForTesting() {
return mAppMenuHandler; return mAppMenuHandler;
} }
} }
...@@ -73,17 +73,20 @@ class AppMenuHandlerImpl ...@@ -73,17 +73,20 @@ class AppMenuHandlerImpl
* activity. * activity.
* @param activityLifecycleDispatcher The {@link ActivityLifecycleDispatcher} for the containing * @param activityLifecycleDispatcher The {@link ActivityLifecycleDispatcher} for the containing
* activity. * activity.
* @param hardwareButtonAnchorView The {@link View} used as an anchor for the menu when it is
* displayed using a hardware button.
*/ */
public AppMenuHandlerImpl(AppMenuPropertiesDelegate delegate, AppMenuDelegate appMenuDelegate, public AppMenuHandlerImpl(AppMenuPropertiesDelegate delegate, AppMenuDelegate appMenuDelegate,
int menuResourceId, View decorView, int menuResourceId, View decorView,
ActivityLifecycleDispatcher activityLifecycleDispatcher) { ActivityLifecycleDispatcher activityLifecycleDispatcher,
View hardwareButtonAnchorView) {
mAppMenuDelegate = appMenuDelegate; mAppMenuDelegate = appMenuDelegate;
mDelegate = delegate; mDelegate = delegate;
mDecorView = decorView; mDecorView = decorView;
mBlockers = new ArrayList<>(); mBlockers = new ArrayList<>();
mObservers = new ArrayList<>(); mObservers = new ArrayList<>();
mMenuResourceId = menuResourceId; mMenuResourceId = menuResourceId;
mHardwareButtonMenuAnchor = mDecorView.findViewById(R.id.menu_anchor_stub); mHardwareButtonMenuAnchor = hardwareButtonAnchorView;
mActivityLifecycleDispatcher = activityLifecycleDispatcher; mActivityLifecycleDispatcher = activityLifecycleDispatcher;
mActivityLifecycleDispatcher.register(this); mActivityLifecycleDispatcher.register(this);
......
...@@ -279,7 +279,8 @@ public class RootUiCoordinator ...@@ -279,7 +279,8 @@ public class RootUiCoordinator
if (mActivity.supportsAppMenu()) { if (mActivity.supportsAppMenu()) {
mAppMenuCoordinator = AppMenuCoordinatorFactory.createAppMenuCoordinator(mActivity, mAppMenuCoordinator = AppMenuCoordinatorFactory.createAppMenuCoordinator(mActivity,
mActivity.getLifecycleDispatcher(), mActivity.getToolbarManager(), mActivity, mActivity.getLifecycleDispatcher(), mActivity.getToolbarManager(), mActivity,
mActivity.getWindow().getDecorView()); mActivity.getWindow().getDecorView(),
mActivity.getWindow().getDecorView().findViewById(R.id.menu_anchor_stub));
mActivity.getToolbarManager().onAppMenuInitialized( mActivity.getToolbarManager().onAppMenuInitialized(
mAppMenuCoordinator.getAppMenuHandler(), mAppMenuCoordinator.getAppMenuHandler(),
mAppMenuCoordinator.getAppMenuPropertiesDelegate()); mAppMenuCoordinator.getAppMenuPropertiesDelegate());
......
...@@ -3,6 +3,7 @@ include_rules = [ ...@@ -3,6 +3,7 @@ include_rules = [
"+chrome/browser/ui/android/styles", "+chrome/browser/ui/android/styles",
"+chrome/browser/ui/android/widget", "+chrome/browser/ui/android/widget",
"+chrome/browser/util/android", "+chrome/browser/util/android",
"+chrome/lib/lifecycle/public",
"+components/autofill/android/java/src/org/chromium/components/autofill", "+components/autofill/android/java/src/org/chromium/components/autofill",
"+components/background_task_scheduler/android/java", "+components/background_task_scheduler/android/java",
"+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks", "+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks",
......
<?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:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"
android:fillColor="#010101"/>
</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. -->
<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,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
</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. -->
<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="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</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. -->
<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="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</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. -->
<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="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</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. -->
<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="M18.7,12.4c-0.28,-0.16 -0.57,-0.29 -0.86,-0.4 0.29,-0.11 0.58,-0.24 0.86,-0.4 1.92,-1.11 2.99,-3.12 3,-5.19 -1.79,-1.03 -4.07,-1.11 -6,0 -0.28,0.16 -0.54,0.35 -0.78,0.54 0.05,-0.31 0.08,-0.63 0.08,-0.95 0,-2.22 -1.21,-4.15 -3,-5.19C10.21,1.85 9,3.78 9,6c0,0.32 0.03,0.64 0.08,0.95 -0.24,-0.2 -0.5,-0.39 -0.78,-0.55 -1.92,-1.11 -4.2,-1.03 -6,0 0,2.07 1.07,4.08 3,5.19 0.28,0.16 0.57,0.29 0.86,0.4 -0.29,0.11 -0.58,0.24 -0.86,0.4 -1.92,1.11 -2.99,3.12 -3,5.19 1.79,1.03 4.07,1.11 6,0 0.28,-0.16 0.54,-0.35 0.78,-0.54 -0.05,0.32 -0.08,0.64 -0.08,0.96 0,2.22 1.21,4.15 3,5.19 1.79,-1.04 3,-2.97 3,-5.19 0,-0.32 -0.03,-0.64 -0.08,-0.95 0.24,0.2 0.5,0.38 0.78,0.54 1.92,1.11 4.2,1.03 6,0 -0.01,-2.07 -1.08,-4.08 -3,-5.19zM12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
</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. -->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="HardcodedText"
android:text="Menu Footer"/>
\ No newline at end of file
<?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. -->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="HardcodedText"
android:text="Menu Header"/>
\ No newline at end of file
<?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. -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText">
<item android:id="@+id/menu_item_one"
android:title="Menu Item One" />
<item android:id="@+id/menu_item_two"
android:title="Menu Item Two" />
<item android:id="@+id/menu_item_three"
android:title="Menu Item Three" />
<item android:id="@+id/icon_row_menu_id"
android:title="@null">
<menu>
<item android:id="@+id/icon_one"
android:title="Icon One" />
<item android:id="@+id/icon_two"
android:title="Icon Two" />
<item android:id="@+id/icon_three"
android:title="Icon Three" />
</menu>
</item>
</menu>
\ No newline at end of file
// 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 static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.TITLE_1;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.TITLE_2;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.TITLE_3;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.TITLE_4;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.TITLE_5;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.buildIconRow;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.buildMenuItem;
import static org.chromium.chrome.browser.appmenu.AppMenuAdapterTest.buildTitleMenuItem;
import android.graphics.drawable.Drawable;
import android.support.test.filters.MediumTest;
import android.support.v7.content.res.AppCompatResources;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.chromium.base.test.params.ParameterAnnotations;
import org.chromium.base.test.params.ParameterProvider;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.chrome.test.R;
import org.chromium.chrome.test.ui.DummyUiActivityTestCase;
import org.chromium.chrome.test.util.RenderTestRule;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Render tests for {@link AppMenuAdapter}.
*/
@RunWith(ParameterizedRunner.class)
@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
public class AppMenuAdapterRenderTest extends DummyUiActivityTestCase {
// TODO(twellington): Add night mode variant after NightModeTestUtils methods are modularized
// in https://crbug.com/1002287.
/**
* Parameter set controlling whether the menu item being rendered is enabled.
*/
public static class EnabledParams implements ParameterProvider {
private static List<ParameterSet> sEnabledDisabledParams =
Arrays.asList(new ParameterSet().value(false).name("Enabled"),
new ParameterSet().value(true).name("Disabled"));
@Override
public List<ParameterSet> getParameters() {
return sEnabledDisabledParams;
}
}
@Rule
public RenderTestRule mRenderTestRule =
new RenderTestRule("chrome/test/data/android/render_tests");
@Override
public void setUpTest() throws Exception {
super.setUpTest();
MockitoAnnotations.initMocks(this);
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testStandardMenuItem(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
MenuItem item = buildMenuItem(1, TITLE_1, enabled);
mRenderTestRule.render(createView(item), "standard");
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testStandardMenuItem_Icon(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
Drawable icon =
AppCompatResources.getDrawable(getActivity(), R.drawable.test_ic_vintage_filter);
MenuItem item = buildMenuItem(1, TITLE_1, enabled, icon);
mRenderTestRule.render(createView(item), "standard_with_icon");
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testTitleButtonMenuItem_Icon(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
Drawable icon =
AppCompatResources.getDrawable(getActivity(), R.drawable.test_ic_vintage_filter);
MenuItem item = buildTitleMenuItem(1, 2, TITLE_2, 3, TITLE_3, icon, false, false, enabled);
mRenderTestRule.render(createView(item), "title_button_icon");
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testTitleButtonMenuItem_Checkbox_Checked(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
MenuItem item = buildTitleMenuItem(1, 2, TITLE_2, 3, TITLE_3, null, true, true, enabled);
mRenderTestRule.render(createView(item), "title_button_checkbox_checked");
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testTitleButtonMenuItem_Checkbox_Unchecked(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
MenuItem item = buildTitleMenuItem(1, 2, TITLE_2, 3, TITLE_3, null, true, false, enabled);
mRenderTestRule.render(createView(item), "title_button_checkbox_unchecked");
}
@Test
@MediumTest
@Feature("RenderTest")
@ParameterAnnotations.UseMethodParameter(EnabledParams.class)
public void testIconRow_ThreeIcons(boolean enabled) throws IOException {
setRenderTestPrefix(enabled);
Drawable icon1 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_forward_black_24dp);
Drawable icon2 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_star_border_black_24dp);
Drawable icon3 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_downward_black_24dp);
MenuItem item = buildIconRow(1, 2, TITLE_1, icon1, 3, TITLE_2, icon2, 4, TITLE_3, icon3, 0,
"", null, 0, "", null, enabled);
mRenderTestRule.render(createView(item), "iconrow_three_icons");
}
@Test
@MediumTest
@Feature("RenderTest")
public void testIconRow_FourIcons() throws IOException {
setRenderTestPrefix(true);
Drawable icon1 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_forward_black_24dp);
Drawable icon2 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_star_border_black_24dp);
Drawable icon3 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_downward_black_24dp);
Drawable icon4 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_info_outline_black_24dp);
MenuItem item = buildIconRow(1, 2, TITLE_1, icon1, 3, TITLE_2, icon2, 4, TITLE_3, icon3, 5,
TITLE_4, icon4, 0, "", null, true);
mRenderTestRule.render(createView(item), "iconrow_four_icons");
}
@Test
@MediumTest
@Feature("RenderTest")
public void testIconRow_FiveIcons() throws IOException {
setRenderTestPrefix(true);
Drawable icon1 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_forward_black_24dp);
Drawable icon2 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_star_border_black_24dp);
Drawable icon3 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_arrow_downward_black_24dp);
Drawable icon4 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_info_outline_black_24dp);
Drawable icon5 = AppCompatResources.getDrawable(
getActivity(), R.drawable.test_ic_refresh_black_24dp);
MenuItem item = buildIconRow(1, 2, TITLE_1, icon1, 3, TITLE_2, icon2, 4, TITLE_3, icon3, 5,
TITLE_4, icon4, 6, TITLE_5, icon5, true);
mRenderTestRule.render(createView(item), "iconrow_five_icons");
}
private void setRenderTestPrefix(boolean enabled) {
mRenderTestRule.setVariantPrefix(enabled ? "Enabled" : "Disabled");
}
private View createView(MenuItem item) {
List<MenuItem> items = new ArrayList<>();
items.add(item);
AppMenuAdapter adapter = new AppMenuAdapter(new AppMenuAdapterTest.TestClickHandler(),
items, getActivity().getLayoutInflater(), 0, null);
// Create a new FrameLayout to set as the main content view.
FrameLayout parentView = new FrameLayout(getActivity());
parentView.setLayoutParams(new FrameLayout.LayoutParams(
getActivity().getResources().getDimensionPixelSize(R.dimen.menu_width),
FrameLayout.LayoutParams.WRAP_CONTENT));
// Create a view for the provided menu item and attach it to the content view.
TestThreadUtils.runOnUiThreadBlocking(() -> {
View view = adapter.getView(0, null, parentView);
parentView.addView(view);
getActivity().setContentView(parentView);
});
return parentView.getChildAt(0);
}
}
...@@ -43,7 +43,7 @@ import org.chromium.ui.test.util.UiRestriction; ...@@ -43,7 +43,7 @@ import org.chromium.ui.test.util.UiRestriction;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
/** /**
* Tests AppMenu popup * Tests tabbed mode app menu popup.
*/ */
@RunWith(ChromeJUnit4ClassRunner.class) @RunWith(ChromeJUnit4ClassRunner.class)
@RetryOnFailure @RetryOnFailure
...@@ -178,29 +178,6 @@ public class TabbedAppMenuTest { ...@@ -178,29 +178,6 @@ public class TabbedAppMenuTest {
hitEnterAndAssertAppMenuDismissed(); hitEnterAndAssertAppMenuDismissed();
} }
/**
* Test that changing orientation hides the menu.
*/
/*
@SmallTest
@Feature({"Browser", "Main"})
*/
@Test
@DisabledTest(message = "crbug.com/458193")
public void testChangingOrientationHidesMenu() {
mActivityTestRule.getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
showAppMenuAndAssertMenuShown();
mActivityTestRule.getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
CriteriaHelper.pollInstrumentationThread(new Criteria("AppMenu did not dismiss") {
@Override
public boolean isSatisfied() {
return !mAppMenuHandler.isAppMenuShowing();
}
});
}
@Test @Test
@SmallTest @SmallTest
@Feature({"Browser", "Main"}) @Feature({"Browser", "Main"})
......
// 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.os.Bundle;
import androidx.annotation.Nullable;
import org.chromium.base.test.util.CallbackHelper;
class TestAppMenuDelegate implements AppMenuDelegate {
public final CallbackHelper itemSelectedCallbackHelper = new CallbackHelper();
public int lastSelectedItemId;
@Override
public boolean onOptionsItemSelected(int itemId, @Nullable Bundle menuItemData) {
lastSelectedItemId = itemId;
itemSelectedCallbackHelper.notifyCalled();
return true;
}
@Override
public AppMenuPropertiesDelegate createAppMenuPropertiesDelegate() {
return new TestAppMenuPropertiesDelegate();
}
}
// 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 org.chromium.base.test.util.CallbackHelper;
/**
* AppMenuObserver that notifies callbacks when app menu events occur.
*/
public class TestAppMenuObserver implements AppMenuObserver {
public CallbackHelper menuShownCallback = new CallbackHelper();
public CallbackHelper menuHiddenCallback = new CallbackHelper();
public CallbackHelper menuHighlightChangedCallback = new CallbackHelper();
public boolean menuHighlighting;
@Override
public void onMenuVisibilityChanged(boolean isVisible) {
if (isVisible) {
menuShownCallback.notifyCalled();
} else {
menuHiddenCallback.notifyCalled();
}
}
@Override
public void onMenuHighlightChanged(boolean highlighting) {
menuHighlighting = highlighting;
menuHighlightChangedCallback.notifyCalled();
}
}
// 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.os.Bundle;
import android.support.v7.content.res.AppCompatResources;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.Nullable;
import org.chromium.base.ContextUtils;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.chrome.test.R;
import java.util.List;
class TestAppMenuPropertiesDelegate implements AppMenuPropertiesDelegate {
public final CallbackHelper menuDismissedCallback = new CallbackHelper();
public final CallbackHelper footerInflatedCallback = new CallbackHelper();
public final CallbackHelper headerInflatedCallback = new CallbackHelper();
public int footerResourceId;
public int headerResourceId;
public boolean enableAppIconRow;
@Override
public void destroy() {}
@Override
public int getAppMenuLayoutId() {
return R.menu.test_menu;
}
@Nullable
@Override
public List<CustomViewBinder> getCustomViewBinders() {
return null;
}
@Override
public void prepareMenu(Menu menu, AppMenuHandler handler) {
menu.findItem(R.id.icon_row_menu_id).setVisible(enableAppIconRow);
if (enableAppIconRow) {
menu.findItem(R.id.icon_one)
.setIcon(AppCompatResources.getDrawable(ContextUtils.getApplicationContext(),
R.drawable.test_ic_arrow_forward_black_24dp));
menu.findItem(R.id.icon_two)
.setIcon(AppCompatResources.getDrawable(ContextUtils.getApplicationContext(),
R.drawable.test_ic_arrow_forward_black_24dp));
menu.findItem(R.id.icon_three)
.setIcon(AppCompatResources.getDrawable(ContextUtils.getApplicationContext(),
R.drawable.test_ic_arrow_forward_black_24dp));
}
}
@Nullable
@Override
public Bundle getBundleForMenuItem(MenuItem item) {
return null;
}
@Override
public void loadingStateChanged(boolean isLoading) {}
@Override
public void onMenuDismissed() {
menuDismissedCallback.notifyCalled();
}
@Override
public int getFooterResourceId() {
return footerResourceId;
}
@Override
public int getHeaderResourceId() {
return headerResourceId;
}
@Override
public boolean shouldShowFooter(int maxMenuHeight) {
return footerResourceId != 0;
}
@Override
public boolean shouldShowHeader(int maxMenuHeight) {
return headerResourceId != 0;
}
@Override
public void onFooterViewInflated(AppMenuHandler appMenuHandler, View view) {
footerInflatedCallback.notifyCalled();
}
@Override
public void onHeaderViewInflated(AppMenuHandler appMenuHandler, View view) {
headerInflatedCallback.notifyCalled();
}
}
...@@ -19,15 +19,14 @@ import org.junit.Test; ...@@ -19,15 +19,14 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.Restriction;
import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.appmenu.AppMenuObserver;
import org.chromium.chrome.browser.appmenu.AppMenuTestSupport; import org.chromium.chrome.browser.appmenu.AppMenuTestSupport;
import org.chromium.chrome.browser.appmenu.TestAppMenuObserver;
import org.chromium.chrome.browser.util.UrlConstants; import org.chromium.chrome.browser.util.UrlConstants;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
...@@ -106,22 +105,6 @@ public class UpdateMenuItemHelperTest { ...@@ -106,22 +105,6 @@ public class UpdateMenuItemHelperTest {
} }
} }
private static class TestAppMenuObserver implements AppMenuObserver {
CallbackHelper mMenuShownCallback = new CallbackHelper();
CallbackHelper mMenuHiddenCallback = new CallbackHelper();
@Override
public void onMenuVisibilityChanged(boolean isVisible) {
if (isVisible) {
mMenuShownCallback.notifyCalled();
} else {
mMenuHiddenCallback.notifyCalled();
}
}
@Override
public void onMenuHighlightChanged(boolean highlighting) {}
}
private MockVersionNumberGetter mMockVersionNumberGetter; private MockVersionNumberGetter mMockVersionNumberGetter;
private MockMarketURLGetter mMockMarketURLGetter; private MockMarketURLGetter mMockMarketURLGetter;
...@@ -278,7 +261,7 @@ public class UpdateMenuItemHelperTest { ...@@ -278,7 +261,7 @@ public class UpdateMenuItemHelperTest {
Assert.assertEquals("Incorrect item not clicked histogram count after item clicked", 0, Assert.assertEquals("Incorrect item not clicked histogram count after item clicked", 0,
getTotalItemNotClickedCount()); getTotalItemNotClickedCount());
mMenuObserver.mMenuHiddenCallback.waitForCallback(0); mMenuObserver.menuHiddenCallback.waitForCallback(0);
waitForAppMenuDimissedRunnable(); waitForAppMenuDimissedRunnable();
Assert.assertEquals("Incorrect item clicked histogram count after menu dismissed", 1, Assert.assertEquals("Incorrect item clicked histogram count after menu dismissed", 1,
...@@ -311,21 +294,21 @@ public class UpdateMenuItemHelperTest { ...@@ -311,21 +294,21 @@ public class UpdateMenuItemHelperTest {
} }
private void showAppMenuAndAssertMenuShown() throws TimeoutException { private void showAppMenuAndAssertMenuShown() throws TimeoutException {
int currentCallCount = mMenuObserver.mMenuShownCallback.getCallCount(); int currentCallCount = mMenuObserver.menuShownCallback.getCallCount();
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
AppMenuTestSupport.showAppMenu( AppMenuTestSupport.showAppMenu(
mActivityTestRule.getAppMenuCoordinator(), null, false, false); mActivityTestRule.getAppMenuCoordinator(), null, false, false);
}); });
mMenuObserver.mMenuShownCallback.waitForCallback(currentCallCount); mMenuObserver.menuShownCallback.waitForCallback(currentCallCount);
} }
private void hideAppMenuAndAssertMenuShown() throws TimeoutException { private void hideAppMenuAndAssertMenuShown() throws TimeoutException {
int currentCallCount = mMenuObserver.mMenuHiddenCallback.getCallCount(); int currentCallCount = mMenuObserver.menuHiddenCallback.getCallCount();
TestThreadUtils.runOnUiThreadBlocking( TestThreadUtils.runOnUiThreadBlocking(
() -> mActivityTestRule.getAppMenuCoordinator().getAppMenuHandler().hideAppMenu()); () -> mActivityTestRule.getAppMenuCoordinator().getAppMenuHandler().hideAppMenu());
mMenuObserver.mMenuHiddenCallback.waitForCallback(currentCallCount); mMenuObserver.menuHiddenCallback.waitForCallback(currentCallCount);
} }
private int getTotalItemClickedCount() { private int getTotalItemClickedCount() {
......
a4201a720f7bd86bd2d2ee430c5d474a46045c49
\ No newline at end of file
aee3b1f0f4ebedc3f638a67a1ac10e8a1f3ad26f
\ No newline at end of file
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