OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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.app.SearchManager; |
| 8 import android.content.ClipboardManager; |
| 9 import android.content.Context; |
| 10 import android.content.Intent; |
| 11 import android.content.pm.PackageManager; |
| 12 import android.content.res.TypedArray; |
| 13 import android.provider.Browser; |
| 14 import android.text.TextUtils; |
| 15 import android.view.ActionMode; |
| 16 import android.view.Menu; |
| 17 import android.view.MenuItem; |
| 18 |
| 19 import org.chromium.content.app.AppResource; |
| 20 |
| 21 /** |
| 22 * An ActionMode.Callback for in-page selection. This class handles both the edi
table and |
| 23 * non-editable cases. |
| 24 */ |
| 25 public class SelectActionModeCallback implements ActionMode.Callback { |
| 26 private static final int SELECT_ALL_ATTR_INDEX = 0; |
| 27 private static final int CUT_ATTR_INDEX = 1; |
| 28 private static final int COPY_ATTR_INDEX = 2; |
| 29 private static final int PASTE_ATTR_INDEX = 3; |
| 30 private static final int[] ACTION_MODE_ATTRS = { |
| 31 android.R.attr.actionModeSelectAllDrawable, |
| 32 android.R.attr.actionModeCutDrawable, |
| 33 android.R.attr.actionModeCopyDrawable, |
| 34 android.R.attr.actionModePasteDrawable, |
| 35 }; |
| 36 |
| 37 private static final int ID_SELECTALL = 0; |
| 38 private static final int ID_COPY = 1; |
| 39 private static final int ID_SHARE = 2; |
| 40 private static final int ID_SEARCH = 3; |
| 41 private static final int ID_CUT = 4; |
| 42 private static final int ID_PASTE = 5; |
| 43 |
| 44 /** |
| 45 * An interface to retrieve information about the current selection, and als
o to perform |
| 46 * actions based on the selection or when the action bar is dismissed. |
| 47 */ |
| 48 public interface ActionHandler { |
| 49 /** |
| 50 * Perform a select all action. |
| 51 * @return true iff the action was successful. |
| 52 */ |
| 53 boolean selectAll(); |
| 54 |
| 55 /** |
| 56 * Perform a copy (to clipboard) action. |
| 57 * @return true iff the action was successful. |
| 58 */ |
| 59 boolean copy(); |
| 60 |
| 61 /** |
| 62 * Perform a cut (to clipboard) action. |
| 63 * @return true iff the action was successful. |
| 64 */ |
| 65 boolean cut(); |
| 66 |
| 67 /** |
| 68 * Perform a paste action. |
| 69 * @return true iff the action was successful. |
| 70 */ |
| 71 boolean paste(); |
| 72 |
| 73 /** |
| 74 * @return true iff the current selection is editable (e.g. text within
an input field). |
| 75 */ |
| 76 boolean isSelectionEditable(); |
| 77 |
| 78 /** |
| 79 * @return the currently selected text String. |
| 80 */ |
| 81 String getSelectedText(); |
| 82 |
| 83 /** |
| 84 * Called when the onDestroyActionMode of the SelectActionmodeCallback i
s called. |
| 85 */ |
| 86 void onDestroyActionMode(); |
| 87 } |
| 88 |
| 89 private Context mContext; |
| 90 private ActionHandler mActionHandler; |
| 91 private final boolean mIncognito; |
| 92 private boolean mEditable; |
| 93 |
| 94 protected SelectActionModeCallback( |
| 95 Context context, ActionHandler actionHandler, boolean incognito) { |
| 96 mContext = context; |
| 97 mActionHandler = actionHandler; |
| 98 mIncognito = incognito; |
| 99 } |
| 100 |
| 101 protected Context getContext() { |
| 102 return mContext; |
| 103 } |
| 104 |
| 105 @Override |
| 106 public boolean onCreateActionMode(ActionMode mode, Menu menu) { |
| 107 mode.setSubtitle(null); |
| 108 mEditable = mActionHandler.isSelectionEditable(); |
| 109 createActionMenu(mode, menu); |
| 110 return true; |
| 111 } |
| 112 |
| 113 @Override |
| 114 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { |
| 115 boolean isEditableNow = mActionHandler.isSelectionEditable(); |
| 116 if (mEditable != isEditableNow) { |
| 117 mEditable = isEditableNow; |
| 118 menu.clear(); |
| 119 createActionMenu(mode, menu); |
| 120 return true; |
| 121 } |
| 122 return false; |
| 123 } |
| 124 |
| 125 private void createActionMenu(ActionMode mode, Menu menu) { |
| 126 TypedArray styledAttributes = getContext().obtainStyledAttributes(ACTION
_MODE_ATTRS); |
| 127 |
| 128 menu.add(Menu.NONE, ID_SELECTALL, Menu.NONE, android.R.string.selectAll)
. |
| 129 setAlphabeticShortcut('a'). |
| 130 setIcon(styledAttributes.getResourceId(SELECT_ALL_ATTR_INDEX, 0)). |
| 131 setShowAsAction( |
| 132 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WIT
H_TEXT); |
| 133 |
| 134 if (mEditable) { |
| 135 menu.add(Menu.NONE, ID_CUT, Menu.NONE, android.R.string.cut). |
| 136 setIcon(styledAttributes.getResourceId(CUT_ATTR_INDEX, 0)). |
| 137 setAlphabeticShortcut('x'). |
| 138 setShowAsAction( |
| 139 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WIT
H_TEXT); |
| 140 } |
| 141 |
| 142 menu.add(Menu.NONE, ID_COPY, Menu.NONE, android.R.string.copy). |
| 143 setIcon(styledAttributes.getResourceId(COPY_ATTR_INDEX, 0)). |
| 144 setAlphabeticShortcut('c'). |
| 145 setShowAsAction( |
| 146 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WIT
H_TEXT); |
| 147 |
| 148 if (mEditable && canPaste()) { |
| 149 menu.add(Menu.NONE, ID_PASTE, Menu.NONE, android.R.string.paste). |
| 150 setIcon(styledAttributes.getResourceId(PASTE_ATTR_INDEX, 0)). |
| 151 setAlphabeticShortcut('v'). |
| 152 setShowAsAction( |
| 153 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION
_WITH_TEXT); |
| 154 } |
| 155 |
| 156 if (!mEditable) { |
| 157 if (isShareHandlerAvailable()) { |
| 158 assert AppResource.STRING_ACTION_BAR_SHARE != 0; |
| 159 assert AppResource.DRAWABLE_ICON_ACTION_BAR_SHARE != 0; |
| 160 menu.add(Menu.NONE, ID_SHARE, Menu.NONE, AppResource.STRING_ACTI
ON_BAR_SHARE). |
| 161 setIcon(AppResource.DRAWABLE_ICON_ACTION_BAR_SHARE). |
| 162 setShowAsAction( |
| 163 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_AC
TION_WITH_TEXT); |
| 164 } |
| 165 |
| 166 if (!mIncognito && isWebSearchAvailable()) { |
| 167 assert AppResource.STRING_ACTION_BAR_WEB_SEARCH != 0; |
| 168 assert AppResource.DRAWABLE_ICON_ACTION_BAR_WEB_SEARCH != 0; |
| 169 menu.add(Menu.NONE, ID_SEARCH, Menu.NONE, |
| 170 AppResource.STRING_ACTION_BAR_WEB_SEARCH). |
| 171 setIcon(AppResource.DRAWABLE_ICON_ACTION_BAR_WEB_SEARCH). |
| 172 setShowAsAction( |
| 173 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_AC
TION_WITH_TEXT); |
| 174 } |
| 175 } |
| 176 |
| 177 styledAttributes.recycle(); |
| 178 } |
| 179 |
| 180 @Override |
| 181 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { |
| 182 String selection = mActionHandler.getSelectedText(); |
| 183 switch(item.getItemId()) { |
| 184 case ID_SELECTALL: |
| 185 mActionHandler.selectAll(); |
| 186 break; |
| 187 case ID_CUT: |
| 188 mActionHandler.cut(); |
| 189 break; |
| 190 case ID_COPY: |
| 191 mActionHandler.copy(); |
| 192 mode.finish(); |
| 193 break; |
| 194 case ID_PASTE: |
| 195 mActionHandler.paste(); |
| 196 break; |
| 197 case ID_SHARE: |
| 198 if (!TextUtils.isEmpty(selection)) { |
| 199 Intent send = new Intent(Intent.ACTION_SEND); |
| 200 send.setType("text/plain"); |
| 201 send.putExtra(Intent.EXTRA_TEXT, selection); |
| 202 try { |
| 203 assert AppResource.STRING_ACTION_BAR_SHARE != 0; |
| 204 Intent i = Intent.createChooser(send, getContext().getSt
ring( |
| 205 AppResource.STRING_ACTION_BAR_SHARE)); |
| 206 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| 207 getContext().startActivity(i); |
| 208 } catch (android.content.ActivityNotFoundException ex) { |
| 209 // If no app handles it, do nothing. |
| 210 } |
| 211 } |
| 212 mode.finish(); |
| 213 break; |
| 214 case ID_SEARCH: |
| 215 if (!TextUtils.isEmpty(selection)) { |
| 216 Intent i = new Intent(Intent.ACTION_WEB_SEARCH); |
| 217 i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); |
| 218 i.putExtra(SearchManager.QUERY, selection); |
| 219 i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPac
kageName()); |
| 220 try { |
| 221 getContext().startActivity(i); |
| 222 } catch (android.content.ActivityNotFoundException ex) { |
| 223 // If no app handles it, do nothing. |
| 224 } |
| 225 } |
| 226 mode.finish(); |
| 227 break; |
| 228 default: |
| 229 return false; |
| 230 } |
| 231 return true; |
| 232 } |
| 233 |
| 234 @Override |
| 235 public void onDestroyActionMode(ActionMode mode) { |
| 236 mActionHandler.onDestroyActionMode(); |
| 237 } |
| 238 |
| 239 private boolean canPaste() { |
| 240 ClipboardManager clipMgr = (ClipboardManager) |
| 241 getContext().getSystemService(Context.CLIPBOARD_SERVICE); |
| 242 return clipMgr.hasPrimaryClip(); |
| 243 } |
| 244 |
| 245 private boolean isShareHandlerAvailable() { |
| 246 Intent intent = new Intent(Intent.ACTION_SEND); |
| 247 intent.setType("text/plain"); |
| 248 return getContext().getPackageManager() |
| 249 .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY
).size() > 0; |
| 250 } |
| 251 |
| 252 private boolean isWebSearchAvailable() { |
| 253 Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); |
| 254 intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); |
| 255 return getContext().getPackageManager() |
| 256 .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY
).size() > 0; |
| 257 } |
| 258 } |
OLD | NEW |