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.browser.contextmenu; 6 7import android.view.ContextMenu; 8import android.view.ContextMenu.ContextMenuInfo; 9import android.view.HapticFeedbackConstants; 10import android.view.Menu; 11import android.view.MenuItem; 12import android.view.MenuItem.OnMenuItemClickListener; 13import android.view.View; 14import android.view.View.OnCreateContextMenuListener; 15 16import org.chromium.base.CalledByNative; 17import org.chromium.base.VisibleForTesting; 18import org.chromium.content.browser.ContentViewCore; 19 20/** 21 * A helper class that handles generating context menus for {@link ContentViewCore}s. 22 */ 23public class ContextMenuHelper implements OnCreateContextMenuListener, OnMenuItemClickListener { 24 private long mNativeContextMenuHelper; 25 26 private ContextMenuPopulator mPopulator; 27 private ContextMenuParams mCurrentContextMenuParams; 28 29 private ContextMenuHelper(long nativeContextMenuHelper) { 30 mNativeContextMenuHelper = nativeContextMenuHelper; 31 } 32 33 @CalledByNative 34 private static ContextMenuHelper create(long nativeContextMenuHelper) { 35 return new ContextMenuHelper(nativeContextMenuHelper); 36 } 37 38 @CalledByNative 39 private void destroy() { 40 mNativeContextMenuHelper = 0; 41 } 42 43 /** 44 * @param populator A {@link ContextMenuPopulator} that is responsible for managing and showing 45 * context menus. 46 */ 47 @CalledByNative 48 private void setPopulator(ContextMenuPopulator populator) { 49 mPopulator = populator; 50 } 51 52 /** 53 * Starts showing a context menu for {@code view} based on {@code params}. 54 * @param contentViewCore The {@link ContentViewCore} to show the menu to. 55 * @param params The {@link ContextMenuParams} that indicate what menu items to show. 56 */ 57 @CalledByNative 58 private void showContextMenu(ContentViewCore contentViewCore, ContextMenuParams params) { 59 final View view = contentViewCore.getContainerView(); 60 61 if (!shouldShowMenu(params) 62 || view == null 63 || view.getVisibility() != View.VISIBLE 64 || view.getParent() == null) { 65 return; 66 } 67 68 mCurrentContextMenuParams = params; 69 70 view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 71 contentViewCore.setIgnoreRemainingTouchEvents(); 72 view.setOnCreateContextMenuListener(this); 73 view.showContextMenu(); 74 } 75 76 /** 77 * Starts a download based on the current {@link ContextMenuParams}. 78 * @param isLink Whether or not the download target is a link. 79 */ 80 public void startContextMenuDownload(boolean isLink) { 81 if (mNativeContextMenuHelper != 0) nativeOnStartDownload(mNativeContextMenuHelper, isLink); 82 } 83 84 @Override 85 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 86 if (!shouldShowMenu(mCurrentContextMenuParams)) return; 87 88 if (mCurrentContextMenuParams.isCustomMenu()) { 89 for (int i = 0; i < mCurrentContextMenuParams.getCustomMenuSize(); i++) { 90 menu.add(Menu.NONE, i, Menu.NONE, mCurrentContextMenuParams.getCustomLabelAt(i)); 91 } 92 } else { 93 assert mPopulator != null; 94 mPopulator.buildContextMenu(menu, v.getContext(), mCurrentContextMenuParams); 95 } 96 97 for (int i = 0; i < menu.size(); i++) { 98 menu.getItem(i).setOnMenuItemClickListener(this); 99 } 100 } 101 102 @Override 103 public boolean onMenuItemClick(MenuItem item) { 104 if (mCurrentContextMenuParams.isCustomMenu()) { 105 if (mNativeContextMenuHelper != 0) { 106 final int action = mCurrentContextMenuParams.getCustomActionAt(item.getItemId()); 107 nativeOnCustomItemSelected(mNativeContextMenuHelper, action); 108 } 109 return true; 110 } else { 111 return mPopulator.onItemSelected(this, mCurrentContextMenuParams, item.getItemId()); 112 } 113 } 114 115 /** 116 * @return The {@link ContextMenuPopulator} responsible for populating the context menu. 117 */ 118 @VisibleForTesting 119 public ContextMenuPopulator getPopulator() { 120 return mPopulator; 121 } 122 123 private boolean shouldShowMenu(ContextMenuParams params) { 124 // Custom menus are handled by this class and do not require a ContextMenuPopulator. 125 return params.isCustomMenu() || 126 (mPopulator != null && mPopulator.shouldShowContextMenu(params)); 127 } 128 129 private native void nativeOnStartDownload(long nativeContextMenuHelper, boolean isLink); 130 private native void nativeOnCustomItemSelected(long nativeContextMenuHelper, int action); 131}