1 // Copyright 2012 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 5 package org.chromium.content.browser; 6 7 import android.content.ClipboardManager; 8 import android.content.Context; 9 import android.view.ActionMode; 10 import android.view.Menu; 11 import android.view.MenuItem; 12 13 import org.chromium.content.R; 14 15 /** 16 * An ActionMode.Callback for in-page selection. This class handles both the editable and 17 * non-editable cases. 18 */ 19 public class SelectActionModeCallback implements ActionMode.Callback { 20 /** 21 * An interface to retrieve information about the current selection, and also to perform 22 * actions based on the selection or when the action bar is dismissed. 23 */ 24 public interface ActionHandler { 25 /** 26 * Perform a select all action. 27 */ selectAll()28 void selectAll(); 29 30 /** 31 * Perform a copy (to clipboard) action. 32 */ copy()33 void copy(); 34 35 /** 36 * Perform a cut (to clipboard) action. 37 */ cut()38 void cut(); 39 40 /** 41 * Perform a paste action. 42 */ paste()43 void paste(); 44 45 /** 46 * Perform a share action. 47 */ share()48 void share(); 49 50 /** 51 * Perform a search action. 52 */ search()53 void search(); 54 55 /** 56 * @return true iff the current selection is editable (e.g. text within an input field). 57 */ isSelectionEditable()58 boolean isSelectionEditable(); 59 60 /** 61 * Called when the onDestroyActionMode of the SelectActionmodeCallback is called. 62 */ onDestroyActionMode()63 void onDestroyActionMode(); 64 65 /** 66 * @return Whether or not share is available. 67 */ isShareAvailable()68 boolean isShareAvailable(); 69 70 /** 71 * @return Whether or not web search is available. 72 */ isWebSearchAvailable()73 boolean isWebSearchAvailable(); 74 75 /** 76 * @return true if the current selection is of password type. 77 */ isSelectionPassword()78 boolean isSelectionPassword(); 79 } 80 81 private final Context mContext; 82 private final ActionHandler mActionHandler; 83 private final boolean mIncognito; 84 private boolean mEditable; 85 private boolean mIsPasswordType; 86 SelectActionModeCallback( Context context, ActionHandler actionHandler, boolean incognito)87 protected SelectActionModeCallback( 88 Context context, ActionHandler actionHandler, boolean incognito) { 89 mContext = context; 90 mActionHandler = actionHandler; 91 mIncognito = incognito; 92 } 93 getContext()94 protected Context getContext() { 95 return mContext; 96 } 97 98 @Override onCreateActionMode(ActionMode mode, Menu menu)99 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 100 mode.setTitle(null); 101 mode.setSubtitle(null); 102 mEditable = mActionHandler.isSelectionEditable(); 103 mIsPasswordType = mActionHandler.isSelectionPassword(); 104 createActionMenu(mode, menu); 105 return true; 106 } 107 108 @Override onPrepareActionMode(ActionMode mode, Menu menu)109 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 110 boolean isEditableNow = mActionHandler.isSelectionEditable(); 111 boolean isPasswordNow = mActionHandler.isSelectionPassword(); 112 if (mEditable != isEditableNow || mIsPasswordType != isPasswordNow) { 113 mEditable = isEditableNow; 114 mIsPasswordType = isPasswordNow; 115 menu.clear(); 116 createActionMenu(mode, menu); 117 return true; 118 } 119 return false; 120 } 121 createActionMenu(ActionMode mode, Menu menu)122 private void createActionMenu(ActionMode mode, Menu menu) { 123 mode.getMenuInflater().inflate(R.menu.select_action_menu, menu); 124 if (!mEditable || !canPaste()) { 125 menu.removeItem(R.id.select_action_menu_paste); 126 } 127 128 if (!mEditable) { 129 menu.removeItem(R.id.select_action_menu_cut); 130 } 131 132 if (mEditable || !mActionHandler.isShareAvailable()) { 133 menu.removeItem(R.id.select_action_menu_share); 134 } 135 136 if (mEditable || mIncognito || !mActionHandler.isWebSearchAvailable()) { 137 menu.removeItem(R.id.select_action_menu_web_search); 138 } 139 if (mIsPasswordType) { 140 menu.removeItem(R.id.select_action_menu_copy); 141 menu.removeItem(R.id.select_action_menu_cut); 142 } 143 } 144 145 @Override onActionItemClicked(ActionMode mode, MenuItem item)146 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 147 int id = item.getItemId(); 148 149 if (id == R.id.select_action_menu_select_all) { 150 mActionHandler.selectAll(); 151 } else if (id == R.id.select_action_menu_cut) { 152 mActionHandler.cut(); 153 } else if (id == R.id.select_action_menu_copy) { 154 mActionHandler.copy(); 155 mode.finish(); 156 } else if (id == R.id.select_action_menu_paste) { 157 mActionHandler.paste(); 158 } else if (id == R.id.select_action_menu_share) { 159 mActionHandler.share(); 160 mode.finish(); 161 } else if (id == R.id.select_action_menu_web_search) { 162 mActionHandler.search(); 163 mode.finish(); 164 } else { 165 return false; 166 } 167 return true; 168 } 169 170 @Override onDestroyActionMode(ActionMode mode)171 public void onDestroyActionMode(ActionMode mode) { 172 mActionHandler.onDestroyActionMode(); 173 } 174 canPaste()175 private boolean canPaste() { 176 ClipboardManager clipMgr = (ClipboardManager) 177 getContext().getSystemService(Context.CLIPBOARD_SERVICE); 178 return clipMgr.hasPrimaryClip(); 179 } 180 } 181