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..0f56a3639b7c9bdc60cbc83e4cf677e5f9c6005c 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,61 @@ |
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; |
+ private static final String TAG = "ContextualSearch"; |
// 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 +69,153 @@ 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 original selection. |
+ * @return The text that surrounds the selection, or {@code null} if none yet known. |
*/ |
- String getSelection() { |
- return mSelection; |
+ @Nullable |
+ String getSurroundingText() { |
+ return mSurroundingText; |
} |
/** |
- * @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 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 encoding of the base page. |
+ */ |
+ String getEncoding() { |
+ return mEncoding; |
+ } |
+ |
+ /** |
+ * @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! |
+ * 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. |
+ * See crbug.com/435778 for details. |
+ * @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)) { |
+ return; |
+ } |
+ |
+ 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(TAG, "Warning, unable to update context from the selection!"); |
+ } |
+ |
+ /** |
+ * Makes adjustments to the selection offsets. |
+ * @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). |
+ */ |
+ 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 +231,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); |
} |