| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..576b8e71c5f02dace85ebc069111c43310d40284
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
|
| @@ -0,0 +1,636 @@
|
| +// Copyright 2015 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.chrome.browser.widget.findinpage;
|
| +
|
| +import android.annotation.SuppressLint;
|
| +import android.content.Context;
|
| +import android.graphics.Rect;
|
| +import android.os.Handler;
|
| +import android.os.Vibrator;
|
| +import android.provider.Settings;
|
| +import android.support.v4.view.accessibility.AccessibilityEventCompat;
|
| +import android.text.Editable;
|
| +import android.text.InputType;
|
| +import android.text.TextWatcher;
|
| +import android.util.AttributeSet;
|
| +import android.view.ActionMode;
|
| +import android.view.Gravity;
|
| +import android.view.KeyEvent;
|
| +import android.view.View;
|
| +import android.widget.LinearLayout;
|
| +import android.widget.TextView;
|
| +
|
| +import com.google.android.apps.chrome.R;
|
| +
|
| +import org.chromium.base.VisibleForTesting;
|
| +import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid;
|
| +import org.chromium.chrome.browser.EmptyTabObserver;
|
| +import org.chromium.chrome.browser.FindMatchRectsDetails;
|
| +import org.chromium.chrome.browser.FindNotificationDetails;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.TabObserver;
|
| +import org.chromium.chrome.browser.findinpage.FindInPageBridge;
|
| +import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
|
| +import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
|
| +import org.chromium.chrome.browser.tabmodel.TabModelObserver;
|
| +import org.chromium.chrome.browser.tabmodel.TabModelSelector;
|
| +import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
|
| +import org.chromium.chrome.browser.widget.TintedImageButton;
|
| +import org.chromium.chrome.browser.widget.VerticallyFixedEditText;
|
| +import org.chromium.ui.UiUtils;
|
| +
|
| +/** A toolbar providing find in page functionality. */
|
| +public class FindToolbar extends LinearLayout
|
| + implements ChromeWebContentsDelegateAndroid.FindResultListener,
|
| + ChromeWebContentsDelegateAndroid.FindMatchRectsListener {
|
| + private static final long ACCESSIBLE_ANNOUNCEMENT_DELAY_MILLIS = 500;
|
| +
|
| + // Toolbar UI
|
| + private TextView mFindStatus;
|
| + protected FindQuery mFindQuery;
|
| + protected TintedImageButton mCloseFindButton;
|
| + protected TintedImageButton mFindPrevButton;
|
| + protected TintedImageButton mFindNextButton;
|
| +
|
| + private FindResultBar mResultBar = null;
|
| +
|
| + protected TabModelSelector mTabModelSelector;
|
| + private final TabModelSelectorObserver mTabModelSelectorObserver;
|
| + private final TabModelObserver mTabModelObserver;
|
| + private Tab mCurrentTab;
|
| + private final TabObserver mTabObserver;
|
| + private FindInPageBridge mFindInPageBridge;
|
| + private FindToolbarObserver mObserver;
|
| +
|
| + /** Most recently entered search text (globally, in non-incognito tabs). */
|
| + private String mLastUserSearch = "";
|
| +
|
| + /** Whether toolbar text is being set automatically (not typed by user). */
|
| + private boolean mSettingFindTextProgrammatically = false;
|
| +
|
| + /** Whether the search key should trigger a new search. */
|
| + private boolean mSearchKeyShouldTriggerSearch = false;
|
| +
|
| + private boolean mActive = false;
|
| +
|
| + private Handler mHandler = new Handler();
|
| + private Runnable mAccessibleAnnouncementRunnable;
|
| + private boolean mAccessibilityDidActivateResult;
|
| +
|
| + /** Subclasses EditText in order to intercept BACK key presses. */
|
| + @SuppressLint("Instantiatable")
|
| + static class FindQuery extends VerticallyFixedEditText {
|
| + private FindToolbar mFindToolbar;
|
| +
|
| + public FindQuery(Context context, AttributeSet attrs) {
|
| + super(context, attrs);
|
| + }
|
| +
|
| + void setFindToolbar(FindToolbar findToolbar) {
|
| + mFindToolbar = findToolbar;
|
| + }
|
| +
|
| + @Override
|
| + public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
| + if (keyCode == KeyEvent.KEYCODE_BACK) {
|
| + if (event.getAction() == KeyEvent.ACTION_DOWN
|
| + && event.getRepeatCount() == 0) {
|
| + // Tell the framework to start tracking this event.
|
| + getKeyDispatcherState().startTracking(event, this);
|
| + return true;
|
| + } else if (event.getAction() == KeyEvent.ACTION_UP) {
|
| + getKeyDispatcherState().handleUpEvent(event);
|
| + if (event.isTracking() && !event.isCanceled()) {
|
| + mFindToolbar.deactivate();
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + return super.onKeyPreIme(keyCode, event);
|
| + }
|
| +
|
| + @Override
|
| + public boolean onKeyDown(int keyCode, KeyEvent event) {
|
| + if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_F3
|
| + || (keyCode == KeyEvent.KEYCODE_G && event.isCtrlPressed())) {
|
| + mFindToolbar.hideKeyboardAndStartFinding(!event.isShiftPressed());
|
| + return true;
|
| + }
|
| + return super.onKeyDown(keyCode, event);
|
| + }
|
| + }
|
| +
|
| + public FindToolbar(Context context, AttributeSet attrs) {
|
| + super(context, attrs);
|
| +
|
| + mTabObserver = new EmptyTabObserver() {
|
| + @Override
|
| + public void onPageLoadStarted(Tab tab) {
|
| + deactivate();
|
| + }
|
| +
|
| + @Override
|
| + public void onContentChanged(Tab tab) {
|
| + deactivate();
|
| + }
|
| +
|
| + @Override
|
| + public void onClosingStateChanged(Tab tab, boolean closing) {
|
| + if (closing) deactivate();
|
| + }
|
| + };
|
| +
|
| + mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
|
| + @Override
|
| + public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
|
| + deactivate();
|
| + updateVisualsForTabModel(newModel.isIncognito());
|
| + }
|
| + };
|
| +
|
| + mTabModelObserver = new EmptyTabModelObserver() {
|
| + @Override
|
| + public void didSelectTab(Tab tab, TabSelectionType type, int lastId) {
|
| + deactivate();
|
| + }
|
| + };
|
| + }
|
| +
|
| + @Override
|
| + public void onFinishInflate() {
|
| + setOrientation(HORIZONTAL);
|
| + setGravity(Gravity.CENTER_VERTICAL);
|
| +
|
| + mFindQuery = (FindQuery) findViewById(R.id.find_query);
|
| + mFindQuery.setFindToolbar(this);
|
| + mFindQuery.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER);
|
| + mFindQuery.setSelectAllOnFocus(true);
|
| + mFindQuery.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
| + @Override
|
| + public void onFocusChange(View v, boolean hasFocus) {
|
| + mAccessibilityDidActivateResult = false;
|
| + if (!hasFocus) {
|
| + if (mFindQuery.getText().length() > 0) {
|
| + mSearchKeyShouldTriggerSearch = true;
|
| + }
|
| + UiUtils.hideKeyboard(mFindQuery);
|
| + }
|
| + }
|
| + });
|
| + mFindQuery.addTextChangedListener(new TextWatcher() {
|
| + @Override
|
| + public void onTextChanged(CharSequence s, int start, int before, int count) {
|
| + mAccessibilityDidActivateResult = false;
|
| + setPrevNextEnabled(s.length() > 0);
|
| +
|
| + if (mSettingFindTextProgrammatically) return;
|
| +
|
| + // If we're called during onRestoreInstanceState() the current
|
| + // view won't have been set yet. TODO(husky): Find a better fix.
|
| + assert mCurrentTab != null;
|
| + assert mCurrentTab.getContentViewCore() != null;
|
| + if (mCurrentTab.getContentViewCore() == null) return;
|
| +
|
| + if (s.length() > 0) {
|
| + // Don't clearResults() as that would cause flicker.
|
| + // Just wait until onFindResultReceived updates it.
|
| + mSearchKeyShouldTriggerSearch = false;
|
| + mFindInPageBridge.startFinding(s.toString(), true, false);
|
| + } else {
|
| + clearResults();
|
| + mFindInPageBridge.stopFinding();
|
| + }
|
| +
|
| + if (!mCurrentTab.isIncognito()) {
|
| + mLastUserSearch = s.toString();
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void beforeTextChanged(CharSequence s,
|
| + int start, int count, int after) {
|
| + }
|
| +
|
| + @Override
|
| + public void afterTextChanged(Editable s) {
|
| + }
|
| + });
|
| + mFindQuery.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
| + @Override
|
| + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
| + if (event != null && event.getAction() == KeyEvent.ACTION_UP) return false;
|
| +
|
| + // Only trigger a new find if the text was set programmatically.
|
| + // Otherwise just revisit the current active match.
|
| + if (mSearchKeyShouldTriggerSearch) {
|
| + mSearchKeyShouldTriggerSearch = false;
|
| + hideKeyboardAndStartFinding(true);
|
| + } else {
|
| + UiUtils.hideKeyboard(mFindQuery);
|
| + mFindInPageBridge.activateFindInPageResultForAccessibility();
|
| + mAccessibilityDidActivateResult = true;
|
| + }
|
| + return true;
|
| + }
|
| + });
|
| +
|
| + mFindStatus = (TextView) findViewById(R.id.find_status);
|
| +
|
| + mFindPrevButton = (TintedImageButton) findViewById(R.id.find_prev_button);
|
| + mFindPrevButton.setOnClickListener(new OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + hideKeyboardAndStartFinding(false);
|
| + }
|
| + });
|
| +
|
| + mFindNextButton = (TintedImageButton) findViewById(R.id.find_next_button);
|
| + mFindNextButton.setOnClickListener(new OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + hideKeyboardAndStartFinding(true);
|
| + }
|
| + });
|
| +
|
| + setPrevNextEnabled(false);
|
| +
|
| + mCloseFindButton = (TintedImageButton) findViewById(R.id.close_find_button);
|
| + mCloseFindButton.setOnClickListener(new OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + deactivate();
|
| + }
|
| + });
|
| + }
|
| +
|
| + // Overriden by subclasses.
|
| + protected void findResultSelected(Rect rect) {
|
| + }
|
| +
|
| + private void hideKeyboardAndStartFinding(boolean forward) {
|
| + final String findQuery = mFindQuery.getText().toString();
|
| + if (findQuery.length() == 0) return;
|
| +
|
| + UiUtils.hideKeyboard(mFindQuery);
|
| + mFindInPageBridge.startFinding(findQuery, forward, false);
|
| + mFindInPageBridge.activateFindInPageResultForAccessibility();
|
| + mAccessibilityDidActivateResult = true;
|
| + }
|
| +
|
| + private boolean mShowKeyboardOnceWindowIsFocused = false;
|
| +
|
| + @Override
|
| + public void onWindowFocusChanged(boolean hasFocus) {
|
| + super.onWindowFocusChanged(hasFocus);
|
| +
|
| + if (mShowKeyboardOnceWindowIsFocused) {
|
| + mShowKeyboardOnceWindowIsFocused = false;
|
| + // See showKeyboard() for explanation.
|
| + // By this point we've already waited till the window regains focus
|
| + // from the options menu, but we still need to use postDelayed with
|
| + // a zero wait time to delay until all the side-effects are complete
|
| + // (e.g. becoming the target of the Input Method).
|
| + mHandler.postDelayed(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + showKeyboard();
|
| +
|
| + // This is also a great time to set accessibility focus to the query box -
|
| + // this also fails if we don't wait until the window regains focus.
|
| + // Sending a HOVER_ENTER event before the ACCESSIBILITY_FOCUSED event
|
| + // is a widely-used hack to force TalkBack to move accessibility focus
|
| + // to a view, which is discouraged in general but reasonable in this case.
|
| + mFindQuery.sendAccessibilityEvent(
|
| + AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER);
|
| + mFindQuery.sendAccessibilityEvent(
|
| + AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
| + }
|
| + }, 0);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void onFindMatchRects(FindMatchRectsDetails matchRects) {
|
| + if (mResultBar == null) return;
|
| + if (mFindQuery.getText().length() > 0) {
|
| + mResultBar.setMatchRects(matchRects.version, matchRects.rects, matchRects.activeRect);
|
| + } else {
|
| + // Since we don't issue a request for an empty string we never get a 'no rects' response
|
| + // in that case. This could cause us to display stale state if the user is deleting the
|
| + // search string. If the response for the last character comes in after we've issued a
|
| + // clearReslts in TextChangedListener that response will be accepted and we will end up
|
| + // showing stale results for an empty query.
|
| + // Sending an empty string message seems a bit wasteful, so instead we simply ignore all
|
| + // results that come in if the query is empty.
|
| + mResultBar.clearMatchRects();
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void onFindResult(FindNotificationDetails result) {
|
| + if (mResultBar != null) mResultBar.mWaitingForActivateAck = false;
|
| +
|
| + if ((result.activeMatchOrdinal == -1 || result.numberOfMatches == 1)
|
| + && !result.finalUpdate) {
|
| + // Wait until activeMatchOrdinal has been determined (is no longer
|
| + // -1) before showing counts. Additionally, to reduce flicker,
|
| + // ignore short-lived interim notifications with numberOfMatches set
|
| + // to 1, which are sent as soon as something has been found (see bug
|
| + // 894389 and FindBarController::UpdateFindBarForCurrentResult).
|
| + // Instead wait until the scoping effort starts returning real
|
| + // match counts (or the search actually finishes with 1 result).
|
| + // This also protects against receiving bogus rendererSelectionRects
|
| + // at the start (see below for why we can't filter them out).
|
| + return;
|
| + }
|
| +
|
| + if (result.finalUpdate) {
|
| + if (result.numberOfMatches > 0) {
|
| + // TODO(johnme): Don't wait till end of find, stream rects live!
|
| + mFindInPageBridge.requestFindMatchRects(
|
| + mResultBar != null ? mResultBar.mRectsVersion : -1);
|
| + } else {
|
| + clearResults();
|
| + }
|
| +
|
| + findResultSelected(result.rendererSelectionRect);
|
| + }
|
| +
|
| + // Even though we wait above until activeMatchOrdinal is no longer -1,
|
| + // it's possible for it to still be -1 (unknown) in the final find
|
| + // notification. This happens very rarely, e.g. if the m_activeMatch
|
| + // found by WebFrameImpl::find has been removed from the DOM by the time
|
| + // WebFrameImpl::scopeStringMatches tries to find the ordinal of the
|
| + // active match (while counting the matches), as in b/4147049. In such
|
| + // cases it looks less broken to show 0 instead of -1 (as desktop does).
|
| + Context context = getContext();
|
| + String text = context.getResources().getString(
|
| + R.string.find_in_page_count,
|
| + Math.max(result.activeMatchOrdinal, 0),
|
| + result.numberOfMatches);
|
| + setStatus(text, result.numberOfMatches == 0);
|
| +
|
| + // The accessible version will be something like "Result 1 of 9".
|
| + String accessibleText = getAccessibleStatusText(
|
| + Math.max(result.activeMatchOrdinal, 0),
|
| + result.numberOfMatches);
|
| + mFindStatus.setContentDescription(accessibleText);
|
| + announceStatusForAccessibility(accessibleText);
|
| +
|
| + // Vibrate when no results are found, unless you're just deleting chars.
|
| + if (result.numberOfMatches == 0 && result.finalUpdate
|
| + && !mFindInPageBridge.getPreviousFindText().startsWith(
|
| + mFindQuery.getText().toString())) {
|
| + final boolean hapticFeedbackEnabled = Settings.System.getInt(
|
| + context.getContentResolver(),
|
| + Settings.System.HAPTIC_FEEDBACK_ENABLED, 1) == 1;
|
| + if (hapticFeedbackEnabled) {
|
| + Vibrator v = (Vibrator) context.getSystemService(
|
| + Context.VIBRATOR_SERVICE);
|
| + final long noResultsVibrateDurationMs = 50;
|
| + v.vibrate(noResultsVibrateDurationMs);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private String getAccessibleStatusText(int activeMatchOrdinal, int numberOfMatches) {
|
| + Context context = getContext();
|
| + return (numberOfMatches > 0)
|
| + ? context.getResources().getString(
|
| + R.string.accessible_find_in_page_count,
|
| + activeMatchOrdinal,
|
| + numberOfMatches)
|
| + : context.getResources().getString(R.string.accessible_find_in_page_no_results);
|
| + }
|
| +
|
| + private void announceStatusForAccessibility(final String announcementText) {
|
| + // Don't announce if the user has already activated a result by pressing Enter/Search
|
| + // or clicking on the Next/Previous buttons.
|
| + if (mAccessibilityDidActivateResult) return;
|
| +
|
| + // Delay the announcement briefly, and if any additional announcements come in,
|
| + // have them preempt the previous queued one. That makes for a better user experience
|
| + // than speaking instantly as you're typing and constantly interrupting itself.
|
| +
|
| + if (mAccessibleAnnouncementRunnable != null) {
|
| + mHandler.removeCallbacks(mAccessibleAnnouncementRunnable);
|
| + }
|
| +
|
| + mAccessibleAnnouncementRunnable = new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mFindQuery.announceForAccessibility(announcementText);
|
| + }
|
| + };
|
| + mHandler.postDelayed(mAccessibleAnnouncementRunnable,
|
| + ACCESSIBLE_ANNOUNCEMENT_DELAY_MILLIS);
|
| + }
|
| +
|
| + /** The find toolbar's container must provide access to its TabModel. */
|
| + public void setTabModelSelector(TabModelSelector modelSelector) {
|
| + mTabModelSelector = modelSelector;
|
| + updateVisualsForTabModel(modelSelector != null && modelSelector.isIncognitoSelected());
|
| + }
|
| +
|
| + /**
|
| + * Handles updating any visual elements of the find toolbar based on changes to the tab model.
|
| + * @param isIncognito Whether the current tab model is incognito or not.
|
| + */
|
| + protected void updateVisualsForTabModel(boolean isIncognito) {
|
| + }
|
| +
|
| + /**
|
| + * Sets a custom ActionMode.Callback instance to the FindQuery. This lets us
|
| + * get notified when the user tries to do copy, paste, etc. on the FindQuery.
|
| + * @param callback The ActionMode.Callback instance to be notified when selection ActionMode
|
| + * is triggered.
|
| + */
|
| + public void setActionModeCallbackForTextEdit(ActionMode.Callback callback) {
|
| + mFindQuery.setCustomSelectionActionModeCallback(callback);
|
| + }
|
| +
|
| + /**
|
| + * Sets the observer to be notified of changes to the find toolbar.
|
| + */
|
| + protected void setObserver(FindToolbarObserver observer) {
|
| + mObserver = observer;
|
| + }
|
| +
|
| + /**
|
| + * Checks to see if a ContentViewCore is available to hook into.
|
| + */
|
| + protected boolean isViewAvailable() {
|
| + Tab currentTab = mTabModelSelector.getCurrentTab();
|
| + return currentTab != null && currentTab.getContentViewCore() != null;
|
| + }
|
| +
|
| + /**
|
| + * Initializes the find toolbar. Should be called just after the find toolbar is shown.
|
| + * If the toolbar is already showing, this just focuses the toolbar.
|
| + */
|
| + public void activate() {
|
| + if (!isViewAvailable()) return;
|
| + if (mActive) {
|
| + requestQueryFocus();
|
| + return;
|
| + }
|
| +
|
| + mTabModelSelector.addObserver(mTabModelSelectorObserver);
|
| + for (TabModel model : mTabModelSelector.getModels()) {
|
| + model.addObserver(mTabModelObserver);
|
| + }
|
| + mCurrentTab = mTabModelSelector.getCurrentTab();
|
| + mCurrentTab.addObserver(mTabObserver);
|
| + mFindInPageBridge = new FindInPageBridge(mCurrentTab.getWebContents());
|
| + mCurrentTab.getChromeWebContentsDelegateAndroid().setFindResultListener(this);
|
| + mCurrentTab.getChromeWebContentsDelegateAndroid().setFindMatchRectsListener(this);
|
| + initializeFindText();
|
| + mFindQuery.requestFocus();
|
| + // The keyboard doesn't show itself automatically.
|
| + showKeyboard();
|
| + // Always show the bar to make the FindToolbar more distinct from the Omnibox.
|
| + setResultsBarVisibility(true);
|
| + mActive = true;
|
| + updateVisualsForTabModel(mTabModelSelector.isIncognitoSelected());
|
| +
|
| + // Let everyone know that we've just updated.
|
| + if (mObserver != null) mObserver.onFindToolbarShown();
|
| + }
|
| +
|
| + /** Call this just before closing the find toolbar. */
|
| + public void deactivate() {
|
| + if (!mActive) return;
|
| +
|
| + if (mObserver != null) mObserver.onFindToolbarHidden();
|
| +
|
| + setResultsBarVisibility(false);
|
| +
|
| + mTabModelSelector.removeObserver(mTabModelSelectorObserver);
|
| + for (TabModel model : mTabModelSelector.getModels()) {
|
| + model.removeObserver(mTabModelObserver);
|
| + }
|
| +
|
| + mCurrentTab.getChromeWebContentsDelegateAndroid().setFindResultListener(null);
|
| + mCurrentTab.getChromeWebContentsDelegateAndroid().setFindMatchRectsListener(null);
|
| + mCurrentTab.removeObserver(mTabObserver);
|
| +
|
| + UiUtils.hideKeyboard(mFindQuery);
|
| + if (mFindQuery.getText().length() > 0) {
|
| + clearResults();
|
| + mFindInPageBridge.stopFinding();
|
| + }
|
| +
|
| + mFindInPageBridge.destroy();
|
| + mActive = false;
|
| + }
|
| +
|
| + /**
|
| + * Requests focus for the query input field and shows the keyboard.
|
| + */
|
| + public void requestQueryFocus() {
|
| + mFindQuery.requestFocus();
|
| + showKeyboard();
|
| + }
|
| +
|
| + /** Called by the tablet-specific implementation when the hide animation is about to begin. */
|
| + protected void onHideAnimationStart() {
|
| + // We do this because hiding the bar after the animation ends doesn't look good.
|
| + setResultsBarVisibility(false);
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + public FindResultBar getFindResultBar() {
|
| + return mResultBar;
|
| + }
|
| +
|
| + /**
|
| + * Returns whether an animation to show/hide the FindToolbar is currently running.
|
| + */
|
| + @VisibleForTesting
|
| + public boolean isAnimating() {
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Restores the last text searched in this tab, or the global last search.
|
| + */
|
| + private void initializeFindText() {
|
| + mSettingFindTextProgrammatically = true;
|
| + String findText = null;
|
| + if (mSettingFindTextProgrammatically) {
|
| + findText = mFindInPageBridge.getPreviousFindText();
|
| + if (findText.isEmpty() && !mCurrentTab.isIncognito()) {
|
| + findText = mLastUserSearch;
|
| + }
|
| + mSearchKeyShouldTriggerSearch = true;
|
| + } else {
|
| + mSearchKeyShouldTriggerSearch = false;
|
| + }
|
| + mFindQuery.setText(findText);
|
| + mSettingFindTextProgrammatically = false;
|
| + }
|
| +
|
| + /** Clears the result displays (except in-page match highlighting). */
|
| + protected void clearResults() {
|
| + setStatus("", false);
|
| + if (mResultBar != null) {
|
| + mResultBar.clearMatchRects();
|
| + }
|
| + }
|
| +
|
| + private void setResultsBarVisibility(boolean visibility) {
|
| + if (visibility && mResultBar == null && mCurrentTab != null
|
| + && mCurrentTab.getContentViewCore() != null) {
|
| + mResultBar = new FindResultBar(getContext(), mCurrentTab, mFindInPageBridge);
|
| + } else if (!visibility) {
|
| + if (mResultBar != null) {
|
| + mResultBar.dismiss();
|
| + mResultBar = null;
|
| + }
|
| + }
|
| + }
|
| +
|
| + private void setStatus(String text, boolean failed) {
|
| + mFindStatus.setText(text);
|
| + mFindStatus.setContentDescription(null);
|
| + boolean incognito = mTabModelSelector != null && mTabModelSelector.isIncognitoSelected();
|
| + mFindStatus.setTextColor(getStatusColor(failed, incognito));
|
| + }
|
| +
|
| + /**
|
| + * @param failed Whether or not the find query had any matching results.
|
| + * @param incognito Whether or not the current tab is incognito.
|
| + * @return The color of the status text.
|
| + */
|
| + protected int getStatusColor(boolean failed, boolean incognito) {
|
| + int colorResourceId = failed ? R.color.find_in_page_failed_results_status_color
|
| + : R.color.find_in_page_results_status_color;
|
| + return getContext().getResources().getColor(colorResourceId);
|
| + }
|
| +
|
| + protected void setPrevNextEnabled(boolean enable) {
|
| + mFindPrevButton.setEnabled(enable);
|
| + mFindNextButton.setEnabled(enable);
|
| + }
|
| +
|
| + private void showKeyboard() {
|
| + if (!mFindQuery.hasWindowFocus()) {
|
| + // HACK: showKeyboard() is normally called from activate() which is
|
| + // triggered by an options menu item. Unfortunately, because the
|
| + // options menu is still focused at this point, that means our
|
| + // window doesn't actually have focus when this first gets called,
|
| + // and hence it isn't the target of the Input Method, and in
|
| + // practice that means the soft keyboard never shows up (whatever
|
| + // flags you pass). So as a workaround we postpone asking for the
|
| + // keyboard to be shown until just after the window gets refocused.
|
| + // See onWindowFocusChanged(boolean hasFocus).
|
| + mShowKeyboardOnceWindowIsFocused = true;
|
| + return;
|
| + }
|
| + UiUtils.showKeyboard(mFindQuery);
|
| + }
|
| +}
|
|
|