1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.chrome.test.util.browser.contextmenu; 6 7import android.test.ActivityInstrumentationTestCase2; 8import android.text.TextUtils; 9import android.view.ContextMenu; 10import android.view.MenuItem; 11 12import junit.framework.Assert; 13 14import org.chromium.chrome.browser.EmptyTabObserver; 15import org.chromium.chrome.browser.Tab; 16import org.chromium.content.browser.test.util.CallbackHelper; 17import org.chromium.content.browser.test.util.Criteria; 18import org.chromium.content.browser.test.util.CriteriaHelper; 19import org.chromium.content.browser.test.util.DOMUtils; 20 21import java.lang.ref.WeakReference; 22import java.util.concurrent.TimeoutException; 23 24/** 25 * A utility class to help open and interact with context menus triggered by a WebContents. 26 */ 27public class ContextMenuUtils { 28 /** 29 * Callback helper that also provides access to the last display ContextMenu. 30 */ 31 private static class OnContextMenuShownHelper extends CallbackHelper { 32 private WeakReference<ContextMenu> mContextMenu; 33 34 public void notifyCalled(ContextMenu menu) { 35 mContextMenu = new WeakReference<ContextMenu>(menu); 36 notifyCalled(); 37 } 38 39 public ContextMenu getContextMenu() { 40 assert getCallCount() > 0; 41 return mContextMenu.get(); 42 } 43 } 44 45 /** 46 * Opens a context menu. 47 * @param testCase The test harness. 48 * @param tab The tab to open a context menu for. 49 * @param openerDOMNodeId The DOM node to long press to open the context menu for. 50 * @return The {@link ContextMenu} that was opened. 51 * @throws InterruptedException 52 * @throws TimeoutException 53 */ 54 public static ContextMenu openContextMenu(ActivityInstrumentationTestCase2 testCase, 55 Tab tab, String openerDOMNodeId) 56 throws InterruptedException, TimeoutException { 57 final OnContextMenuShownHelper helper = new OnContextMenuShownHelper(); 58 tab.addObserver(new EmptyTabObserver() { 59 @Override 60 public void onContextMenuShown(Tab tab, ContextMenu menu) { 61 helper.notifyCalled(menu); 62 } 63 }); 64 int callCount = helper.getCallCount(); 65 DOMUtils.longPressNode(testCase, tab.getContentViewCore(), openerDOMNodeId); 66 67 helper.waitForCallback(callCount); 68 return helper.getContextMenu(); 69 } 70 71 /** 72 * Opens and selects an item from a context menu. 73 * @param testCase The test harness. 74 * @param tab The tab to open a context menu for. 75 * @param openerDOMNodeId The DOM node to long press to open the context menu for. 76 * @param itemId The context menu item ID to select. 77 * @throws InterruptedException 78 * @throws TimeoutException 79 */ 80 public static void selectContextMenuItem(ActivityInstrumentationTestCase2 testCase, 81 Tab tab, String openerDOMNodeId, 82 final int itemId) throws InterruptedException, TimeoutException { 83 ContextMenu menu = openContextMenu(testCase, tab, openerDOMNodeId); 84 Assert.assertNotNull("Failed to open context menu", menu); 85 86 selectOpenContextMenuItem(testCase, menu, itemId); 87 } 88 89 /** 90 * Opens and selects an item from a context menu. 91 * @param testCase The test harness. 92 * @param tab The tab to open a context menu for. 93 * @param openerDOMNodeId The DOM node to long press to open the context menu for. 94 * @param itemTitle The title of the context menu item to select. 95 * @throws InterruptedException 96 * @throws TimeoutException 97 */ 98 public static void selectContextMenuItemByTitle(ActivityInstrumentationTestCase2 testCase, 99 Tab tab, String openerDOMNodeId, 100 String itemTitle) throws InterruptedException, TimeoutException { 101 102 ContextMenu menu = openContextMenu(testCase, tab, openerDOMNodeId); 103 Assert.assertNotNull("Failed to open context menu", menu); 104 105 Integer itemId = null; 106 for (int i = 0; i < menu.size(); i++) { 107 MenuItem item = menu.getItem(i); 108 if (TextUtils.equals(item.getTitle(), itemTitle)) { 109 itemId = item.getItemId(); 110 break; 111 } 112 } 113 Assert.assertNotNull("Couldn't find context menu item for '" + itemTitle + "'", itemId); 114 115 selectOpenContextMenuItem(testCase, menu, itemId); 116 } 117 118 private static void selectOpenContextMenuItem(final ActivityInstrumentationTestCase2 testCase, 119 final ContextMenu menu, final int itemId) throws InterruptedException { 120 MenuItem item = menu.findItem(itemId); 121 Assert.assertNotNull("Could not find '" + itemId + "' in menu", item); 122 Assert.assertTrue("'" + itemId + "' is not visible", item.isVisible()); 123 Assert.assertTrue("'" + itemId + "' is not enabled", item.isEnabled()); 124 125 testCase.getInstrumentation().runOnMainSync(new Runnable() { 126 @Override 127 public void run() { 128 boolean activated = menu.performIdentifierAction(itemId, 0); 129 Assert.assertTrue("Failed to activate '" + itemId + "' in menu", activated); 130 } 131 }); 132 133 Assert.assertTrue("Activity did not regain focus.", 134 CriteriaHelper.pollForCriteria(new Criteria() { 135 @Override 136 public boolean isSatisfied() { 137 return testCase.getActivity().hasWindowFocus(); 138 } 139 })); 140 } 141}