Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java |
| index b1ac520fc8828c0d12afd85e0946fc5e3038a2a8..1d8d2c79222e7ba976039020a953afabacc4665b 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContext.java |
| @@ -4,45 +4,60 @@ |
| package org.chromium.chrome.browser.contextualsearch; |
| +import android.text.TextUtils; |
| + |
| +import org.chromium.base.Log; |
| import org.chromium.base.annotations.CalledByNative; |
| +import javax.annotation.Nullable; |
| + |
| /** |
| * Provides a context in which to search, and links to the native ContextualSearchContext. |
| * Includes the selection, selection offsets, surrounding page content, etc. |
| + * Requires an override of #onSelectionChanged to call when a non-empty selection is established |
| + * or changed. |
| */ |
| -public class ContextualSearchContext { |
| - // The initial selection that established this context, or null. |
| - private final String mSelection; |
| +public abstract class ContextualSearchContext { |
| + static final int INVALID_SELECTION_OFFSET = -1; |
| // Pointer to the native instance of this class. |
| private long mNativePointer; |
| - // Whether this context can Resolve a Search Term. |
| - private boolean mCanResolve; |
| + // Whether this context has had the required properties set so it can Resolve a Search Term. |
| + private boolean mHasSetResolveProperties; |
| + |
| + // A shortened version of the actual text content surrounding the selection, or null if not yet |
| + // established. |
| + private String mSurroundingText; |
| + |
| + // The start and end offsets of the selection within the text content. |
| + private int mSelectionStartOffset = INVALID_SELECTION_OFFSET; |
| + private int mSelectionEndOffset = INVALID_SELECTION_OFFSET; |
| + |
| + // The initial word selected by a Tap, or null. |
| + private String mInitialSelectedWord; |
| + |
| + // The original encoding of the base page. |
| + private String mEncoding; |
| /** |
| - * Constructs a context that cannot resolve a search term and has a small amount of |
| - * page content. |
| + * Constructs a context that tracks the selection and some amount of page content. |
| */ |
| ContextualSearchContext() { |
| mNativePointer = nativeInit(); |
| - mSelection = null; |
| - mCanResolve = false; |
| + mHasSetResolveProperties = false; |
| } |
| /** |
| - * Constructs a context that can resolve a search term and has a large amount of |
| + * Updates a context to be able to resolve a search term and have a large amount of |
| * page content. |
| - * @param selection The current selection. |
| * @param homeCountry The country where the user usually resides, or an empty string if not |
| * known. |
| * @param maySendBasePageUrl Whether policy allows sending the base-page URL to the server. |
| */ |
| - ContextualSearchContext(String selection, String homeCountry, boolean maySendBasePageUrl) { |
| - mNativePointer = nativeInit(); |
| - mSelection = selection; |
| - mCanResolve = true; |
| - nativeSetResolveProperties(getNativePointer(), selection, homeCountry, maySendBasePageUrl); |
| + void setResolveProperties(String homeCountry, boolean maySendBasePageUrl) { |
| + mHasSetResolveProperties = true; |
| + nativeSetResolveProperties(getNativePointer(), homeCountry, maySendBasePageUrl); |
| } |
| /** |
| @@ -53,23 +68,148 @@ public class ContextualSearchContext { |
| assert mNativePointer != 0; |
| nativeDestroy(mNativePointer); |
| mNativePointer = 0; |
| + |
| + // Also zero out private data that may be sizable. |
| + mSurroundingText = null; |
| + } |
| + |
| + /** |
| + * Sets the surrounding text and selection offsets. |
| + * @param encoding The original encoding of the base page. |
| + * @param surroundingText The text from the base page surrounding the selection. |
| + * @param startOffset The offset of start the selection. |
| + * @param endOffset The offset of the end of the selection |
| + */ |
| + void setSurroundingText( |
| + String encoding, String surroundingText, int startOffset, int endOffset) { |
| + mEncoding = encoding; |
| + mSurroundingText = surroundingText; |
| + mSelectionStartOffset = startOffset; |
| + mSelectionEndOffset = endOffset; |
| + // Notify of an initial selection if it's not empty. |
| + if (endOffset > startOffset) onSelectionChanged(); |
| + } |
| + |
| + /** |
| + * @return The text that surrounds the selection, or {@code null} if none yet known. |
| + */ |
| + @Nullable |
| + String getSurroundingText() { |
| + return mSurroundingText; |
| + } |
| + |
| + /** |
| + * @return The offset into the surrounding text of the start of the selection, or |
| + * {@link #INVALID_SELECTION_OFFSET} if not yet established. |
| + */ |
| + int getSelectionStartOffset() { |
| + return mSelectionStartOffset; |
| + } |
| + |
| + /** |
| + * @return The offset into the surrounding text of the end of the selection, or |
| + * {@link #INVALID_SELECTION_OFFSET} if not yet established. |
| + */ |
| + int getSelectionEndOffset() { |
| + return mSelectionEndOffset; |
| } |
| /** |
| - * @return the original selection. |
| + * @return The original encoding of the base page. |
| */ |
| - String getSelection() { |
| - return mSelection; |
| + String getEncoding() { |
| + return mEncoding; |
| } |
| /** |
| - * @return Whether this context can "Resolve" the Search Term or is just used for a |
| - * non-resolving Tap gesture or a Long-press gesture. |
| + * @return The initial word selected by a Tap. |
| + */ |
| + String getInitialSelectedWord() { |
| + return mInitialSelectedWord; |
| + } |
| + |
| + /** |
| + * @return The text content that follows the selection (one side of the surrounding text). |
| + */ |
| + String getTextContentFollowingSelection() { |
| + if (mSurroundingText != null && mSelectionEndOffset > 0 |
| + && mSelectionEndOffset <= mSurroundingText.length()) { |
| + return mSurroundingText.substring(mSelectionEndOffset); |
| + } else { |
| + return ""; |
| + } |
| + } |
| + |
| + /** |
| + * @return Whether this context can Resolve the Search Term. |
| */ |
| boolean canResolve() { |
| - return mCanResolve; |
| + return mHasSetResolveProperties && mSelectionStartOffset != INVALID_SELECTION_OFFSET |
| + && mSelectionEndOffset != INVALID_SELECTION_OFFSET |
| + && mSelectionEndOffset > mSelectionStartOffset; |
| + } |
| + |
| + /** |
| + * Notifies of an adjustment that has been applied to the start and end of the selection. |
| + * @param startAdjust A signed value indicating the direction of the adjustment to the start of |
| + * the selection (typically a negative value when the selection expands). |
| + * @param endAdjust A signed value indicating the direction of the adjustment to the end of |
| + * the selection (typically a positive value when the selection expands). |
| + */ |
| + void onSelectionAdjusted(int startAdjust, int endAdjust) { |
| + makeSelectionAdjustments(startAdjust, endAdjust); |
| } |
| + /** |
| + * Update the context based on the given selection. |
| + * TODO(donnd): This method of finding the adjustment to the selection is unreliable! |
|
Theresa
2017/04/25 17:30:41
How unreliable? Is this something we need to fix b
Donn Denman
2017/04/25 22:35:36
I think we need to fix this before Stable, but it'
Theresa
2017/04/26 18:01:14
Can we make crbug.com/435778 release-blocking to m
Donn Denman
2017/04/26 20:28:16
Done.
|
| + * TODO(donnd): Replace by getting the selection adjustment directly from |
| + * {@link #onSelectionAdjusted} which is called by SelectWordAroundCaretAck |
| + * (since it knows how the selection was actually adjusted). |
| + * This method can be removed once SelectWordAroundCaretAck is in place. |
| + * @param selection The new selection. |
| + */ |
| + void updateContextFromSelection(String selection) { |
| + mInitialSelectedWord = selection; |
| + if (mSelectionStartOffset != INVALID_SELECTION_OFFSET |
| + && mSelectionEndOffset != INVALID_SELECTION_OFFSET |
| + && !TextUtils.isEmpty(mSurroundingText) && !TextUtils.isEmpty(selection)) { |
|
Theresa
2017/04/25 17:30:41
Let's do an early return instead to avoid one leve
Donn Denman
2017/04/25 22:35:36
Funny, I had it that way but the early return was
|
| + int selectionLength = selection.length(); |
| + for (int i = 0; i <= selectionLength; i++) { |
| + int possibleStart = mSelectionStartOffset - i; |
| + int possibleEnd = possibleStart + selectionLength; |
| + if (possibleStart >= 0 && possibleEnd <= mSurroundingText.length() |
| + && selection.equals( |
| + mSurroundingText.substring(possibleStart, possibleEnd))) { |
| + makeSelectionAdjustments(-i, selectionLength - i); |
| + return; |
| + } |
| + } |
| + } |
| + Log.w("ContextualSearch", "Warning, unable to update context from the selection!"); |
| + } |
| + |
| + /** |
| + * Makes adjustments to the selection offsets. |
| + * @param startAdjust |
|
Theresa
2017/04/25 17:30:41
Finish JavaDoc
Donn Denman
2017/04/25 22:35:36
Done.
|
| + * @param endAdjust |
| + */ |
| + private void makeSelectionAdjustments(int startAdjust, int endAdjust) { |
| + nativeAdjustSelection(getNativePointer(), startAdjust, endAdjust); |
| + // Fully track the selection as it changes. |
| + mSelectionStartOffset += startAdjust; |
| + mSelectionEndOffset += endAdjust; |
| + // Notify of changes. |
| + onSelectionChanged(); |
| + } |
| + |
| + /** |
| + * Notifies this instance that the selection has been changed. |
| + */ |
| + abstract void onSelectionChanged(); |
| + |
| + // TODO(donnd): Add a test for this class! |
| + |
| // ============================================================================================ |
| // Native callback support. |
| // ============================================================================================ |
| @@ -85,6 +225,8 @@ public class ContextualSearchContext { |
| // ============================================================================================ |
| private native long nativeInit(); |
| private native void nativeDestroy(long nativeContextualSearchContext); |
| - private native void nativeSetResolveProperties(long nativeContextualSearchContext, |
| - String selection, String homeCountry, boolean maySendBasePageUrl); |
| + private native void nativeSetResolveProperties( |
| + long nativeContextualSearchContext, String homeCountry, boolean maySendBasePageUrl); |
| + private native void nativeAdjustSelection( |
| + long nativeContextualSearchContext, int startAdjust, int endAdjust); |
| } |