Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java

Issue 1206673003: Merge java_staging/src into java/src. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
deleted file mode 100644
index d75f35163ab16d1fe2d487ff8c508089c2c32f25..0000000000000000000000000000000000000000
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ /dev/null
@@ -1,635 +0,0 @@
-// 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 org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.R;
-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, String url) {
- 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);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698