diff options
9 files changed, 109 insertions, 16 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java index 5b452c5..cf39c5b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java @@ -5,6 +5,7 @@ package org.chromium.android_webview; import android.content.Context; +import android.content.Intent; import android.view.KeyEvent; import android.view.View; import android.webkit.URLUtil; @@ -103,6 +104,16 @@ public class AwContentViewClient extends ContentViewClient implements ContentVid public void setSystemUiVisibility(boolean enterFullscreen) { } + @Override + public boolean doesPerformProcessText() { + return true; + } + + @Override + public void startProcessTextIntent(Intent intent) { + mAwContents.startProcessTextIntent(intent); + } + /** * Called to show the web contents in fullscreen mode. * diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index ab356ff..6f3b8d0 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -100,6 +100,8 @@ public class AwContents implements SmartClipProvider, private static final int WARN = 1; private static final String WEB_ARCHIVE_EXTENSION = ".mht"; + // The request code should be unique per WebView/AwContents object. + private static final int PROCESS_TEXT_REQUEST_CODE = 100; // Used to avoid enabling zooming in / out if resulting zooming will // produce little visible difference. @@ -2210,7 +2212,7 @@ public class AwContents implements SmartClipProvider, * be thrown by Android framework if startActivityForResult is called with * a non-Activity context. */ - public void startActivityForResult(Intent intent, int requestCode) { + void startActivityForResult(Intent intent, int requestCode) { // Even in fullscreen mode, startActivityForResult will still use the // initial internal access delegate because it has access to // the hidden API View#startActivityForResult. @@ -2218,9 +2220,27 @@ public class AwContents implements SmartClipProvider, .super_startActivityForResult(intent, requestCode); } + void startProcessTextIntent(Intent intent) { + // on Android M, WebView is not able to replace the text with the processed text. + // So set the readonly flag for M. + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { + intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true); + } + + if (ContentViewCore.activityFromContext(mContext) == null) { + mContext.startActivity(intent); + return; + } + + startActivityForResult(intent, PROCESS_TEXT_REQUEST_CODE); + } + public void onActivityResult(int requestCode, int resultCode, Intent data) { - // TODO(hush): Forward the activity result to content view core and - // replace the text with translated text. + if (requestCode == PROCESS_TEXT_REQUEST_CODE) { + mContentViewCore.onReceivedProcessTextResult(resultCode, data); + } else { + Log.e(TAG, "Received activity result for an unknown request code " + requestCode); + } } /** diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc index cbbc8bf..7ef1ffd 100644 --- a/content/browser/web_contents/web_contents_android.cc +++ b/content/browser/web_contents/web_contents_android.cc @@ -265,6 +265,10 @@ void WebContentsAndroid::Paste(JNIEnv* env, jobject obj) { web_contents_->Paste(); } +void WebContentsAndroid::Replace(JNIEnv* env, jobject obj, jstring jstr) { + web_contents_->Replace(base::android::ConvertJavaStringToUTF16(env, jstr)); +} + void WebContentsAndroid::SelectAll(JNIEnv* env, jobject obj) { web_contents_->SelectAll(); } diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h index f4eb17c..a153b1f 100644 --- a/content/browser/web_contents/web_contents_android.h +++ b/content/browser/web_contents/web_contents_android.h @@ -50,6 +50,7 @@ class CONTENT_EXPORT WebContentsAndroid void Cut(JNIEnv* env, jobject obj); void Copy(JNIEnv* env, jobject obj); void Paste(JNIEnv* env, jobject obj); + void Replace(JNIEnv* env, jobject obj, jstring jstr); void SelectAll(JNIEnv* env, jobject obj); void Unselect(JNIEnv* env, jobject obj); jint GetBackgroundColor(JNIEnv* env, jobject obj); diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java index 8a81f8f..a95acdd 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java @@ -106,6 +106,22 @@ public class ContentViewClient { } /** + * If this returns {@code true} the text processing intents should be forwarded to {@link + * startProcessTextIntent(Intent)}, otherwise these intents should be sent by WindowAndroid by + * default. + * @return {@code true} iff this {@link ContentViewClient} wants to send the processing intents + * and override the default intent behavior. + */ + public boolean doesPerformProcessText() { + return false; + } + + /** + * Send the intent to process the current selected text. + */ + public void startProcessTextIntent(Intent intent) {} + + /** * Called when a new content intent is requested to be started. */ public void onStartContentIntent(Context context, String intentUrl) { diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 69d11cf..98a5479 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -9,6 +9,7 @@ import android.annotation.TargetApi; import android.app.Activity; import android.app.SearchManager; import android.content.ClipboardManager; +import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; @@ -102,10 +103,8 @@ import java.util.Map.Entry; * being tied to the view system. */ @JNINamespace("content") -public class ContentViewCore implements - AccessibilityStateChangeListener, ScreenOrientationObserver, - SystemCaptioningBridge.SystemCaptioningBridgeListener { - +public class ContentViewCore implements AccessibilityStateChangeListener, ScreenOrientationObserver, + SystemCaptioningBridge.SystemCaptioningBridgeListener { private static final String TAG = "cr.ContentViewCore"; // Used to avoid enabling zooming in / out if resulting zooming will @@ -2091,7 +2090,19 @@ public class ContentViewCore implements intent.putExtra(Intent.EXTRA_PROCESS_TEXT, query); try { - getContext().startActivity(intent); + if (getContentViewClient().doesPerformProcessText()) { + getContentViewClient().startProcessTextIntent(intent); + } else { + getWindowAndroid().showIntent( + intent, new WindowAndroid.IntentCallback() { + @Override + public void onIntentCompleted(WindowAndroid window, + int resultCode, ContentResolver contentResolver, + Intent data) { + onReceivedProcessTextResult(resultCode, data); + } + }, null); + } } catch (android.content.ActivityNotFoundException ex) { // If no app handles it, do nothing. } @@ -3045,6 +3056,26 @@ public class ContentViewCore implements } /** + * Called when the processed text is replied from an activity that supports + * Intent.ACTION_PROCESS_TEXT. + * @param resultCode the code that indicates if the activity successfully processed the text + * @param data the reply that contains the processed text. + */ + public void onReceivedProcessTextResult(int resultCode, Intent data) { + if (mWebContents == null || !isSelectionEditable() || resultCode != Activity.RESULT_OK + || data == null) { + return; + } + + CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT); + if (result != null) { + // TODO(hush): Use a variant of replace that re-selects the replaced text. + // crbug.com/546710 + mWebContents.replace(result.toString()); + } + } + + /** * Returns true if accessibility is on and touch exploration is enabled. */ public boolean isTouchExplorationEnabled() { diff --git a/content/public/android/java/src/org/chromium/content/browser/WebActionModeCallback.java b/content/public/android/java/src/org/chromium/content/browser/WebActionModeCallback.java index d6eab6e..9477fce 100644 --- a/content/public/android/java/src/org/chromium/content/browser/WebActionModeCallback.java +++ b/content/public/android/java/src/org/chromium/content/browser/WebActionModeCallback.java @@ -169,15 +169,12 @@ public class WebActionModeCallback implements ActionMode.Callback { new MenuInflater(getContext()).inflate(R.menu.select_action_menu, menu); } - initializeTextProcessingMenu(menu); - if (mIsInsertion) { menu.removeItem(R.id.select_action_menu_select_all); menu.removeItem(R.id.select_action_menu_cut); menu.removeItem(R.id.select_action_menu_copy); menu.removeItem(R.id.select_action_menu_share); menu.removeItem(R.id.select_action_menu_web_search); - menu.removeGroup(R.id.select_action_menu_text_processing_menus); return; } @@ -200,8 +197,10 @@ public class WebActionModeCallback implements ActionMode.Callback { if (mIsPasswordType) { menu.removeItem(R.id.select_action_menu_copy); menu.removeItem(R.id.select_action_menu_cut); - menu.removeGroup(R.id.select_action_menu_text_processing_menus); + return; } + + initializeTextProcessingMenu(menu); } @Override @@ -230,7 +229,8 @@ public class WebActionModeCallback implements ActionMode.Callback { mode.finish(); } else if (groupId == R.id.select_action_menu_text_processing_menus) { mActionHandler.processText(item.getIntent()); - mode.finish(); + // The ActionMode is not dismissed to match the behavior with + // TextView in Android M. } else { return false; } @@ -288,10 +288,9 @@ public class WebActionModeCallback implements ActionMode.Callback { @TargetApi(Build.VERSION_CODES.M) private Intent createProcessTextIntentForResolveInfo(ResolveInfo info) { + boolean isReadOnly = !mActionHandler.isSelectionEditable(); return createProcessTextIntent() - // TODO(hush crbug.com/521027): should be !isSelectionEditable(), - // when WebView supports replacing the text. - .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true) + .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, isReadOnly) .setClassName(info.activityInfo.packageName, info.activityInfo.name); } } diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 7835908..2e625f3 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java @@ -181,6 +181,11 @@ import java.util.UUID; } @Override + public void replace(String word) { + nativeReplace(mNativeWebContentsAndroid, word); + } + + @Override public void selectAll() { nativeSelectAll(mNativeWebContentsAndroid); } @@ -421,6 +426,7 @@ import java.util.UUID; private native void nativeCut(long nativeWebContentsAndroid); private native void nativeCopy(long nativeWebContentsAndroid); private native void nativePaste(long nativeWebContentsAndroid); + private native void nativeReplace(long nativeWebContentsAndroid, String word); private native void nativeSelectAll(long nativeWebContentsAndroid); private native void nativeUnselect(long nativeWebContentsAndroid); private native void nativeInsertCSS(long nativeWebContentsAndroid, String css); diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java index 2cc9e5f..f165310 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java @@ -90,6 +90,11 @@ public interface WebContents extends Parcelable { void paste(); /** + * Replace the selected text with the {@code word}. + */ + void replace(String word); + + /** * Select all content. */ void selectAll(); |