Commit 22c27291 authored by Patrick Noland's avatar Patrick Noland Committed by Chromium LUCI CQ

[ToolbarMVC] Move url focus logic to LBMediator

This change moves setUrlFocusChangeInProgress, onUrlFocusChange, and
finishUrlFocusChange to LocationBarMediator, consolidating phone- and
tablet-specific logic as appropriate. Moving these together allows
us to move several pieces of state into LocationBarMediator together,
e.g. mUrlFocusedWithoutAnimations and mUrlFocusChangeListeners.
Unit and instrumentation tests covering the migrated logic are also
included, and some on-focus triggered accessibility logic has been moved
to UrlBarCoordinator.

Bug: 1147581

Change-Id: I4cab5b32402b86a953d22418eb94f375a21b9cc2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2598036Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Commit-Queue: Patrick Noland <pnoland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845273}
parent b8c095a7
......@@ -127,7 +127,7 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
mLocationBarLayout, locationBarDataProvider, profileObservableSupplier,
PrivacyPreferencesManagerImpl.getInstance(), overrideUrlLoadingDelegate,
LocaleManager.getInstance(), mTemplateUrlServiceSupplier, backKeyBehavior,
windowAndroid);
windowAndroid, isTablet());
mUrlCoordinator =
new UrlBarCoordinator((UrlBar) mUrlBar, windowDelegate, actionModeCallback,
mCallbackController.makeCancelable(mLocationBarMediator::onUrlFocusChange),
......@@ -138,17 +138,21 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
StatusView statusView = mLocationBarLayout.findViewById(R.id.location_bar_status);
mStatusCoordinator = new StatusCoordinator(isTablet(), statusView, mUrlCoordinator,
incognitoStateProvider, modalDialogManagerSupplier, locationBarDataProvider);
mLocationBarMediator.setCoordinators(
mUrlCoordinator, mAutocompleteCoordinator, mStatusCoordinator);
mUrlBar.setOnKeyListener(mLocationBarMediator);
mLocationBarMediator.addUrlFocusChangeListener(mAutocompleteCoordinator);
mLocationBarMediator.addUrlFocusChangeListener(mUrlCoordinator);
mDeleteButton = mLocationBarLayout.findViewById(R.id.delete_button);
mMicButton = mLocationBarLayout.findViewById(R.id.mic_button);
mDeleteButton.setOnClickListener(mLocationBarMediator::deleteButtonClicked);
mMicButton = mLocationBarLayout.findViewById(R.id.mic_button);
mMicButton.setOnClickListener(mLocationBarMediator::micButtonClicked);
mUrlBar.setOnKeyListener(mLocationBarMediator);
mUrlCoordinator.addUrlTextChangeListener(mAutocompleteCoordinator);
// The LocationBar's direction is tied to the UrlBar's text direction. Icons inside the
// location bar, e.g. lock, refresh, X, should be reversed if UrlBar's text is RTL.
mUrlCoordinator.setUrlDirectionListener(
......@@ -158,8 +162,6 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
}));
mLocationBarLayout.getContext().registerComponentCallbacks(mLocationBarMediator);
mLocationBarLayout.addUrlFocusChangeListener(mAutocompleteCoordinator);
mLocationBarLayout.addUrlFocusChangeListener(mUrlCoordinator);
mLocationBarLayout.initialize(mAutocompleteCoordinator, mUrlCoordinator, mStatusCoordinator,
locationBarDataProvider);
......@@ -176,28 +178,40 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
public void destroy() {
mActivityLifecycleDispatcher.unregister(this);
mActivityLifecycleDispatcher = null;
if (mSubCoordinator != null) {
mSubCoordinator.destroy();
mSubCoordinator = null;
}
mUrlBar.setOnKeyListener(null);
mUrlBar = null;
mDeleteButton.setOnClickListener(null);
mDeleteButton = null;
mMicButton.setOnClickListener(null);
mMicButton = null;
mLocationBarMediator.removeUrlFocusChangeListener(mUrlCoordinator);
mUrlCoordinator.destroy();
mUrlCoordinator = null;
mLocationBarLayout.getContext().unregisterComponentCallbacks(mLocationBarMediator);
mLocationBarLayout.removeUrlFocusChangeListener(mAutocompleteCoordinator);
mLocationBarMediator.removeUrlFocusChangeListener(mAutocompleteCoordinator);
mAutocompleteCoordinator.destroy();
mAutocompleteCoordinator = null;
mStatusCoordinator.destroy();
mStatusCoordinator = null;
mLocationBarLayout.destroy();
mLocationBarLayout = null;
mCallbackController.destroy();
mCallbackController = null;
mLocationBarMediator.destroy();
mLocationBarMediator = null;
}
......@@ -251,7 +265,7 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
@Override
public View getContainerView() {
return mLocationBarLayout.getContainerView();
return mLocationBarLayout;
}
@Override
......@@ -431,6 +445,25 @@ public final class LocationBarCoordinator implements LocationBar, NativeInitObse
mLocationBarMediator.setUrlFocusChangeInProgress(inProgress);
}
/**
* Handles any actions to be performed after all other actions triggered by the URL focus
* change. This will be called after any animations are performed to transition from one
* focus state to the other.
*
* @param hasFocus Whether the URL field has gained focus.
* @param shouldShowKeyboard Whether the keyboard should be shown. This value should be the same
* as hasFocus by default.
* @param shouldShowInOverviewMode Whether the location bar should be shown when in overview
* mode.
*/
public void finishUrlFocusChange(
boolean hasFocus, boolean shouldShowKeyboard, boolean shouldShowInOverviewMode) {
mLocationBarMediator.finishUrlFocusChange(hasFocus, shouldShowKeyboard);
if (shouldShowInOverviewMode) {
mStatusCoordinator.onSecurityStateChanged();
}
}
public void setVoiceRecognitionHandlerForTesting(
VoiceRecognitionHandler voiceRecognitionHandler) {
mLocationBarMediator.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler);
......
......@@ -70,25 +70,6 @@ public class LocationBarCoordinatorPhone implements LocationBarCoordinator.SubCo
}
}
/**
* Handles any actions to be performed after all other actions triggered by the URL focus
* change. This will be called after any animations are performed to transition from one
* focus state to the other.
*
* @param hasFocus Whether the URL field has gained focus.
* @param shouldShowKeyboard Whether the keyboard should be shown. This value should be the same
* as hasFocus by default.
* @param shouldShowInOverviewMode Whether the location bar should be shown when in overview
* mode.
*/
public void finishUrlFocusChange(
boolean hasFocus, boolean shouldShowKeyboard, boolean shouldShowInOverviewMode) {
mLocationBarPhone.finishUrlFocusChange(hasFocus, shouldShowKeyboard);
if (shouldShowInOverviewMode) {
mStatusCoordinator.onSecurityStateChanged();
}
}
/**
* Returns {@link FrameLayout.LayoutParams} of the LocationBar view.
*
......
......@@ -14,7 +14,6 @@ import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
......@@ -25,17 +24,10 @@ import androidx.annotation.VisibleForTesting;
import androidx.core.view.MarginLayoutParamsCompat;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ObserverList;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType;
import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
import org.chromium.chrome.browser.omnibox.status.StatusView;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.components.browser_ui.widget.CompositeTouchDelegate;
import java.util.ArrayList;
......@@ -55,19 +47,12 @@ public class LocationBarLayout extends FrameLayout {
protected AutocompleteCoordinator mAutocompleteCoordinator;
protected LocationBarDataProvider mLocationBarDataProvider;
private final ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners =
new ObserverList<>();
private final List<Runnable> mDeferredNativeRunnables = new ArrayList<Runnable>();
protected StatusCoordinator mStatusCoordinator;
private boolean mUrlFocusChangeInProgress;
protected boolean mNativeInitialized;
private boolean mUrlHasFocus;
private boolean mUrlFocusedFromFakebox;
private boolean mUrlFocusedFromQueryTiles;
private boolean mUrlFocusedWithoutAnimations;
protected boolean mVoiceSearchEnabled;
protected float mUrlFocusChangeFraction;
......@@ -97,8 +82,6 @@ public class LocationBarLayout extends FrameLayout {
* Called when activity is being destroyed.
*/
void destroy() {
mUrlFocusChangeListeners.clear();
if (mAutocompleteCoordinator != null) {
// Don't call destroy() on mAutocompleteCoordinator since we don't own it.
mAutocompleteCoordinator = null;
......@@ -143,7 +126,6 @@ public class LocationBarLayout extends FrameLayout {
mLocationBarDataProvider = locationBarDataProvider;
updateButtonVisibility();
updateShouldAnimateIconChanges();
}
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
......@@ -157,34 +139,9 @@ public class LocationBarLayout extends FrameLayout {
public void onFinishNativeInitialization() {
mNativeInitialized = true;
for (Runnable deferredRunnable : mDeferredNativeRunnables) {
post(deferredRunnable);
}
mDeferredNativeRunnables.clear();
updateMicButtonVisibility();
}
/* package */ boolean didFocusUrlFromFakebox() {
return mUrlFocusedFromFakebox;
}
/* package */ void setUrlFocusedFromFakebox(boolean focusedFromFakebox) {
mUrlFocusedFromFakebox = focusedFromFakebox;
}
/* package */ boolean didFocusUrlFromQueryTiles() {
return mUrlFocusedFromQueryTiles;
}
/* package */ void setUrlFocusedFromQueryTiles(boolean focusedFromQueryTiles) {
mUrlFocusedFromQueryTiles = focusedFromQueryTiles;
}
/* package */ void setIsUrlFocusedWithoutAnimations(boolean isUrlFocusedWithoutAnimations) {
mUrlFocusedWithoutAnimations = isUrlFocusedWithoutAnimations;
}
/* package */ void setMicButtonDrawable(Drawable drawable) {
mMicButton.setImageDrawable(drawable);
}
......@@ -221,24 +178,8 @@ public class LocationBarLayout extends FrameLayout {
return mUrlHasFocus;
}
/* package */ boolean isUrlBarFocusedWithoutAnimations() {
return mUrlFocusedWithoutAnimations;
}
/* package */ void addUrlFocusChangeListener(UrlFocusChangeListener listener) {
mUrlFocusChangeListeners.addObserver(listener);
}
/* package */ void removeUrlFocusChangeListener(UrlFocusChangeListener listener) {
mUrlFocusChangeListeners.removeObserver(listener);
}
protected void onNtpStartedLoading() {}
public View getContainerView() {
return this;
}
public View getSecurityIconView() {
return mStatusCoordinator.getSecurityIconView();
}
......@@ -248,22 +189,8 @@ public class LocationBarLayout extends FrameLayout {
mUrlFocusChangeFraction = fraction;
}
/**
* Evaluate state and update child components' animations.
*
* This call and all overrides should invoke `notifyShouldAnimateIconChanges(boolean)` with a
* computed boolean value toggling animation support in child components.
*/
protected void updateShouldAnimateIconChanges() {
notifyShouldAnimateIconChanges(mUrlHasFocus);
}
/**
* Toggle child components animations.
* @param shouldAnimate Boolean flag indicating whether animations should be enabled.
*/
protected void notifyShouldAnimateIconChanges(boolean shouldAnimate) {
mStatusCoordinator.setShouldAnimateIconChanges(shouldAnimate);
/* package */ float getUrlFocusChangeFraction() {
return mUrlFocusChangeFraction;
}
/**
......@@ -284,105 +211,15 @@ public class LocationBarLayout extends FrameLayout {
* @param inProgress Whether a URL focus change is taking place.
*/
protected void setUrlFocusChangeInProgress(boolean inProgress) {
if (mUrlCoordinator == null) return;
mUrlFocusChangeInProgress = inProgress;
if (!inProgress) {
updateButtonVisibility();
// The accessibility bounding box is not properly updated when focusing the Omnibox
// from the NTP fakebox. Clearing/re-requesting focus triggers the bounding box to
// be recalculated.
if (didFocusUrlFromFakebox() && mUrlHasFocus
&& ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
String existingText = mUrlCoordinator.getTextWithoutAutocomplete();
mUrlBar.clearFocus();
mUrlBar.requestFocus();
// Existing text (e.g. if the user pasted via the fakebox) from the fake box
// should be restored after toggling the focus.
if (!TextUtils.isEmpty(existingText)) {
mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(existingText),
UrlBar.ScrollType.NO_SCROLL,
UrlBarCoordinator.SelectionState.SELECT_END);
forceOnTextChanged();
}
}
for (UrlFocusChangeListener listener : mUrlFocusChangeListeners) {
listener.onUrlAnimationFinished(mUrlHasFocus);
}
}
}
/**
* Triggered when the URL input field has gained or lost focus.
* @param hasFocus Whether the URL field has gained focus.
*/
protected void onUrlFocusChange(boolean hasFocus) {
protected void setUrlHasFocus(boolean hasFocus) {
mUrlHasFocus = hasFocus;
updateButtonVisibility();
updateShouldAnimateIconChanges();
if (mUrlHasFocus) {
if (mNativeInitialized) RecordUserAction.record("FocusLocation");
UrlBarData urlBarData = mLocationBarDataProvider.getUrlBarData();
if (urlBarData.editingText != null) {
setUrlBarText(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
}
// Explicitly tell InputMethodManager that the url bar is focused before any callbacks
// so that it updates the active view accordingly. Otherwise, it may fail to update
// the correct active view if ViewGroup.addView() or ViewGroup.removeView() is called
// to update a view that accepts text input.
InputMethodManager imm = (InputMethodManager) mUrlBar.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.viewClicked(mUrlBar);
} else {
mUrlFocusedFromFakebox = false;
mUrlFocusedFromQueryTiles = false;
mUrlFocusedWithoutAnimations = false;
// Moving focus away from UrlBar(EditText) to a non-editable focus holder, such as
// ToolbarPhone, won't automatically hide keyboard app, but restart it with TYPE_NULL,
// which will result in a visual glitch. Also, currently, we do not allow moving focus
// directly from omnibox to web content's form field. Therefore, we hide keyboard on
// focus blur indiscriminately here. Note that hiding keyboard may lower FPS of other
// animation effects, but we found it tolerable in an experiment.
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
if (imm.isActive(mUrlBar)) imm.hideSoftInputFromWindow(getWindowToken(), 0, null);
}
mStatusCoordinator.onUrlFocusChange(mUrlHasFocus);
if (!mUrlFocusedWithoutAnimations) handleUrlFocusAnimation(mUrlHasFocus);
if (mUrlHasFocus && mLocationBarDataProvider.hasTab()
&& !mLocationBarDataProvider.isIncognito()) {
if (mNativeInitialized
&& TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) {
GeolocationHeader.primeLocationForGeoHeader();
} else {
mDeferredNativeRunnables.add(new Runnable() {
@Override
public void run() {
if (TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle()) {
GeolocationHeader.primeLocationForGeoHeader();
}
}
});
}
}
}
/**
* Handle and run any necessary animations that are triggered off focusing the UrlBar.
* @param hasFocus Whether focus was gained.
*/
protected void handleUrlFocusAnimation(boolean hasFocus) {
if (hasFocus) mUrlFocusedWithoutAnimations = false;
for (UrlFocusChangeListener listener : mUrlFocusChangeListeners) {
listener.onUrlFocusChange(hasFocus);
}
}
/**
......@@ -499,32 +336,6 @@ public class LocationBarLayout extends FrameLayout {
mDeleteButton.setVisibility(shouldShowDeleteButton() ? VISIBLE : GONE);
}
/**
* Changes the text on the url bar. The text update will be applied regardless of the current
* focus state (comparing to {@link LocationBarMediator#setUrl} which only applies text updates
* when not focused).
*
* @param urlBarData The contents of the URL bar, both for editing and displaying.
* @param scrollType Specifies how the text should be scrolled in the unfocused state.
* @param selectionState Specifies how the text should be selected in the focused state.
* @return Whether the URL was changed as a result of this call.
*/
/* package */ boolean setUrlBarText(
UrlBarData urlBarData, @ScrollType int scrollType, @SelectionState int selectionState) {
return mUrlCoordinator.setUrlBarData(urlBarData, scrollType, selectionState);
}
/**
* Clear any text in the URL bar.
* @return Whether this changed the existing text.
*/
/* package */ boolean setUrlBarTextEmpty() {
boolean textChanged = mUrlCoordinator.setUrlBarData(
UrlBarData.EMPTY, UrlBar.ScrollType.SCROLL_TO_BEGINNING, SelectionState.SELECT_ALL);
forceOnTextChanged();
return textChanged;
}
protected void setUnfocusedWidth(int unfocusedWidth) {
mStatusCoordinator.setUnfocusedLocationBarWidth(unfocusedWidth);
}
......@@ -566,31 +377,14 @@ public class LocationBarLayout extends FrameLayout {
return mStatusCoordinator;
}
/* package */ void forceOnTextChanged() {
String textWithoutAutocomplete = mUrlCoordinator.getTextWithoutAutocomplete();
String textWithAutocomplete = mUrlCoordinator.getTextWithAutocomplete();
mAutocompleteCoordinator.onTextChanged(textWithoutAutocomplete, textWithAutocomplete);
}
/**
* Handles any actions to be performed after all other actions triggered by the URL focus
* change. This will be called after any animations are performed to transition from one
* focus state to the other.
* @param hasFocus Whether the URL field has gained focus.
* @param shouldShowKeyboard Whether the keyboard should be shown. This value should be the same
* as hasFocus by default.
*/
protected void finishUrlFocusChange(boolean hasFocus, boolean shouldShowKeyboard) {
if (mUrlCoordinator == null) return;
mUrlCoordinator.setKeyboardVisibility(hasFocus && shouldShowKeyboard, true);
setUrlFocusChangeInProgress(false);
updateShouldAnimateIconChanges();
}
/* package */ void setVoiceSearchEnabled(boolean isEnabled) {
mVoiceSearchEnabled = isEnabled;
}
/** Update the status visibility according to the current state held in LocationBar. */
/* package */ void updateStatusVisibility() {}
/* package */ void setUrlActionContainerVisibility(int visibility) {
mUrlActionContainer.setVisibility(visibility);
}
}
......@@ -4,10 +4,14 @@
package org.chromium.chrome.browser.omnibox;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.Property;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
......@@ -19,6 +23,7 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.base.CallbackController;
import org.chromium.base.CommandLine;
import org.chromium.base.ObserverList;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.ObservableSupplier;
......@@ -41,8 +46,10 @@ import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.chrome.browser.util.KeyNavigationUtil;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.externalauth.ExternalAuthUtils;
import org.chromium.components.search_engines.TemplateUrl;
......@@ -66,6 +73,21 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
VoiceRecognitionHandler.Delegate,
AssistantVoiceSearchService.Observer, UrlBarDelegate,
OnKeyListener, ComponentCallbacks, TemplateUrlServiceObserver {
private static final long MAX_NTP_KEYBOARD_FOCUS_DURATION_MS = 200;
private final Property<LocationBarMediator, Float> mUrlFocusChangeFractionProperty =
new Property<LocationBarMediator, Float>(Float.class, "") {
@Override
public Float get(LocationBarMediator object) {
return mLocationBarLayout.getUrlFocusChangeFraction();
}
@Override
public void set(LocationBarMediator object, Float value) {
setUrlFocusChangeFraction(value);
}
};
private final LocationBarLayout mLocationBarLayout;
private VoiceRecognitionHandler mVoiceRecognitionHandler;
private final LocationBarDataProvider mLocationBarDataProvider;
......@@ -87,8 +109,16 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
private final BackKeyBehaviorDelegate mBackKeyBehavior;
private final WindowAndroid mWindowAndroid;
private String mOriginalUrl = "";
private Animator mUrlFocusChangeAnimator;
private final ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners =
new ObserverList<>();
private final Rect mRootViewBounds = new Rect();
private boolean mNativeInitialized;
private boolean mUrlFocusedFromFakebox;
private boolean mUrlFocusedFromQueryTiles;
private boolean mUrlFocusedWithoutAnimations;
private final boolean mIsTablet;
/*package */ LocationBarMediator(@NonNull Context context,
@NonNull LocationBarLayout locationBarLayout,
......@@ -98,8 +128,8 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
@NonNull OverrideUrlLoadingDelegate overrideUrlLoadingDelegate,
@NonNull LocaleManager localeManager,
@NonNull OneshotSupplier<TemplateUrlService> templateUrlServiceSupplier,
@NonNull BackKeyBehaviorDelegate backKeyBehavior,
@NonNull WindowAndroid windowAndroid) {
@NonNull BackKeyBehaviorDelegate backKeyBehavior, @NonNull WindowAndroid windowAndroid,
boolean isTablet) {
mContext = context;
mLocationBarLayout = locationBarLayout;
mLocationBarDataProvider = locationBarDataProvider;
......@@ -114,6 +144,7 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
mTemplateUrlServiceSupplier = templateUrlServiceSupplier;
mBackKeyBehavior = backKeyBehavior;
mWindowAndroid = windowAndroid;
mIsTablet = isTablet;
}
/**
......@@ -129,6 +160,7 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
mUrlCoordinator = urlCoordinator;
mAutocompleteCoordinator = autocompleteCoordinator;
mStatusCoordinator = statusCoordinator;
updateShouldAnimateIconChanges();
}
/*package */ void destroy() {
......@@ -147,13 +179,45 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
if (templateUrlService != null) {
templateUrlService.removeObserver(this);
}
mUrlFocusChangeListeners.clear();
}
/*package */ void onUrlFocusChange(boolean hasFocus) {
mLocationBarLayout.onUrlFocusChange(hasFocus);
setUrlFocusChangeInProgress(true);
mLocationBarLayout.setUrlHasFocus(hasFocus);
updateButtonVisibility();
updateShouldAnimateIconChanges();
onPrimaryColorChanged();
mLocationBarLayout.updateStatusVisibility();
// Focus change caused by a closed tab may result in there not being an active tab.
if (hasFocus) {
if (mNativeInitialized) RecordUserAction.record("FocusLocation");
UrlBarData urlBarData = mLocationBarDataProvider.getUrlBarData();
if (urlBarData.editingText != null) {
setUrlBarText(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
}
} else {
mUrlFocusedFromFakebox = false;
mUrlFocusedFromQueryTiles = false;
mUrlFocusedWithoutAnimations = false;
}
mStatusCoordinator.onUrlFocusChange(hasFocus);
if (!mUrlFocusedWithoutAnimations) handleUrlFocusAnimation(hasFocus);
if (hasFocus && mLocationBarDataProvider.hasTab()
&& !mLocationBarDataProvider.isIncognito()) {
if (mNativeInitialized
&& mTemplateUrlServiceSupplier.get().isDefaultSearchEngineGoogle()) {
GeolocationHeader.primeLocationForGeoHeader();
} else {
mDeferredNativeRunnables.add(() -> {
if (mTemplateUrlServiceSupplier.get().isDefaultSearchEngineGoogle()) {
GeolocationHeader.primeLocationForGeoHeader();
}
});
}
} // Focus change caused by a closed tab may result in there not being an active tab.
if (!hasFocus && mLocationBarDataProvider.hasTab()) {
setUrl(mLocationBarDataProvider.getCurrentUrl(),
mLocationBarDataProvider.getUrlBarData());
......@@ -204,6 +268,11 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
return mAssistantVoiceSearchServiceSupplier;
}
/* package */ void setIsUrlBarFocusedWithoutAnimationsForTesting(
boolean isUrlBarFocusedWithoutAnimations) {
mUrlFocusedWithoutAnimations = isUrlBarFocusedWithoutAnimations;
}
/*package */ void updateVisualsForState() {
onPrimaryColorChanged();
}
......@@ -213,11 +282,11 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
}
/*package */ void showUrlBarCursorWithoutFocusAnimations() {
if (mLocationBarLayout.isUrlBarFocused() || mLocationBarLayout.didFocusUrlFromFakebox()) {
if (mLocationBarLayout.isUrlBarFocused() || mUrlFocusedFromFakebox) {
return;
}
mLocationBarLayout.setIsUrlFocusedWithoutAnimations(true);
mUrlFocusedWithoutAnimations = true;
// This method should only be called on devices with a hardware keyboard attached, as
// described in the documentation for LocationBar#showUrlBarCursorWithoutFocusAnimations.
setUrlBarFocus(/*shouldBeFocused=*/true, /*pastedText=*/null,
......@@ -229,10 +298,10 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
String currentUrl = mLocationBarDataProvider.getCurrentUrl();
if (NativePageFactory.isNativePageUrl(
currentUrl, mLocationBarDataProvider.isIncognito())) {
mLocationBarLayout.setUrlBarTextEmpty();
setUrlBarTextEmpty();
} else {
mLocationBarLayout.setUrlBarText(mLocationBarDataProvider.getUrlBarData(),
UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
setUrlBarText(mLocationBarDataProvider.getUrlBarData(), UrlBar.ScrollType.NO_SCROLL,
SelectionState.SELECT_ALL);
}
mUrlCoordinator.setKeyboardVisibility(false, false);
} else {
......@@ -256,9 +325,8 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
// Handle the case where suggestions (in particular zero suggest) are received without the
// URL focusing happening.
if (mLocationBarLayout.isUrlBarFocusedWithoutAnimations()
&& mLocationBarLayout.isUrlBarFocused()) {
mLocationBarLayout.handleUrlFocusAnimation(/*hasFocus=*/true);
if (mUrlFocusedWithoutAnimations && mLocationBarLayout.isUrlBarFocused()) {
handleUrlFocusAnimation(/*hasFocus=*/true);
}
if (mNativeInitialized
......@@ -337,11 +405,11 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
}
/* package */ boolean didFocusUrlFromFakebox() {
return mLocationBarLayout.didFocusUrlFromFakebox();
return mUrlFocusedFromFakebox;
}
/* package */ boolean didFocusUrlFromQueryTiles() {
return mLocationBarLayout.didFocusUrlFromQueryTiles();
return mUrlFocusedFromQueryTiles;
}
/** Updates the visibility of the buttons inside the location bar. */
......@@ -369,8 +437,7 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
// If the URL is currently focused, do not replace the text they have entered with the URL.
// Once they stop editing the URL, the current tab's URL will automatically be filled in.
if (mUrlCoordinator.hasFocus()) {
if (mLocationBarLayout.isUrlBarFocusedWithoutAnimations()
&& !UrlUtilities.isNTPUrl(currentUrlString)) {
if (mUrlFocusedWithoutAnimations && !UrlUtilities.isNTPUrl(currentUrlString)) {
// If we did not run the focus animations, then the user has not typed any text.
// So, clear the focus and accept whatever URL the page is currently attempting to
// display. If the NTP is showing, the current page's URL should not be displayed.
......@@ -381,14 +448,13 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
}
mOriginalUrl = currentUrlString;
mLocationBarLayout.setUrlBarText(
urlBarData, UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
setUrlBarText(urlBarData, UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
}
/* package */ void deleteButtonClicked(View view) {
if (!mNativeInitialized) return;
RecordUserAction.record("MobileOmniboxDeleteUrl");
mLocationBarLayout.setUrlBarTextEmpty();
setUrlBarTextEmpty();
updateButtonVisibility();
}
......@@ -400,7 +466,133 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
}
/* package */ void setUrlFocusChangeInProgress(boolean inProgress) {
if (mUrlCoordinator == null) return;
mLocationBarLayout.setUrlFocusChangeInProgress(inProgress);
if (!inProgress) {
updateButtonVisibility();
// The accessibility bounding box is not properly updated when focusing the Omnibox
// from the NTP fakebox. Clearing/re-requesting focus triggers the bounding box to
// be recalculated.
if (didFocusUrlFromFakebox() && mLocationBarLayout.isUrlBarFocused()
&& ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
String existingText = mUrlCoordinator.getTextWithoutAutocomplete();
mUrlCoordinator.clearFocus();
mUrlCoordinator.requestFocus();
// Existing text (e.g. if the user pasted via the fakebox) from the fake box
// should be restored after toggling the focus.
if (!TextUtils.isEmpty(existingText)) {
mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(existingText),
UrlBar.ScrollType.NO_SCROLL,
UrlBarCoordinator.SelectionState.SELECT_END);
forceOnTextChanged();
}
}
for (UrlFocusChangeListener listener : mUrlFocusChangeListeners) {
listener.onUrlAnimationFinished(mLocationBarLayout.isUrlBarFocused());
}
}
}
/**
* Handles any actions to be performed after all other actions triggered by the URL focus
* change. This will be called after any animations are performed to transition from one
* focus state to the other.
* @param hasFocus Whether the URL field has gained focus.
* @param shouldShowKeyboard Whether the keyboard should be shown. This value should be the same
* as hasFocus by default.
*/
/* package */ void finishUrlFocusChange(boolean hasFocus, boolean shouldShowKeyboard) {
if (mUrlCoordinator == null) return;
mUrlCoordinator.setKeyboardVisibility(hasFocus && shouldShowKeyboard, true);
setUrlFocusChangeInProgress(false);
updateShouldAnimateIconChanges();
mStatusCoordinator.onUrlAnimationFinished(hasFocus);
if (!mIsTablet && !hasFocus) {
mLocationBarLayout.setUrlActionContainerVisibility(View.GONE);
}
}
/**
* Handle and run any necessary animations that are triggered off focusing the UrlBar.
* @param hasFocus Whether focus was gained.
*/
@VisibleForTesting
/* package */ void handleUrlFocusAnimation(boolean hasFocus) {
if (hasFocus) {
mUrlFocusedWithoutAnimations = false;
}
for (UrlFocusChangeListener listener : mUrlFocusChangeListeners) {
listener.onUrlFocusChange(hasFocus);
}
// The focus animation for phones is driven by ToolbarPhone, so we don't currently have any
// phone-specific animation logic in this class.
if (mIsTablet) {
if (mUrlFocusChangeAnimator != null && mUrlFocusChangeAnimator.isRunning()) {
mUrlFocusChangeAnimator.cancel();
mUrlFocusChangeAnimator = null;
}
if (mLocationBarDataProvider.getNewTabPageDelegate().isCurrentlyVisible()) {
finishUrlFocusChange(hasFocus, /* shouldShowKeyboard= */ hasFocus);
return;
}
mLocationBarLayout.getRootView().getLocalVisibleRect(mRootViewBounds);
float screenSizeRatio = (mRootViewBounds.height()
/ (float) (Math.max(mRootViewBounds.height(), mRootViewBounds.width())));
mUrlFocusChangeAnimator = ObjectAnimator.ofFloat(
this, mUrlFocusChangeFractionProperty, hasFocus ? 1f : 0f);
mUrlFocusChangeAnimator.setDuration(
(long) (MAX_NTP_KEYBOARD_FOCUS_DURATION_MS * screenSizeRatio));
mUrlFocusChangeAnimator.addListener(new CancelAwareAnimatorListener() {
@Override
public void onEnd(Animator animator) {
finishUrlFocusChange(hasFocus, /* shouldShowKeyboard= */ hasFocus);
}
@Override
public void onCancel(Animator animator) {
setUrlFocusChangeInProgress(false);
}
});
mUrlFocusChangeAnimator.start();
}
}
/**
* Changes the text on the url bar. The text update will be applied regardless of the current
* focus state (comparing to {@link LocationBarMediator#setUrl} which only applies text updates
* when not focused).
*
* @param urlBarData The contents of the URL bar, both for editing and displaying.
* @param scrollType Specifies how the text should be scrolled in the unfocused state.
* @param selectionState Specifies how the text should be selected in the focused state.
* @return Whether the URL was changed as a result of this call.
*/
/* package */ boolean setUrlBarText(UrlBarData urlBarData, @UrlBar.ScrollType int scrollType,
@SelectionState int selectionState) {
return mUrlCoordinator.setUrlBarData(urlBarData, scrollType, selectionState);
}
/**
* Clear any text in the URL bar.
* @return Whether this changed the existing text.
*/
/* package */ boolean setUrlBarTextEmpty() {
boolean textChanged = mUrlCoordinator.setUrlBarData(
UrlBarData.EMPTY, UrlBar.ScrollType.SCROLL_TO_BEGINNING, SelectionState.SELECT_ALL);
forceOnTextChanged();
return textChanged;
}
/* package */ void forceOnTextChanged() {
String textWithoutAutocomplete = mUrlCoordinator.getTextWithoutAutocomplete();
String textWithAutocomplete = mUrlCoordinator.getTextWithAutocomplete();
mAutocompleteCoordinator.onTextChanged(textWithoutAutocomplete, textWithAutocomplete);
}
// Private methods
......@@ -470,6 +662,13 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
}
}
private void updateShouldAnimateIconChanges() {
boolean shouldAnimate = mIsTablet
? isUrlBarFocused()
: isUrlBarFocused() || mLocationBarLayout.isUrlFocusChangeInProgress();
mStatusCoordinator.setShouldAnimateIconChanges(shouldAnimate);
}
private void recordOmniboxFocusReason(@OmniboxFocusReason int reason) {
RecordHistogram.recordEnumeratedHistogram(
"Android.OmniboxFocusReason", reason, OmniboxFocusReason.NUM_ENTRIES);
......@@ -526,16 +725,16 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
|| reason == OmniboxFocusReason.FAKE_BOX_LONG_PRESS
|| reason == OmniboxFocusReason.TASKS_SURFACE_FAKE_BOX_LONG_PRESS
|| reason == OmniboxFocusReason.TASKS_SURFACE_FAKE_BOX_TAP) {
mLocationBarLayout.setUrlFocusedFromFakebox(true);
mUrlFocusedFromFakebox = true;
}
if (reason == OmniboxFocusReason.QUERY_TILES_NTP_TAP) {
mLocationBarLayout.setUrlFocusedFromFakebox(true);
mLocationBarLayout.setUrlFocusedFromQueryTiles(true);
mUrlFocusedFromFakebox = true;
mUrlFocusedFromQueryTiles = true;
}
if (urlHasFocus && mLocationBarLayout.isUrlBarFocusedWithoutAnimations()) {
mLocationBarLayout.handleUrlFocusAnimation(true);
if (urlHasFocus && mUrlFocusedWithoutAnimations) {
handleUrlFocusAnimation(true);
} else {
mUrlCoordinator.requestFocus();
}
......@@ -548,7 +747,7 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
// This must be happen after requestUrlFocus(), which changes the selection.
mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(pastedText),
UrlBar.ScrollType.NO_SCROLL, UrlBarCoordinator.SelectionState.SELECT_END);
mLocationBarLayout.forceOnTextChanged();
forceOnTextChanged();
}
}
......@@ -578,12 +777,12 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
@Override
public void addUrlFocusChangeListener(UrlFocusChangeListener listener) {
mLocationBarLayout.addUrlFocusChangeListener(listener);
mUrlFocusChangeListeners.addObserver(listener);
}
@Override
public void removeUrlFocusChangeListener(UrlFocusChangeListener listener) {
mLocationBarLayout.removeUrlFocusChangeListener(listener);
mUrlFocusChangeListeners.removeObserver(listener);
}
@Override
......@@ -630,8 +829,8 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
// autocomplete text will be updated but the visible text will not.
setUrlBarFocus(
/*shouldBeFocused=*/true, /*pastedText=*/null, OmniboxFocusReason.SEARCH_QUERY);
mLocationBarLayout.setUrlBarText(UrlBarData.forNonUrlText(query),
UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
setUrlBarText(UrlBarData.forNonUrlText(query), UrlBar.ScrollType.NO_SCROLL,
SelectionState.SELECT_ALL);
mAutocompleteCoordinator.startAutocompleteForQuery(query);
mUrlCoordinator.setKeyboardVisibility(true, false);
}
......@@ -689,11 +888,10 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
public boolean onKey(View view, int keyCode, KeyEvent event) {
boolean result = handleKeyEvent(view, keyCode, event);
if (result && mLocationBarLayout.isUrlBarFocused()
&& mLocationBarLayout.isUrlBarFocusedWithoutAnimations()
if (result && mLocationBarLayout.isUrlBarFocused() && mUrlFocusedWithoutAnimations
&& event.getAction() == KeyEvent.ACTION_DOWN && event.isPrintingKey()
&& event.hasNoModifiers()) {
mLocationBarLayout.handleUrlFocusAnimation(/*hasFocus=*/true);
handleUrlFocusAnimation(/*hasFocus=*/true);
}
return result;
......@@ -735,8 +933,7 @@ class LocationBarMediator implements LocationBarDataProvider.Observer, FakeboxDe
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mLocationBarLayout.isUrlBarFocused()
&& mLocationBarLayout.isUrlBarFocusedWithoutAnimations()
if (mLocationBarLayout.isUrlBarFocused() && mUrlFocusedWithoutAnimations
&& newConfig.keyboard != Configuration.KEYBOARD_QWERTY) {
// If we lose the hardware keyboard and the focus animations were not run, then the
// user has not typed any text, so we will just clear the focus instead.
......
......@@ -109,19 +109,6 @@ class LocationBarPhone extends LocationBarLayout {
mStatusCoordinator.setUrlFocusChangePercent(fraction);
}
@Override
public void onUrlFocusChange(boolean hasFocus) {
if (hasFocus) {
// Remove the focus of this view once the URL field has taken focus as this view no
// longer needs it.
setFocusable(false);
setFocusableInTouchMode(false);
}
setUrlFocusChangeInProgress(true);
updateShouldAnimateIconChanges();
super.onUrlFocusChange(hasFocus);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean needsCanvasRestore = false;
......@@ -146,26 +133,12 @@ class LocationBarPhone extends LocationBarLayout {
return retVal;
}
@Override
public void finishUrlFocusChange(boolean hasFocus, boolean shouldShowKeyboard) {
super.finishUrlFocusChange(hasFocus, shouldShowKeyboard);
if (!hasFocus) {
mUrlActionContainer.setVisibility(GONE);
}
mStatusCoordinator.onUrlAnimationFinished(hasFocus);
}
@Override
protected void updateButtonVisibility() {
super.updateButtonVisibility();
updateMicButtonVisibility();
}
@Override
public void updateShouldAnimateIconChanges() {
notifyShouldAnimateIconChanges(isUrlBarFocused() || isUrlFocusChangeInProgress());
}
@Override
public void setShowIconsWhenUrlFocused(boolean showIcon) {
super.setShowIconsWhenUrlFocused(showIcon);
......
......@@ -22,7 +22,6 @@ import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.top.ToolbarTablet;
import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.interpolators.BakedBezierInterpolator;
......@@ -33,26 +32,11 @@ import java.util.List;
* Location bar for tablet form factors.
*/
class LocationBarTablet extends LocationBarLayout {
private static final long MAX_NTP_KEYBOARD_FOCUS_DURATION_MS = 200;
private static final int ICON_FADE_ANIMATION_DURATION_MS = 150;
private static final int ICON_FADE_ANIMATION_DELAY_MS = 75;
private static final int WIDTH_CHANGE_ANIMATION_DURATION_MS = 225;
private static final int WIDTH_CHANGE_ANIMATION_DELAY_MS = 75;
private final Property<LocationBarTablet, Float> mUrlFocusChangeFractionProperty =
new Property<LocationBarTablet, Float>(Float.class, "") {
@Override
public Float get(LocationBarTablet object) {
return object.mUrlFocusChangeFraction;
}
@Override
public void set(LocationBarTablet object, Float value) {
setUrlFocusChangeFraction(value);
}
};
private final Property<LocationBarTablet, Float> mWidthChangeFractionProperty =
new Property<LocationBarTablet, Float>(Float.class, "") {
@Override
......@@ -69,7 +53,6 @@ class LocationBarTablet extends LocationBarLayout {
private View mLocationBarIcon;
private View mBookmarkButton;
private View mSaveOfflineButton;
private Animator mUrlFocusChangeAnimator;
private View[] mTargets;
private final Rect mCachedTargetBounds = new Rect();
......@@ -155,43 +138,6 @@ class LocationBarTablet extends LocationBarLayout {
return selectedTarget.onTouchEvent(event);
}
@Override
public void handleUrlFocusAnimation(final boolean hasFocus) {
super.handleUrlFocusAnimation(hasFocus);
if (mUrlFocusChangeAnimator != null && mUrlFocusChangeAnimator.isRunning()) {
mUrlFocusChangeAnimator.cancel();
mUrlFocusChangeAnimator = null;
}
if (mLocationBarDataProvider.getNewTabPageDelegate().isCurrentlyVisible()) {
finishUrlFocusChange(hasFocus, /* shouldShowKeyboard= */ hasFocus);
return;
}
Rect rootViewBounds = new Rect();
getRootView().getLocalVisibleRect(rootViewBounds);
float screenSizeRatio = (rootViewBounds.height()
/ (float) (Math.max(rootViewBounds.height(), rootViewBounds.width())));
mUrlFocusChangeAnimator =
ObjectAnimator.ofFloat(this, mUrlFocusChangeFractionProperty, hasFocus ? 1f : 0f);
mUrlFocusChangeAnimator.setDuration(
(long) (MAX_NTP_KEYBOARD_FOCUS_DURATION_MS * screenSizeRatio));
mUrlFocusChangeAnimator.addListener(new CancelAwareAnimatorListener() {
@Override
public void onEnd(Animator animator) {
finishUrlFocusChange(hasFocus, /* shouldShowKeyboard= */ hasFocus);
}
@Override
public void onCancel(Animator animator) {
setUrlFocusChangeInProgress(false);
}
});
setUrlFocusChangeInProgress(true);
mUrlFocusChangeAnimator.start();
}
/**
* Updates progress of current the URL focus change animation.
*
......
......@@ -4,9 +4,11 @@
package org.chromium.chrome.browser.omnibox;
import android.content.Context;
import android.text.TextWatcher;
import android.view.ActionMode;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
......@@ -50,6 +52,7 @@ public class UrlBarCoordinator implements UrlBarEditingTextStateProvider, UrlFoc
private WindowDelegate mWindowDelegate;
private Runnable mKeyboardResizeModeTask = NO_OP_RUNNABLE;
private Runnable mKeyboardHideTask = NO_OP_RUNNABLE;
private Callback<Boolean> mFocusChangeCallback;
/**
* Constructs a coordinator for the given UrlBar view.
......@@ -71,6 +74,7 @@ public class UrlBarCoordinator implements UrlBarEditingTextStateProvider, UrlFoc
mUrlBar = urlBar;
mKeyboardVisibilityDelegate = keyboardVisibilityDelegate;
mWindowDelegate = windowDelegate;
mFocusChangeCallback = focusChangeCallback;
PropertyModel model =
new PropertyModel.Builder(UrlBarProperties.ALL_KEYS)
......@@ -80,7 +84,7 @@ public class UrlBarCoordinator implements UrlBarEditingTextStateProvider, UrlFoc
.build();
PropertyModelChangeProcessor.create(model, urlBar, UrlBarViewBinder::bind);
mMediator = new UrlBarMediator(model, focusChangeCallback);
mMediator = new UrlBarMediator(model, this::onUrlFocusChangeInternal);
}
public void destroy() {
......@@ -90,6 +94,7 @@ public class UrlBarCoordinator implements UrlBarEditingTextStateProvider, UrlFoc
mUrlBar.removeCallbacks(mKeyboardHideTask);
mUrlBar.destroy();
mUrlBar = null;
mFocusChangeCallback = null;
}
/** @see UrlBarMediator#addUrlTextChangeListener(UrlTextChangeListener) */
......@@ -235,4 +240,25 @@ public class UrlBarCoordinator implements UrlBarEditingTextStateProvider, UrlFoc
mWindowDelegate.setWindowSoftInputMode(softInputMode);
}
}
private void onUrlFocusChangeInternal(boolean hasFocus) {
InputMethodManager imm = (InputMethodManager) mUrlBar.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
if (hasFocus) {
// Explicitly tell InputMethodManager that the url bar is focused before any callbacks
// so that it updates the active view accordingly. Otherwise, it may fail to update
// the correct active view if ViewGroup.addView() or ViewGroup.removeView() is called
// to update a view that accepts text input.
imm.viewClicked(mUrlBar);
} else {
// Moving focus away from UrlBar(EditText) to a non-editable focus holder, such as
// ToolbarPhone, won't automatically hide keyboard app, but restart it with TYPE_NULL,
// which will result in a visual glitch. Also, currently, we do not allow moving focus
// directly from omnibox to web content's form field. Therefore, we hide keyboard on
// focus blur indiscriminately here. Note that hiding keyboard may lower FPS of other
// animation effects, but we found it tolerable in an experiment.
if (imm.isActive(mUrlBar)) setKeyboardVisibility(false, false);
}
mFocusChangeCallback.onResult(hasFocus);
}
}
......@@ -286,9 +286,7 @@ class StatusMediator implements IncognitoStateProvider.IncognitoStateObserver {
// focused, but hide it when unfocused.
void setUrlAnimationFinished(boolean urlHasFocus) {
// On tablets, the status icon should always be shown so the following logic doesn't apply.
assert !mIsTablet : "This logic shouldn't be called on tablets";
if (!mDelegate.shouldShowSearchEngineLogo(mIsIncognito)) {
if (mIsTablet || !mDelegate.shouldShowSearchEngineLogo(mIsIncognito)) {
return;
}
......
......@@ -2137,8 +2137,7 @@ public class ToolbarPhone extends ToolbarLayout implements OnClickListener, TabC
mLayoutLocationBarInFocusedMode = false;
requestLayout();
}
mLocationBar.getPhoneCoordinator().finishUrlFocusChange(hasFocus,
shouldShowKeyboard,
mLocationBar.finishUrlFocusChange(hasFocus, shouldShowKeyboard,
getToolbarDataProvider().shouldShowLocationBarInOverviewMode());
mUrlFocusChangeInProgress = false;
}
......
......@@ -505,7 +505,7 @@ public class LocationBarLayoutTest {
true, SEARCH_TERMS_URL, OmniboxFocusReason.FAKE_BOX_LONG_PRESS);
});
Assert.assertTrue(locationBar.isUrlBarFocused());
Assert.assertTrue(locationBar.didFocusUrlFromFakebox());
Assert.assertTrue(getLocationBarMediator().didFocusUrlFromFakebox());
Assert.assertEquals(SEARCH_TERMS_URL, getUrlText(getUrlBar()));
Assert.assertEquals(
1, RecordHistogram.getHistogramTotalCountForTesting("Android.OmniboxFocusReason"));
......@@ -514,7 +514,7 @@ public class LocationBarLayoutTest {
locationBarMediator.setUrlBarFocus(true, SEARCH_TERMS, OmniboxFocusReason.SEARCH_QUERY);
});
Assert.assertTrue(locationBar.isUrlBarFocused());
Assert.assertTrue(locationBar.didFocusUrlFromFakebox());
Assert.assertTrue(getLocationBarMediator().didFocusUrlFromFakebox());
Assert.assertEquals(SEARCH_TERMS, getUrlText(getUrlBar()));
Assert.assertEquals(
1, RecordHistogram.getHistogramTotalCountForTesting("Android.OmniboxFocusReason"));
......@@ -523,7 +523,7 @@ public class LocationBarLayoutTest {
locationBarMediator.setUrlBarFocus(false, null, OmniboxFocusReason.UNFOCUS);
});
Assert.assertFalse(locationBar.isUrlBarFocused());
Assert.assertFalse(locationBar.didFocusUrlFromFakebox());
Assert.assertFalse(getLocationBarMediator().didFocusUrlFromFakebox());
Assert.assertEquals(
1, RecordHistogram.getHistogramTotalCountForTesting("Android.OmniboxFocusReason"));
......@@ -531,7 +531,7 @@ public class LocationBarLayoutTest {
locationBarMediator.setUrlBarFocus(true, null, OmniboxFocusReason.OMNIBOX_TAP);
});
Assert.assertTrue(locationBar.isUrlBarFocused());
Assert.assertFalse(locationBar.didFocusUrlFromFakebox());
Assert.assertFalse(getLocationBarMediator().didFocusUrlFromFakebox());
Assert.assertEquals(
2, RecordHistogram.getHistogramTotalCountForTesting("Android.OmniboxFocusReason"));
}
......
......@@ -4,11 +4,19 @@
package org.chromium.chrome.browser.omnibox;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.CoreMatchers.allOf;
import static org.mockito.Mockito.doReturn;
import android.content.Intent;
import android.content.res.Configuration;
import androidx.lifecycle.Lifecycle;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.filters.MediumTest;
import org.junit.After;
......@@ -23,9 +31,8 @@ import org.mockito.junit.MockitoRule;
import org.chromium.base.CommandLine;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.Matchers;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.ChromeActivity;
......@@ -36,11 +43,14 @@ import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.OmniboxTestUtils;
import org.chromium.chrome.test.util.ViewUtils;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.search_engines.TemplateUrl;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.common.ContentSwitches;
import org.chromium.ui.test.util.UiRestriction;
import java.util.Arrays;
import java.util.List;
......@@ -147,11 +157,7 @@ public class LocationBarTest {
Assert.assertTrue(mLocationBarMediator.isUrlBarFocused());
});
CriteriaHelper.pollUiThread(() -> {
Criteria.checkThat(
mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(mActivity, mUrlBar),
Matchers.is(true));
});
OmniboxTestUtils.waitForFocusAndKeyboardActive(mUrlBar, true);
}
@Test
......@@ -168,11 +174,7 @@ public class LocationBarTest {
Assert.assertTrue(mLocationBarMediator.isUrlBarFocused());
});
CriteriaHelper.pollUiThread(() -> {
Criteria.checkThat(
mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(mActivity, mUrlBar),
Matchers.is(true));
});
OmniboxTestUtils.waitForFocusAndKeyboardActive(mUrlBar, true);
}
@Test
......@@ -254,12 +256,16 @@ public class LocationBarTest {
@MediumTest
public void testPostDestroyFocusLogic() {
startActivityNormally();
TestThreadUtils.runOnUiThreadBlocking(() -> {
LocationBarLayout locationBarLayout =
mActivity.findViewById(org.chromium.chrome.R.id.location_bar);
locationBarLayout.destroy();
locationBarLayout.finishUrlFocusChange(true, true);
TestThreadUtils.runOnUiThreadBlocking(() -> { mActivity.finish(); });
CriteriaHelper.pollUiThread(
() -> mActivity.getLifecycle().getCurrentState().equals(Lifecycle.State.DESTROYED));
TestThreadUtils.runOnUiThreadBlocking(() -> {
locationBarLayout.setUrlFocusChangeInProgress(false);
mLocationBarMediator.finishUrlFocusChange(true, true);
});
}
......@@ -281,4 +287,100 @@ public class LocationBarTest {
Assert.assertEquals(url.length(), mUrlBar.getSelectionEnd());
});
}
@Test
@MediumTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
public void testFocusLogic_buttonVisibilityPhone() {
startActivityNormally();
String url = mActivityTestRule.getEmbeddedTestServerRule().getServer().getURLWithHostName(
HOSTNAME, "/");
mActivityTestRule.loadUrl(url);
onView(withId(R.id.url_action_container))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.requestFocus(); });
ViewUtils.waitForView(allOf(withId(R.id.url_action_container),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
TestThreadUtils.runOnUiThreadBlocking(
() -> { mLocationBarCoordinator.setOmniboxEditingText(url); });
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.clearFocus(); });
ViewUtils.waitForView(allOf(withId(R.id.url_action_container),
withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
}
@Test
@MediumTest
@Restriction(UiRestriction.RESTRICTION_TYPE_TABLET)
public void testFocusLogic_buttonVisibilityTablet() {
startActivityNormally();
String url = mActivityTestRule.getEmbeddedTestServerRule().getServer().getURLWithHostName(
HOSTNAME, "/");
mActivityTestRule.loadUrl(url);
onView(withId(R.id.url_action_container))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.bookmark_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.save_offline_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.requestFocus(); });
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
TestThreadUtils.runOnUiThreadBlocking(
() -> { mLocationBarCoordinator.setOmniboxEditingText(url); });
onView(withId(R.id.mic_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
onView(withId(R.id.delete_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.clearFocus(); });
mLocationBarCoordinator.getTabletCoordinator().setShouldShowButtonsWhenUnfocused(false);
onView(withId(R.id.bookmark_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
onView(withId(R.id.save_offline_button))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
}
@Test
@MediumTest
public void testFocusLogic_keyboardVisibility() {
startActivityNormally();
OmniboxTestUtils.waitForFocusAndKeyboardActive(mUrlBar, false);
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.requestFocus(); });
OmniboxTestUtils.waitForFocusAndKeyboardActive(mUrlBar, true);
TestThreadUtils.runOnUiThreadBlocking(() -> { mUrlBar.clearFocus(); });
OmniboxTestUtils.waitForFocusAndKeyboardActive(mUrlBar, false);
}
}
include_rules = [
"+chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar",
]
......@@ -17,15 +17,20 @@ import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.Property;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
......@@ -54,8 +59,10 @@ import org.chromium.base.supplier.OneshotSupplierImpl;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.gsa.GSAState;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
import org.chromium.chrome.browser.omnibox.voice.AssistantVoiceSearchService;
......@@ -63,6 +70,8 @@ import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImp
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileJni;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.NewTabPageDelegate;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.embedder_support.util.UrlUtilities;
......@@ -78,7 +87,10 @@ import java.util.List;
/** Unit tests for LocationBarMediator. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(shadows = {LocationBarMediatorTest.ShadowUrlUtilities.class})
@Config(shadows = {LocationBarMediatorTest.ShadowUrlUtilities.class,
LocationBarMediatorTest.ShadowGeolocationHeader.class,
LocationBarMediatorTest.ObjectAnimatorShadow.class,
LocationBarMediatorTest.GSAStateShadow.class})
@Features.EnableFeatures(ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH)
public class LocationBarMediatorTest {
@Implements(UrlUtilities.class)
......@@ -89,8 +101,45 @@ public class LocationBarMediatorTest {
}
}
@Implements(GeolocationHeader.class)
static class ShadowGeolocationHeader {
@Implementation
public static void primeLocationForGeoHeader() {
sGeoHeaderPrimeCount++;
}
}
@Implements(ObjectAnimator.class)
static class ObjectAnimatorShadow {
private static ObjectAnimator sUrlAnimator;
@Implementation
public static <T> ObjectAnimator ofFloat(
T target, Property<T, Float> property, float... values) {
return sUrlAnimator;
}
static void setUrlAnimator(ObjectAnimator objectAnimator) {
sUrlAnimator = objectAnimator;
}
}
@Implements(GSAState.class)
static class GSAStateShadow {
private static GSAState sGSAState;
@Implementation
public static GSAState getInstance(Context context) {
return sGSAState;
}
static void setGSAState(GSAState gsaState) {
sGSAState = gsaState;
}
}
private static final String TEST_URL = "http://www.example.org";
private static int sGeoHeaderPrimeCount;
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
......@@ -142,6 +191,12 @@ public class LocationBarMediatorTest {
private BackKeyBehaviorDelegate mOverrideBackKeyBehaviorDelegate;
@Mock
private WindowAndroid mWindowAndroid;
@Mock
private ObjectAnimator mUrlAnimator;
@Mock
private View mRootView;
@Mock
private GSAState mGSAState;
@Captor
private ArgumentCaptor<Runnable> mRunnableCaptor;
......@@ -154,15 +209,18 @@ public class LocationBarMediatorTest {
@Before
public void setUp() {
doReturn(mTemplateUrlService).when(mTemplateUrlServiceSupplier).get();
doReturn(mRootView).when(mLocationBarLayout).getRootView();
mJniMocker.mock(ProfileJni.TEST_HOOKS, mProfileNativesJniMock);
mJniMocker.mock(OmniboxPrerenderJni.TEST_HOOKS, mPrerenderJni);
SearchEngineLogoUtils.setDelegateForTesting(mSearchEngineDelegate);
mMediator = new LocationBarMediator(/* context= */ RuntimeEnvironment.application,
mLocationBarLayout, mLocationBarDataProvider, mProfileSupplier,
mPrivacyPreferencesManager, mOverrideUrlLoadingDelegate, mLocaleManager,
mTemplateUrlServiceSupplier, mOverrideBackKeyBehaviorDelegate, mWindowAndroid);
mTemplateUrlServiceSupplier, mOverrideBackKeyBehaviorDelegate, mWindowAndroid,
false);
mMediator.setCoordinators(mUrlCoordinator, mAutocompleteCoordinator, mStatusCoordinator);
SearchEngineLogoUtils.setDelegateForTesting(mSearchEngineDelegate);
ObjectAnimatorShadow.setUrlAnimator(mUrlAnimator);
GSAStateShadow.setGSAState(mGSAState);
}
@Test
......@@ -197,8 +255,8 @@ public class LocationBarMediatorTest {
UrlBarData urlBarData = mock(UrlBarData.class);
doReturn(urlBarData).when(mLocationBarDataProvider).getUrlBarData();
mMediator.revertChanges();
verify(mLocationBarLayout)
.setUrlBarText(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
verify(mUrlCoordinator)
.setUrlBarData(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
}
@Test
......@@ -206,15 +264,17 @@ public class LocationBarMediatorTest {
doReturn(UrlConstants.NTP_URL).when(mLocationBarDataProvider).getCurrentUrl();
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
mMediator.revertChanges();
verify(mLocationBarLayout).setUrlBarTextEmpty();
verify(mUrlCoordinator)
.setUrlBarData(UrlBarData.EMPTY, UrlBar.ScrollType.SCROLL_TO_BEGINNING,
SelectionState.SELECT_ALL);
}
@Test
public void testRevertChanges_unFocused() {
doReturn("http://url.com").when(mLocationBarDataProvider).getCurrentUrl();
mMediator.revertChanges();
verify(mLocationBarLayout)
.setUrlBarText(mLocationBarDataProvider.getUrlBarData(),
verify(mUrlCoordinator)
.setUrlBarData(mLocationBarDataProvider.getUrlBarData(),
UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
}
......@@ -242,7 +302,7 @@ public class LocationBarMediatorTest {
doReturn(456L).when(mAutocompleteCoordinator).getCurrentNativeAutocompleteResult();
doReturn("text").when(mUrlCoordinator).getTextWithoutAutocomplete();
doReturn(true).when(mUrlCoordinator).shouldAutocomplete();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
mMediator.onSuggestionsChanged("textWithAutocomplete", true);
......@@ -250,7 +310,6 @@ public class LocationBarMediatorTest {
.prerenderMaybe(123L, omniboxPrerenderCaptor.getValue(), "text", "originalUrl",
456L, profile, mTab);
verify(mUrlCoordinator).setAutocompleteText("text", "textWithAutocomplete");
verify(mLocationBarLayout).handleUrlFocusAnimation(true);
}
@Test
......@@ -322,8 +381,8 @@ public class LocationBarMediatorTest {
mMediator.setSearchQuery(query);
verify(mUrlCoordinator).requestFocus();
verify(mLocationBarLayout)
.setUrlBarText(argThat(matchesUrlBarDataForQuery(query)),
verify(mUrlCoordinator)
.setUrlBarData(argThat(matchesUrlBarDataForQuery(query)),
eq(UrlBar.ScrollType.NO_SCROLL), eq(SelectionState.SELECT_ALL));
verify(mAutocompleteCoordinator).startAutocompleteForQuery(query);
verify(mUrlCoordinator).setKeyboardVisibility(true, false);
......@@ -353,8 +412,8 @@ public class LocationBarMediatorTest {
mRunnableCaptor.getValue().run();
verify(mUrlCoordinator).requestFocus();
verify(mLocationBarLayout)
.setUrlBarText(argThat(matchesUrlBarDataForQuery(query)),
verify(mUrlCoordinator)
.setUrlBarData(argThat(matchesUrlBarDataForQuery(query)),
eq(UrlBar.ScrollType.NO_SCROLL), eq(SelectionState.SELECT_ALL));
verify(mAutocompleteCoordinator).startAutocompleteForQuery(query);
verify(mUrlCoordinator).setKeyboardVisibility(true, false);
......@@ -400,8 +459,8 @@ public class LocationBarMediatorTest {
mMediator.performSearchQuery(query, params);
verify(mUrlCoordinator).requestFocus();
verify(mLocationBarLayout)
.setUrlBarText(argThat(matchesUrlBarDataForQuery(query)),
verify(mUrlCoordinator)
.setUrlBarData(argThat(matchesUrlBarDataForQuery(query)),
eq(UrlBar.ScrollType.NO_SCROLL), eq(SelectionState.SELECT_ALL));
verify(mAutocompleteCoordinator).startAutocompleteForQuery(query);
verify(mUrlCoordinator).setKeyboardVisibility(true, false);
......@@ -410,7 +469,7 @@ public class LocationBarMediatorTest {
@Test
public void testOnConfigurationChanged_qwertyKeyboard() {
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
Configuration newConfig = new Configuration();
newConfig.keyboard = Configuration.KEYBOARD_QWERTY;
mMediator.onConfigurationChanged(newConfig);
......@@ -421,7 +480,6 @@ public class LocationBarMediatorTest {
@Test
public void testOnConfigurationChanged_nonQwertyKeyboard() {
doReturn(false).when(mLocationBarLayout).isUrlBarFocused();
doReturn(false).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
Configuration newConfig = new Configuration();
newConfig.keyboard = Configuration.KEYBOARD_NOKEYS;
mMediator.onConfigurationChanged(newConfig);
......@@ -431,7 +489,7 @@ public class LocationBarMediatorTest {
mMediator.onConfigurationChanged(newConfig);
verify(mUrlCoordinator, never()).clearFocus();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
mMediator.onConfigurationChanged(newConfig);
verify(mUrlCoordinator).clearFocus();
}
......@@ -466,8 +524,8 @@ public class LocationBarMediatorTest {
public void testOnKey_escape() {
doReturn(KeyEvent.ACTION_DOWN).when(mKeyEvent).getAction();
assertTrue(mMediator.onKey(mView, KeyEvent.KEYCODE_ESCAPE, mKeyEvent));
verify(mLocationBarLayout)
.setUrlBarText(mLocationBarDataProvider.getUrlBarData(),
verify(mUrlCoordinator)
.setUrlBarData(mLocationBarDataProvider.getUrlBarData(),
UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
}
......@@ -508,15 +566,15 @@ public class LocationBarMediatorTest {
@Test
public void testOnKey_triggersFocusAnimation() {
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
doReturn(KeyEvent.ACTION_DOWN).when(mKeyEvent).getAction();
doReturn(true).when(mAutocompleteCoordinator).handleKeyEvent(KeyEvent.KEYCODE_9, mKeyEvent);
doReturn(true).when(mKeyEvent).isPrintingKey();
doReturn(true).when(mKeyEvent).hasNoModifiers();
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
assertTrue(mMediator.onKey(mView, KeyEvent.KEYCODE_9, mKeyEvent));
verify(mLocationBarLayout).handleUrlFocusAnimation(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
}
@Test
......@@ -597,8 +655,8 @@ public class LocationBarMediatorTest {
mMediator.updateUseDarkColors();
verify(mLocationBarLayout).setDeleteButtonTint(anyObject());
verify(mLocationBarLayout)
.setUrlBarText(
verify(mUrlCoordinator)
.setUrlBarData(
urlBarData, UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
verify(mStatusCoordinator).setUseDarkColors(false);
verify(mAutocompleteCoordinator)
......@@ -611,12 +669,12 @@ public class LocationBarMediatorTest {
UrlBarData urlBarData = UrlBarData.forUrl(url);
mMediator.setUrl(url, urlBarData);
verify(mLocationBarLayout)
.setUrlBarText(
verify(mUrlCoordinator)
.setUrlBarData(
urlBarData, UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
doReturn(true).when(mUrlCoordinator).hasFocus();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
mMediator.setUrl(url, urlBarData);
verify(mUrlCoordinator).clearFocus();
......@@ -625,24 +683,27 @@ public class LocationBarMediatorTest {
@Test
public void testSetUrlBarFocus_focusedFromFakebox() {
mMediator.setUrlBarFocus(true, null, OmniboxFocusReason.FAKE_BOX_TAP);
verify(mLocationBarLayout).setUrlFocusedFromFakebox(true);
assertTrue(mMediator.didFocusUrlFromFakebox());
verify(mUrlCoordinator).requestFocus();
}
@Test
public void testSetUrlBarFocus_focusedFromQueryTiles() {
mMediator.setUrlBarFocus(true, null, OmniboxFocusReason.QUERY_TILES_NTP_TAP);
verify(mLocationBarLayout).setUrlFocusedFromQueryTiles(true);
verify(mLocationBarLayout).setUrlFocusedFromFakebox(true);
assertTrue(mMediator.didFocusUrlFromQueryTiles());
assertTrue(mMediator.didFocusUrlFromFakebox());
verify(mUrlCoordinator).requestFocus();
}
@Test
public void testSetUrlBarFocus_triggersAnimation() {
public void testSetUrlBarFocus_triggersObservers() {
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
doReturn(true).when(mLocationBarLayout).isUrlBarFocusedWithoutAnimations();
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
mMediator.addUrlFocusChangeListener(mAutocompleteCoordinator);
mMediator.setIsUrlBarFocusedWithoutAnimationsForTesting(true);
mMediator.setUrlBarFocus(true, null, OmniboxFocusReason.QUERY_TILES_NTP_TAP);
verify(mLocationBarLayout).handleUrlFocusAnimation(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
verify(mAutocompleteCoordinator).onUrlFocusChange(true);
}
@Test
......@@ -653,12 +714,175 @@ public class LocationBarMediatorTest {
@Test
public void testSetUrlBarFocus_pastedText() {
doReturn("text").when(mUrlCoordinator).getTextWithoutAutocomplete();
doReturn("textWith").when(mUrlCoordinator).getTextWithAutocomplete();
mMediator.setUrlBarFocus(true, "pastedText", OmniboxFocusReason.OMNIBOX_TAP);
verify(mUrlCoordinator)
.setUrlBarData(argThat(matchesUrlBarDataForQuery("pastedText")),
eq(UrlBar.ScrollType.NO_SCROLL),
eq(UrlBarCoordinator.SelectionState.SELECT_END));
verify(mLocationBarLayout).forceOnTextChanged();
verify(mAutocompleteCoordinator).onTextChanged("text", "textWith");
}
@Test
public void testOnUrlFocusChange() {
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
UrlBarData urlBarData = UrlBarData.create(null, "text", 0, 0, "text");
doReturn(urlBarData).when(mLocationBarDataProvider).getUrlBarData();
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
mMediator.onUrlFocusChange(true);
verify(mLocationBarLayout).setUrlHasFocus(true);
verify(mStatusCoordinator).setShouldAnimateIconChanges(true);
verify(mUrlCoordinator)
.setUrlBarData(urlBarData, UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_ALL);
verify(mStatusCoordinator).onUrlFocusChange(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
}
@Test
public void testOnUrlFocusChange_geolocation() {
int primeCount = sGeoHeaderPrimeCount;
mMediator.onFinishNativeInitialization();
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
UrlBarData urlBarData = mock(UrlBarData.class);
doReturn(urlBarData).when(mLocationBarDataProvider).getUrlBarData();
doReturn(true).when(mLocationBarDataProvider).hasTab();
doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
mMediator.onUrlFocusChange(true);
assertEquals(primeCount + 1, sGeoHeaderPrimeCount);
}
@Test
public void testOnUrlFocusChange_geolocationPreNative() {
int primeCount = sGeoHeaderPrimeCount;
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
UrlBarData urlBarData = mock(UrlBarData.class);
doReturn(urlBarData).when(mLocationBarDataProvider).getUrlBarData();
doReturn(true).when(mLocationBarDataProvider).hasTab();
doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
})
.when(mLocationBarLayout)
.post(any());
mMediator.onUrlFocusChange(true);
assertEquals(primeCount, sGeoHeaderPrimeCount);
mMediator.onFinishNativeInitialization();
assertEquals(primeCount + 1, sGeoHeaderPrimeCount);
}
@Test
public void testOnUrlFocusChange_notFocused() {
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
doReturn(true).when(mLocationBarDataProvider).hasTab();
UrlBarData urlBarData = UrlBarData.create(null, "text", 0, 0, "text");
doReturn(urlBarData).when(mLocationBarDataProvider).getUrlBarData();
Mockito.reset(mStatusCoordinator);
mMediator.onUrlFocusChange(false);
verify(mLocationBarLayout).setUrlHasFocus(false);
verify(mStatusCoordinator).setShouldAnimateIconChanges(false);
verify(mStatusCoordinator).onUrlFocusChange(false);
verify(mUrlCoordinator).onUrlFocusChange(false);
verify(mUrlCoordinator)
.setUrlBarData(
urlBarData, UrlBar.ScrollType.SCROLL_TO_TLD, SelectionState.SELECT_ALL);
}
@Test
public void testHandleUrlFocusAnimation_tablet() {
NewTabPageDelegate newTabPageDelegate = mock(NewTabPageDelegate.class);
doReturn(newTabPageDelegate).when(mLocationBarDataProvider).getNewTabPageDelegate();
doAnswer(invocation -> {
((Rect) invocation.getArgument(0)).set(0, 0, 10, 10);
return null;
})
.when(mRootView)
.getLocalVisibleRect(any());
LocationBarMediator tabletMediator =
new LocationBarMediator(RuntimeEnvironment.application, mLocationBarLayout,
mLocationBarDataProvider, mProfileSupplier, mPrivacyPreferencesManager,
mOverrideUrlLoadingDelegate, mLocaleManager, mTemplateUrlServiceSupplier,
mOverrideBackKeyBehaviorDelegate, mWindowAndroid, true);
tabletMediator.setCoordinators(
mUrlCoordinator, mAutocompleteCoordinator, mStatusCoordinator);
tabletMediator.addUrlFocusChangeListener(mUrlCoordinator);
tabletMediator.handleUrlFocusAnimation(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
verify(mUrlAnimator).start();
verify(mUrlAnimator).setDuration(anyLong());
verify(mUrlAnimator).addListener(any());
}
@Test
public void testHandleUrlFocusAnimation_ntp() {
NewTabPageDelegate newTabPageDelegate = mock(NewTabPageDelegate.class);
doReturn(true).when(newTabPageDelegate).isCurrentlyVisible();
doReturn(newTabPageDelegate).when(mLocationBarDataProvider).getNewTabPageDelegate();
LocationBarMediator tabletMediator =
new LocationBarMediator(RuntimeEnvironment.application, mLocationBarLayout,
mLocationBarDataProvider, mProfileSupplier, mPrivacyPreferencesManager,
mOverrideUrlLoadingDelegate, mLocaleManager, mTemplateUrlServiceSupplier,
mOverrideBackKeyBehaviorDelegate, mWindowAndroid, true);
tabletMediator.setCoordinators(
mUrlCoordinator, mAutocompleteCoordinator, mStatusCoordinator);
tabletMediator.addUrlFocusChangeListener(mUrlCoordinator);
tabletMediator.handleUrlFocusAnimation(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
verify(mUrlAnimator, never()).start();
verify(mUrlAnimator, never()).setDuration(anyLong());
verify(mUrlAnimator, never()).addListener(any());
}
@Test
public void testHandleUrlFocusAnimation_phone() {
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
mMediator.handleUrlFocusAnimation(true);
verify(mUrlCoordinator).onUrlFocusChange(true);
verify(mUrlAnimator, never()).start();
verify(mUrlAnimator, never()).setDuration(anyLong());
verify(mUrlAnimator, never()).addListener(any());
}
@Test
public void testSetUrlFocusChangeInProgress() {
mMediator.addUrlFocusChangeListener(mUrlCoordinator);
mMediator.setUrlFocusChangeInProgress(true);
verify(mLocationBarLayout).setUrlFocusChangeInProgress(true);
ChromeAccessibilityUtil.get().setAccessibilityEnabledForTesting(true);
mMediator.setUrlBarFocus(true, null, OmniboxFocusReason.FAKE_BOX_TAP);
doReturn(true).when(mLocationBarLayout).isUrlBarFocused();
doReturn("text").when(mUrlCoordinator).getTextWithoutAutocomplete();
mMediator.setUrlFocusChangeInProgress(false);
verify(mLocationBarLayout).setUrlFocusChangeInProgress(false);
verify(mLocationBarLayout).updateButtonVisibility();
verify(mUrlCoordinator).onUrlAnimationFinished(true);
verify(mUrlCoordinator).clearFocus();
// The first invocation of requestFocus() is from setUrlBarFocus, which we use above to set
// mUrlFocusedFromFakebox to true.
verify(mUrlCoordinator, times(2)).requestFocus();
verify(mUrlCoordinator)
.setUrlBarData(argThat(matchesUrlBarDataForQuery("text")),
eq(UrlBar.ScrollType.NO_SCROLL),
eq(UrlBarCoordinator.SelectionState.SELECT_END));
}
private ArgumentMatcher<UrlBarData> matchesUrlBarDataForQuery(String query) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment