Loading core/java/android/webkit/SelectActionModeCallback.java +42 −11 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.webkit; import android.app.SearchManager; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.provider.Browser; Loading @@ -27,11 +28,16 @@ import android.view.MenuItem; class SelectActionModeCallback implements ActionMode.Callback { private WebView mWebView; private ActionMode mActionMode; private boolean mIsTextSelected = true; void setWebView(WebView webView) { mWebView = webView; } void setTextSelected(boolean isTextSelected) { mIsTextSelected = isTextSelected; } void finish() { // It is possible that onCreateActionMode was never called, in the case // where there is no ActionBar, for example. Loading @@ -52,17 +58,25 @@ class SelectActionModeCallback implements ActionMode.Callback { mode.setTitle(allowText ? context.getString(com.android.internal.R.string.textSelectionCABTitle) : null); if (!mode.isUiFocusable()) { // If the action mode UI we're running in isn't capable of taking window focus // the user won't be able to type into the find on page UI. Disable this functionality. // (Note that this should only happen in floating dialog windows.) // This can be removed once we can handle multiple focusable windows at a time // in a better way. final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find); if (findOnPageItem != null) { findOnPageItem.setVisible(false); } } ClipboardManager cm = (ClipboardManager)(context .getSystemService(Context.CLIPBOARD_SERVICE)); boolean isFocusable = mode.isUiFocusable(); boolean isEditable = mWebView.focusCandidateIsEditableText(); boolean canPaste = isEditable && cm.hasPrimaryClip() && isFocusable; boolean canFind = !isEditable && isFocusable; boolean canCut = isEditable && mIsTextSelected && isFocusable; boolean canCopy = mIsTextSelected; boolean canWebSearch = mIsTextSelected; setMenuVisibility(menu, canFind, com.android.internal.R.id.find); setMenuVisibility(menu, canPaste, com.android.internal.R.id.paste); setMenuVisibility(menu, canCut, com.android.internal.R.id.cut); setMenuVisibility(menu, canCopy, com.android.internal.R.id.copy); setMenuVisibility(menu, canWebSearch, com.android.internal.R.id.websearch); mActionMode = mode; return true; } Loading @@ -75,11 +89,21 @@ class SelectActionModeCallback implements ActionMode.Callback { @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch(item.getItemId()) { case android.R.id.cut: mWebView.cutSelection(); mode.finish(); break; case android.R.id.copy: mWebView.copySelection(); mode.finish(); break; case android.R.id.paste: mWebView.pasteFromClipboard(); mode.finish(); break; case com.android.internal.R.id.share: String selection = mWebView.getSelection(); Browser.sendString(mWebView.getContext(), selection); Loading Loading @@ -113,4 +137,11 @@ class SelectActionModeCallback implements ActionMode.Callback { public void onDestroyActionMode(ActionMode mode) { mWebView.selectionDone(); } private void setMenuVisibility(Menu menu, boolean visible, int resourceId) { final MenuItem item = menu.findItem(resourceId); if (item != null) { item.setVisible(visible); } } } core/java/android/webkit/WebView.java +79 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.Widget; import android.app.ActivityManager; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ComponentCallbacks2; import android.content.Context; Loading Loading @@ -797,6 +798,8 @@ public class WebView extends AbsoluteLayout static final int UPDATE_ZOOM_DENSITY = 139; static final int EXIT_FULLSCREEN_VIDEO = 140; static final int COPY_TO_CLIPBOARD = 141; private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID; private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT; Loading Loading @@ -4520,6 +4523,11 @@ public class WebView extends AbsoluteLayout final boolean isSelecting = selectText(); if (isSelecting) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } else if (focusCandidateIsEditableText()) { mSelectCallback = new SelectActionModeCallback(); mSelectCallback.setWebView(this); mSelectCallback.setTextSelected(false); startActionMode(mSelectCallback); } return isSelecting; } Loading Loading @@ -5729,11 +5737,48 @@ public class WebView extends AbsoluteLayout ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); cm.setText(selection); int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles); } invalidate(); // remove selection region and pointer return copiedSomething; } /** * Cut the selected text into the clipboard * * @hide This is an implementation detail */ public void cutSelection() { copySelection(); int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles); } /** * Paste text from the clipboard to the cursor position. * * @hide This is an implementation detail */ public void pasteFromClipboard() { ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clipData = cm.getPrimaryClip(); if (clipData != null) { ClipData.Item clipItem = clipData.getItemAt(0); CharSequence pasteText = clipItem.getText(); if (pasteText != null) { int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles); mWebViewCore.sendMessage(EventHub.INSERT_TEXT, pasteText.toString()); } } } /** * @hide This is an implementation detail. */ Loading Loading @@ -8914,6 +8959,10 @@ public class WebView extends AbsoluteLayout nativeSelectAt(msg.arg1, msg.arg2); break; case COPY_TO_CLIPBOARD: copyToClipboard((String) msg.obj); break; default: super.handleMessage(msg); break; Loading Loading @@ -9591,6 +9640,18 @@ public class WebView extends AbsoluteLayout mCurrentTouchInterval = interval; } /** * Copy text into the clipboard. This is called indirectly from * WebViewCore. * @param text The text to put into the clipboard. */ private void copyToClipboard(String text) { ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText(getTitle(), text); cm.setPrimaryClip(clip); } /** * Update our cache with updatedText. * @param updatedText The new text to put in our cache. Loading Loading @@ -9677,6 +9738,23 @@ public class WebView extends AbsoluteLayout return nativeTileProfilingGetFloat(frame, tile, key); } /** * Checks the focused content for an editable text field. This can be * text input or ContentEditable. * @return true if the focused item is an editable text field. */ boolean focusCandidateIsEditableText() { boolean isEditable = false; // TODO: reverse sDisableNavcache so that its name is positive boolean isNavcacheEnabled = !sDisableNavcache; if (isNavcacheEnabled) { isEditable = nativeFocusCandidateIsEditableText(mNativeClass); } else if (mFocusedNode != null) { isEditable = mFocusedNode.mEditable; } return isEditable; } private native int nativeCacheHitFramePointer(); private native boolean nativeCacheHitIsPlugin(); private native Rect nativeCacheHitNodeBounds(); Loading Loading @@ -9722,6 +9800,7 @@ public class WebView extends AbsoluteLayout /* package */ native boolean nativeFocusCandidateIsPassword(); private native boolean nativeFocusCandidateIsRtlText(); private native boolean nativeFocusCandidateIsTextInput(); private native boolean nativeFocusCandidateIsEditableText(int nativeClass); /* package */ native int nativeFocusCandidateMaxLength(); /* package */ native boolean nativeFocusCandidateIsAutoComplete(); /* package */ native boolean nativeFocusCandidateIsSpellcheck(); Loading core/java/android/webkit/WebViewCore.java +57 −0 Original line number Diff line number Diff line Loading @@ -1126,6 +1126,11 @@ public final class WebViewCore { // private message ids private static final int DESTROY = 200; // for cut & paste static final int COPY_TEXT = 210; static final int DELETE_TEXT = 211; static final int INSERT_TEXT = 212; // Private handler for WebCore messages. private Handler mHandler; // Message queue for containing messages before the WebCore thread is Loading Loading @@ -1737,6 +1742,27 @@ public final class WebViewCore { Rect rect = (Rect) msg.obj; nativeScrollLayer(mNativeClass, nativeLayer, rect); case DELETE_TEXT: { int[] handles = (int[]) msg.obj; nativeDeleteText(mNativeClass, handles[0], handles[1], handles[2], handles[3]); break; } case COPY_TEXT: { int[] handles = (int[]) msg.obj; String copiedText = nativeGetText(mNativeClass, handles[0], handles[1], handles[2], handles[3]); if (copiedText != null) { mWebView.mPrivateHandler.obtainMessage(WebView.COPY_TO_CLIPBOARD, copiedText) .sendToTarget(); } break; } case INSERT_TEXT: nativeInsertText(mNativeClass, (String) msg.obj); break; } } }; Loading Loading @@ -2976,4 +3002,35 @@ public final class WebViewCore { private native void nativeAutoFillForm(int nativeClass, int queryId); private native void nativeScrollLayer(int nativeClass, int layer, Rect rect); /** * Deletes editable text between two points. Note that the selection may * differ from the WebView's selection because the algorithms for selecting * text differs for non-LTR text. Any text that isn't editable will be * left unchanged. * @param nativeClass The pointer to the native class (mNativeClass) * @param startX The X position of the top-left selection point. * @param startY The Y position of the top-left selection point. * @param endX The X position of the bottom-right selection point. * @param endY The Y position of the bottom-right selection point. */ private native void nativeDeleteText(int nativeClass, int startX, int startY, int endX, int endY); /** * Inserts text at the current cursor position. If the currently-focused * node does not have a cursor position then this function does nothing. */ private native void nativeInsertText(int nativeClass, String text); /** * Gets the text between two selection points. Note that the selection * may differ from the WebView's selection because the algorithms for * selecting text differs for non-LTR text. * @param nativeClass The pointer to the native class (mNativeClass) * @param startX The X position of the top-left selection point. * @param startY The Y position of the top-left selection point. * @param endX The X position of the bottom-right selection point. * @param endY The Y position of the bottom-right selection point. */ private native String nativeGetText(int nativeClass, int startX, int startY, int endX, int endY); } core/res/res/menu/webview_copy.xml +10 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,21 @@ android:title="@string/selectAll" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/cut" android:icon="?android:attr/actionModeCutDrawable" android:title="@string/cut" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/copy" android:icon="?android:attr/actionModeCopyDrawable" android:title="@string/copy" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/paste" android:icon="?android:attr/actionModePasteDrawable" android:title="@string/paste" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/share" android:icon="?android:attr/actionModeShareDrawable" android:title="@string/share" Loading Loading
core/java/android/webkit/SelectActionModeCallback.java +42 −11 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.webkit; import android.app.SearchManager; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.provider.Browser; Loading @@ -27,11 +28,16 @@ import android.view.MenuItem; class SelectActionModeCallback implements ActionMode.Callback { private WebView mWebView; private ActionMode mActionMode; private boolean mIsTextSelected = true; void setWebView(WebView webView) { mWebView = webView; } void setTextSelected(boolean isTextSelected) { mIsTextSelected = isTextSelected; } void finish() { // It is possible that onCreateActionMode was never called, in the case // where there is no ActionBar, for example. Loading @@ -52,17 +58,25 @@ class SelectActionModeCallback implements ActionMode.Callback { mode.setTitle(allowText ? context.getString(com.android.internal.R.string.textSelectionCABTitle) : null); if (!mode.isUiFocusable()) { // If the action mode UI we're running in isn't capable of taking window focus // the user won't be able to type into the find on page UI. Disable this functionality. // (Note that this should only happen in floating dialog windows.) // This can be removed once we can handle multiple focusable windows at a time // in a better way. final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find); if (findOnPageItem != null) { findOnPageItem.setVisible(false); } } ClipboardManager cm = (ClipboardManager)(context .getSystemService(Context.CLIPBOARD_SERVICE)); boolean isFocusable = mode.isUiFocusable(); boolean isEditable = mWebView.focusCandidateIsEditableText(); boolean canPaste = isEditable && cm.hasPrimaryClip() && isFocusable; boolean canFind = !isEditable && isFocusable; boolean canCut = isEditable && mIsTextSelected && isFocusable; boolean canCopy = mIsTextSelected; boolean canWebSearch = mIsTextSelected; setMenuVisibility(menu, canFind, com.android.internal.R.id.find); setMenuVisibility(menu, canPaste, com.android.internal.R.id.paste); setMenuVisibility(menu, canCut, com.android.internal.R.id.cut); setMenuVisibility(menu, canCopy, com.android.internal.R.id.copy); setMenuVisibility(menu, canWebSearch, com.android.internal.R.id.websearch); mActionMode = mode; return true; } Loading @@ -75,11 +89,21 @@ class SelectActionModeCallback implements ActionMode.Callback { @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch(item.getItemId()) { case android.R.id.cut: mWebView.cutSelection(); mode.finish(); break; case android.R.id.copy: mWebView.copySelection(); mode.finish(); break; case android.R.id.paste: mWebView.pasteFromClipboard(); mode.finish(); break; case com.android.internal.R.id.share: String selection = mWebView.getSelection(); Browser.sendString(mWebView.getContext(), selection); Loading Loading @@ -113,4 +137,11 @@ class SelectActionModeCallback implements ActionMode.Callback { public void onDestroyActionMode(ActionMode mode) { mWebView.selectionDone(); } private void setMenuVisibility(Menu menu, boolean visible, int resourceId) { final MenuItem item = menu.findItem(resourceId); if (item != null) { item.setVisible(visible); } } }
core/java/android/webkit/WebView.java +79 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.Widget; import android.app.ActivityManager; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ClipboardManager; import android.content.ComponentCallbacks2; import android.content.Context; Loading Loading @@ -797,6 +798,8 @@ public class WebView extends AbsoluteLayout static final int UPDATE_ZOOM_DENSITY = 139; static final int EXIT_FULLSCREEN_VIDEO = 140; static final int COPY_TO_CLIPBOARD = 141; private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID; private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT; Loading Loading @@ -4520,6 +4523,11 @@ public class WebView extends AbsoluteLayout final boolean isSelecting = selectText(); if (isSelecting) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); } else if (focusCandidateIsEditableText()) { mSelectCallback = new SelectActionModeCallback(); mSelectCallback.setWebView(this); mSelectCallback.setTextSelected(false); startActionMode(mSelectCallback); } return isSelecting; } Loading Loading @@ -5729,11 +5737,48 @@ public class WebView extends AbsoluteLayout ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); cm.setText(selection); int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles); } invalidate(); // remove selection region and pointer return copiedSomething; } /** * Cut the selected text into the clipboard * * @hide This is an implementation detail */ public void cutSelection() { copySelection(); int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles); } /** * Paste text from the clipboard to the cursor position. * * @hide This is an implementation detail */ public void pasteFromClipboard() { ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clipData = cm.getPrimaryClip(); if (clipData != null) { ClipData.Item clipItem = clipData.getItemAt(0); CharSequence pasteText = clipItem.getText(); if (pasteText != null) { int[] handles = new int[4]; nativeGetSelectionHandles(mNativeClass, handles); mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles); mWebViewCore.sendMessage(EventHub.INSERT_TEXT, pasteText.toString()); } } } /** * @hide This is an implementation detail. */ Loading Loading @@ -8914,6 +8959,10 @@ public class WebView extends AbsoluteLayout nativeSelectAt(msg.arg1, msg.arg2); break; case COPY_TO_CLIPBOARD: copyToClipboard((String) msg.obj); break; default: super.handleMessage(msg); break; Loading Loading @@ -9591,6 +9640,18 @@ public class WebView extends AbsoluteLayout mCurrentTouchInterval = interval; } /** * Copy text into the clipboard. This is called indirectly from * WebViewCore. * @param text The text to put into the clipboard. */ private void copyToClipboard(String text) { ClipboardManager cm = (ClipboardManager)getContext() .getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText(getTitle(), text); cm.setPrimaryClip(clip); } /** * Update our cache with updatedText. * @param updatedText The new text to put in our cache. Loading Loading @@ -9677,6 +9738,23 @@ public class WebView extends AbsoluteLayout return nativeTileProfilingGetFloat(frame, tile, key); } /** * Checks the focused content for an editable text field. This can be * text input or ContentEditable. * @return true if the focused item is an editable text field. */ boolean focusCandidateIsEditableText() { boolean isEditable = false; // TODO: reverse sDisableNavcache so that its name is positive boolean isNavcacheEnabled = !sDisableNavcache; if (isNavcacheEnabled) { isEditable = nativeFocusCandidateIsEditableText(mNativeClass); } else if (mFocusedNode != null) { isEditable = mFocusedNode.mEditable; } return isEditable; } private native int nativeCacheHitFramePointer(); private native boolean nativeCacheHitIsPlugin(); private native Rect nativeCacheHitNodeBounds(); Loading Loading @@ -9722,6 +9800,7 @@ public class WebView extends AbsoluteLayout /* package */ native boolean nativeFocusCandidateIsPassword(); private native boolean nativeFocusCandidateIsRtlText(); private native boolean nativeFocusCandidateIsTextInput(); private native boolean nativeFocusCandidateIsEditableText(int nativeClass); /* package */ native int nativeFocusCandidateMaxLength(); /* package */ native boolean nativeFocusCandidateIsAutoComplete(); /* package */ native boolean nativeFocusCandidateIsSpellcheck(); Loading
core/java/android/webkit/WebViewCore.java +57 −0 Original line number Diff line number Diff line Loading @@ -1126,6 +1126,11 @@ public final class WebViewCore { // private message ids private static final int DESTROY = 200; // for cut & paste static final int COPY_TEXT = 210; static final int DELETE_TEXT = 211; static final int INSERT_TEXT = 212; // Private handler for WebCore messages. private Handler mHandler; // Message queue for containing messages before the WebCore thread is Loading Loading @@ -1737,6 +1742,27 @@ public final class WebViewCore { Rect rect = (Rect) msg.obj; nativeScrollLayer(mNativeClass, nativeLayer, rect); case DELETE_TEXT: { int[] handles = (int[]) msg.obj; nativeDeleteText(mNativeClass, handles[0], handles[1], handles[2], handles[3]); break; } case COPY_TEXT: { int[] handles = (int[]) msg.obj; String copiedText = nativeGetText(mNativeClass, handles[0], handles[1], handles[2], handles[3]); if (copiedText != null) { mWebView.mPrivateHandler.obtainMessage(WebView.COPY_TO_CLIPBOARD, copiedText) .sendToTarget(); } break; } case INSERT_TEXT: nativeInsertText(mNativeClass, (String) msg.obj); break; } } }; Loading Loading @@ -2976,4 +3002,35 @@ public final class WebViewCore { private native void nativeAutoFillForm(int nativeClass, int queryId); private native void nativeScrollLayer(int nativeClass, int layer, Rect rect); /** * Deletes editable text between two points. Note that the selection may * differ from the WebView's selection because the algorithms for selecting * text differs for non-LTR text. Any text that isn't editable will be * left unchanged. * @param nativeClass The pointer to the native class (mNativeClass) * @param startX The X position of the top-left selection point. * @param startY The Y position of the top-left selection point. * @param endX The X position of the bottom-right selection point. * @param endY The Y position of the bottom-right selection point. */ private native void nativeDeleteText(int nativeClass, int startX, int startY, int endX, int endY); /** * Inserts text at the current cursor position. If the currently-focused * node does not have a cursor position then this function does nothing. */ private native void nativeInsertText(int nativeClass, String text); /** * Gets the text between two selection points. Note that the selection * may differ from the WebView's selection because the algorithms for * selecting text differs for non-LTR text. * @param nativeClass The pointer to the native class (mNativeClass) * @param startX The X position of the top-left selection point. * @param startY The Y position of the top-left selection point. * @param endX The X position of the bottom-right selection point. * @param endY The Y position of the bottom-right selection point. */ private native String nativeGetText(int nativeClass, int startX, int startY, int endX, int endY); }
core/res/res/menu/webview_copy.xml +10 −0 Original line number Diff line number Diff line Loading @@ -19,11 +19,21 @@ android:title="@string/selectAll" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/cut" android:icon="?android:attr/actionModeCutDrawable" android:title="@string/cut" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/copy" android:icon="?android:attr/actionModeCopyDrawable" android:title="@string/copy" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/paste" android:icon="?android:attr/actionModePasteDrawable" android:title="@string/paste" android:showAsAction="ifRoom|withText" /> <item android:id="@+id/share" android:icon="?android:attr/actionModeShareDrawable" android:title="@string/share" Loading