Chromium Code Reviews| Index: content/public/android/java/src/org/chromium/content/browser/ContextSelectionClient.java |
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ContextSelectionClient.java b/content/public/android/java/src/org/chromium/content/browser/ContextSelectionClient.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0459becfe2788464ef29bc265424f9d0efffc0cd |
| --- /dev/null |
| +++ b/content/public/android/java/src/org/chromium/content/browser/ContextSelectionClient.java |
| @@ -0,0 +1,168 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.content.browser; |
| + |
| +import android.support.annotation.IntDef; |
| +import android.text.TextUtils; |
| + |
| +import org.chromium.base.Log; |
| +import org.chromium.base.annotations.CalledByNative; |
| +import org.chromium.base.annotations.JNINamespace; |
| +import org.chromium.content_public.browser.WebContents; |
| +import org.chromium.ui.base.WindowAndroid; |
| +import org.chromium.ui.touch_selection.SelectionEventType; |
| + |
| +import java.lang.annotation.Retention; |
| +import java.lang.annotation.RetentionPolicy; |
| + |
| +/** |
| + * A class that controls the classification of the textual selection. |
| + * It requests the selection together with its surrounding text from |
| + * the focused frame and sends it to ContextSelectionProvider |
| + * which does the classification itself. |
| + */ |
| +@JNINamespace("content") |
| +public class ContextSelectionClient implements SelectionClient { |
|
Tima Vaisburd
2017/03/10 20:42:37
A better naming suggestion is welcome.
|
| + private static final String TAG = "ContextSelClient"; // 20 char limit |
| + |
| + @IntDef({CLASSIFY, SUGGEST_AND_CLASSIFY}) |
| + @Retention(RetentionPolicy.SOURCE) |
| + private @interface RequestType {} |
| + |
| + private static final int CLASSIFY = 0; |
|
boliu
2017/03/11 00:37:52
comment on what these actually does?
Tima Vaisburd
2017/03/20 05:06:04
Not done yet.
Tima Vaisburd
2017/03/21 02:07:01
Done.
|
| + private static final int SUGGEST_AND_CLASSIFY = 1; |
| + |
| + // The callback that would receive the information from ContextSelectionProvider. |
| + private class ProviderCallback implements ContextSelectionProvider.ResultCallback { |
|
boliu
2017/03/11 00:37:52
What's the point of this class?
Tima Vaisburd
2017/03/20 05:06:04
See my reply below.
|
| + @Override |
| + public void onClassified(ContextSelectionProvider.Result result) { |
| + mOuterCallback.onClassified(result); |
| + } |
| + }; |
| + |
| + private long mNativeContextSelectionClient; |
| + private ContextSelectionProvider mProvider; |
| + private ProviderCallback mProviderCallback; |
| + private ContextSelectionProvider.ResultCallback mOuterCallback; |
| + |
| + /** |
| + * Creates the ContextSelectionClient. Returns null in case ContextSelectionProvider |
| + * does not exist in the system. |
| + */ |
| + public static ContextSelectionClient create(ContextSelectionProvider.ResultCallback callback, |
| + WindowAndroid windowAndroid, WebContents webContent) { |
| + Log.v(TAG, "create"); |
|
boliu
2017/03/11 00:37:52
remove random logs
Tima Vaisburd
2017/03/20 05:06:04
Done.
|
| + |
| + ContextSelectionClient client = new ContextSelectionClient(callback); |
| + if (!client.initialize(windowAndroid, webContent)) client = null; |
| + return client; |
| + } |
| + |
| + private ContextSelectionClient(ContextSelectionProvider.ResultCallback callback) { |
| + mOuterCallback = callback; |
| + } |
| + |
| + private boolean initialize(WindowAndroid windowAndroid, WebContents webContents) { |
| + Log.v(TAG, "initialize"); |
|
boliu
2017/03/11 00:37:52
ditto
Tima Vaisburd
2017/03/20 05:06:04
Done.
|
| + // We make a chain of callbacks: this class receiive result from provider through |
| + // mProviderCallback and passes the info to embedder with mOuterCallback. |
| + mProviderCallback = new ProviderCallback(); |
| + mProvider = ContentClassFactory.get().createContextSelectionProvider( |
| + mProviderCallback, windowAndroid); |
| + |
| + // ContextSelectionProvider might not exist. |
| + if (mProvider == null) { |
| + Log.v(TAG, "initialize: no provider"); |
| + return false; |
| + } |
| + |
| + mNativeContextSelectionClient = nativeInit(webContents); |
| + return mNativeContextSelectionClient != 0; |
|
boliu
2017/03/11 00:37:52
how can this ever be 0?
you can check null provid
Tima Vaisburd
2017/03/20 05:06:04
When the C++ new fails. I tried to make something
boliu
2017/03/20 20:27:25
yeah, why not just use the same object?
Tima Vaisburd
2017/03/21 02:07:01
Done.
|
| + } |
| + |
| + @CalledByNative |
| + private void onNativeSideDestroyed(long nativeContextSelectionClient) { |
|
boliu
2017/03/11 00:37:52
what if there are pending requests here?
Tima Vaisburd
2017/03/20 05:06:04
They will be executed and eventually passed to Sel
boliu
2017/03/20 20:27:25
Document that you chose this over cancelling pendi
Tima Vaisburd
2017/03/21 02:07:01
When the native side is destroyed we do not care a
|
| + assert nativeContextSelectionClient == mNativeContextSelectionClient; |
| + mNativeContextSelectionClient = 0; |
| + } |
| + |
| + // SelectionClient implementation |
| + @Override |
| + public void onSelectionChanged(String selection) {} |
| + |
| + @Override |
| + public void onSelectionEvent(int eventType, float posXPix, float posYPix) { |
| + switch (eventType) { |
| + case SelectionEventType.SELECTION_HANDLES_SHOWN: |
|
boliu
2017/03/11 00:37:52
I think what happens in each case is super unintui
Tima Vaisburd
2017/03/20 05:06:04
I tried to add some comments, but I think this is
|
| + requestSurroundingText(SUGGEST_AND_CLASSIFY); |
| + break; |
| + |
| + case SelectionEventType.SELECTION_HANDLES_CLEARED: |
| + cancelAllRequests(); |
| + break; |
| + |
| + case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: |
| + requestSurroundingText(CLASSIFY); |
| + break; |
| + |
| + default: |
| + break; // ignore |
| + } |
| + } |
| + |
| + @Override |
| + public void showUnhandledTapUIIfNeeded(int x, int y) {} |
| + |
| + @Override |
| + public boolean sendsMenuUpdates() { |
| + return true; |
| + } |
| + |
| + private void cancelAllRequests() { |
| + if (mNativeContextSelectionClient != 0) { |
| + nativeCancelAllRequests(mNativeContextSelectionClient); |
| + } |
| + |
| + mProvider.cancelAllRequests(); |
| + } |
| + |
| + private void requestSurroundingText(@RequestType int callbackData) { |
| + Log.v(TAG, "requestSurroundingText"); |
| + if (mNativeContextSelectionClient == 0) { |
| + onSurroundingTextReceived(callbackData, "", 0, 0); |
| + return; |
| + } |
| + |
| + nativeRequestSurroundingText(mNativeContextSelectionClient, callbackData); |
| + } |
| + |
| + @CalledByNative |
| + private void onSurroundingTextReceived( |
| + @RequestType int callbackData, String text, int start, int end) { |
| + if (TextUtils.isEmpty(text)) { |
| + mOuterCallback.onClassified(new ContextSelectionProvider.Result()); |
| + return; |
| + } |
| + |
| + switch (callbackData) { |
| + case SUGGEST_AND_CLASSIFY: |
| + mProvider.sendSuggestAndClassifyRequest(text, start, end); |
| + break; |
| + |
| + case CLASSIFY: |
| + mProvider.sendClassifyRequest(text, start, end); |
| + break; |
| + |
| + default: |
| + assert false : "Unexpected callback data"; |
| + break; |
| + } |
| + } |
| + |
| + private native long nativeInit(WebContents webContents); |
| + private native void nativeRequestSurroundingText( |
| + long nativeContextSelectionClient, int callbackData); |
| + private native void nativeCancelAllRequests(long nativeContextSelectionClient); |
| +} |