// Copyright 2014 The Chromium Authors
// 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.toolbar;
import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.LruCache;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import org.jni_zero.CalledByNative;
import org.jni_zero.NativeMethods;
import org.chromium.base.ObserverList;
import org.chromium.base.TraceEvent;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
import org.chromium.chrome.browser.omnibox.NewTabPageDelegate;
import org.chromium.chrome.browser.omnibox.SearchEngineUtils;
import org.chromium.chrome.browser.omnibox.UrlBarData;
import org.chromium.chrome.browser.omnibox.styles.OmniboxResourceProvider;
import org.chromium.chrome.browser.paint_preview.TabbedPaintPreview;
import org.chromium.chrome.browser.pdf.PdfUtils;
import org.chromium.chrome.browser.pdf.PdfUtils.PdfPageType;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TrustedCdn;
import org.chromium.chrome.browser.theme.ThemeUtils;
import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification;
import org.chromium.components.omnibox.AutocompleteSchemeClassifier;
import org.chromium.components.omnibox.OmniboxUrlEmphasizer;
import org.chromium.components.omnibox.SecurityStatusIcon;
import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.components.security_state.SecurityStateModel;
import org.chromium.content_public.browser.WebContents;
import org.chromium.url.GURL;
import java.util.Objects;
/** Provides a way of accessing toolbar data and state. */
public class LocationBarModel implements ToolbarDataProvider, LocationBarDataProvider {
private static final int LRU_CACHE_SIZE = 10;
static class SpannableDisplayTextCacheKey {
@NonNull private final String mUrl;
@NonNull private final String mDisplayText;
private final int mSecurityLevel;
private final int mNonEmphasizedColor;
private final int mEmphasizedColor;
private final int mDangerColor;
private final int mSecureColor;
private SpannableDisplayTextCacheKey(
@NonNull String url,
@NonNull String displayText,
int securityLevel,
int nonEmphasizedColor,
int emphasizedColor,
int dangerColor,
int secureColor) {
mUrl = url;
mDisplayText = displayText;
mSecurityLevel = securityLevel;
mNonEmphasizedColor = nonEmphasizedColor;
mEmphasizedColor = emphasizedColor;
mDangerColor = dangerColor;
mSecureColor = secureColor;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SpannableDisplayTextCacheKey that = (SpannableDisplayTextCacheKey) o;
return mSecurityLevel == that.mSecurityLevel
&& mNonEmphasizedColor == that.mNonEmphasizedColor
&& mEmphasizedColor == that.mEmphasizedColor
&& mDangerColor == that.mDangerColor
&& mSecureColor == that.mSecureColor
&& mUrl.equals(that.mUrl)
&& mDisplayText.equals(that.mDisplayText);
}
@Override
public int hashCode() {
return Objects.hash(
mUrl,
mDisplayText,
mSecurityLevel,
mNonEmphasizedColor,
mEmphasizedColor,
mDangerColor,
mSecureColor);
}
}
/** Formats the given URL to the original one of a distillation. */
@FunctionalInterface
public interface UrlFormatter {
String format(GURL url);
}
/** Offline-related status of a given content. */
public interface OfflineStatus {
/** Returns whether the WebContents is showing trusted offline page. */
default boolean isShowingTrustedOfflinePage(Tab tab) {
return false;
}
/** Checks if an offline page is shown for the tab. */
default boolean isOfflinePage(Tab tab) {
return false;
}
}
private final Context mContext;
private final NewTabPageDelegate mNtpDelegate;
private final @NonNull UrlFormatter mUrlFormatter;
private final @NonNull OfflineStatus mOfflineStatus;
// Always null if optimizations are disabled. Otherwise, non-null and unchanging following
// native init. Always tied to the original profile which is safe because no underlying
// services have an incognito-specific instance.
@Nullable private AutocompleteSchemeClassifier mChromeAutocompleteSchemeClassifier;
@Nullable private Profile mProfile;
private boolean mInitializedProfileDependentFeatures;
@Nullable
private LruCache<SpannableDisplayTextCacheKey, SpannableStringBuilder>
mSpannableDisplayTextCache;
private Tab mTab;
private int mPrimaryColor;
private boolean mIsIncognitoBranded;
private boolean mIsOffTheRecord;
private boolean mIsUsingBrandColor;
private long mNativeLocationBarModelAndroid;
private ObserverList<LocationBarDataProvider.Observer> mLocationBarDataObservers =
new ObserverList<>();
protected GURL mVisibleGurl = GURL.emptyGURL();
protected String mFormattedFullUrl;
protected String mUrlForDisplay;
private boolean mOmniboxUpdatedConnectionSecurityIndicatorsEnabled;
// notifyUrlChanged and notifySecurityStateChanged are usually called 3 times across a same
// document navigation. The first call is usually necessary, which updates the UrlBar to reflect
// the new url. All subsequent calls are spurious and can be avoided. This experiment involves
// using the flags below to short circuit all calls after the UrlBar has already been updated.
private boolean mIsInSameDocNav;
private boolean mAlreadyUpdatedUrlBarForSameDocNav;
private boolean mAlreadyChangedSecurityStateForSameDocNav;
/**
* Default constructor for this class.
*
* @param context The Context used for styling the toolbar visuals.
* @param newTabPageDelegate Delegate used to access NTP.
* @param urlFormatter Formatter returning the formatted version of the original version of URL
* of a distillation.
* @param offlineStatus Offline-related status provider.
* @param searchEngineUtils Utils to query the state of the search engine logos feature.
*/
public LocationBarModel(
Context context,
NewTabPageDelegate newTabPageDelegate,
@NonNull UrlFormatter urlFormatter,
@NonNull OfflineStatus offlineStatus) {
mContext = context;
mNtpDelegate = newTabPageDelegate;
mUrlFormatter = urlFormatter;
mOfflineStatus = offlineStatus;
mPrimaryColor = ChromeColors.getDefaultThemeColor(context, false);
mUrlForDisplay = "";
mFormattedFullUrl = "";
}
/** Handle any initialization that must occur after native has been initialized. */
public void initializeWithNative() {
mOmniboxUpdatedConnectionSecurityIndicatorsEnabled =
ChromeFeatureList.isEnabled(
ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS);
mNativeLocationBarModelAndroid = LocationBarModelJni.get().init(LocationBarModel.this);
mSpannableDisplayTextCache = new LruCache<>(LRU_CACHE_SIZE);
}
private void performProfileDependentInitializationIfRequired() {
if (mInitializedProfileDependentFeatures) return;
assert mProfile != null;
mInitializedProfileDependentFeatures = true;
mChromeAutocompleteSchemeClassifier =
new ChromeAutocompleteSchemeClassifier(getProfile().getOriginalProfile());
recalculateFormattedUrls();
}
/** Destroys the native LocationBarModel. */
public void destroy() {
if (mChromeAutocompleteSchemeClassifier != null) {
mChromeAutocompleteSchemeClassifier.destroy();
mChromeAutocompleteSchemeClassifier = null;
}
if (mNativeLocationBarModelAndroid == 0) return;
LocationBarModelJni.get().destroy(mNativeLocationBarModelAndroid, LocationBarModel.this);
mNativeLocationBarModelAndroid = 0;
}
/**
* @return The currently active WebContents being used by the Toolbar.
*/
@CalledByNative
private WebContents getActiveWebContents() {
if (!hasTab()) return null;
return mTab.getWebContents();
}
/**
* Sets the tab that contains the information to be displayed in the toolbar.
*
* @param tab The tab associated currently with the toolbar.
* @param profile The profile associated with the currently selected model, which must match the
* passed in tab if non-null.
*/
public void setTab(@Nullable Tab tab, @NonNull Profile profile) {
assert tab == null || tab.getProfile() == profile;
assert profile != null;
mTab = tab;
mProfile = profile;
performProfileDependentInitializationIfRequired();
boolean isOffTheRecord = profile.isOffTheRecord();
boolean isIncognitoBranded = profile.isIncognitoBranded();
if (mIsOffTheRecord != isOffTheRecord || mIsIncognitoBranded != isIncognitoBranded) {
mIsOffTheRecord = isOffTheRecord;
mIsIncognitoBranded = isIncognitoBranded;
notifyIncognitoStateChanged();
}
updateUsingBrandColor();
notifyTitleChanged();
notifyUrlChanged();
notifyPrimaryColorChanged();
notifySecurityStateChanged();
}
@Override
public Tab getTab() {
return hasTab() ? mTab : null;
}
@Override
public boolean hasTab() {
// TODO(crbug.com/40730536): Remove the isInitialized() and isDestroyed checks when
// we no longer wait for TAB_CLOSED events to remove this tab. Otherwise there is a chance
// we use this tab after {@link Tab#destroy()} is called.
return mTab != null && mTab.isInitialized() && !mTab.isDestroyed();
}
@Override
public void addObserver(LocationBarDataProvider.Observer observer) {
mLocationBarDataObservers.addObserver(observer);
}
@Override
public void removeObserver(LocationBarDataProvider.Observer observer) {
mLocationBarDataObservers.removeObserver(observer);
}
@Override
// TODO(crbug.com/40218072): migrate to GURL.
@Deprecated
public String getCurrentUrl() {
return getCurrentGurl().getSpec().trim();
}
@Override
public GURL getCurrentGurl() {
return mVisibleGurl;
}
/**
* Reterived updated cached values for the current URL.
*
* @return whether the URL value has changed.
*/
@VisibleForTesting
boolean updateVisibleGurl() {
try (TraceEvent te = TraceEvent.scoped("LocationBarModel.updateVisibleGurl")) {
GURL gurl = getUrlOfVisibleNavigationEntry();
if (!gurl.equals(mVisibleGurl)) {
mVisibleGurl = gurl;
recalculateFormattedUrls();
return true;
}
}
return false;
}
public void notifyUrlChanged() {
if ((mIsInSameDocNav && mAlreadyUpdatedUrlBarForSameDocNav) || !updateVisibleGurl()) {
return;
}
// Url has changed, propagate it.
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onUrlChanged();
}
mAlreadyUpdatedUrlBarForSameDocNav = mIsInSameDocNav;
}
public void notifyZeroSuggestRefresh() {
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.hintZeroSuggestRefresh();
}
}
@Override
public NewTabPageDelegate getNewTabPageDelegate() {
return mNtpDelegate;
}
void notifyNtpStartedLoading() {
for (Observer observer : mLocationBarDataObservers) {
observer.onNtpStartedLoading();
}
}
@Override
public UrlBarData getUrlBarData() {
// Part of scroll jank investigation http://crbug.com/905461. Will remove TraceEvent after
// the investigation is complete.
try (TraceEvent te = TraceEvent.scoped("LocationBarModel.getUrlBarData")) {
if (!hasTab()) {
return UrlBarData.EMPTY;
}
GURL gurl = getCurrentGurl();
if (!UrlBarData.shouldShowUrl(gurl, isOffTheRecord())) {
return UrlBarData.EMPTY;
}
String url = gurl.getSpec().trim();
boolean isOfflinePage = isOfflinePage();
String formattedUrl = getFormattedFullUrl();
if (mTab.isFrozen()) return buildUrlBarData(gurl, isOfflinePage, formattedUrl);
if (DomDistillerUrlUtils.isDistilledPage(url)) {
GURL originalUrl =
DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(new GURL(url));
return buildUrlBarData(originalUrl, isOfflinePage);
}
if (isOfflinePage) {
GURL originalUrl = mTab.getOriginalUrl();
formattedUrl = UrlUtilities.stripScheme(mUrlFormatter.format(originalUrl));
// Clear the editing text for untrusted offline pages.
if (!mOfflineStatus.isShowingTrustedOfflinePage(mTab)) {
return buildUrlBarData(gurl, true, formattedUrl, "");
}
return buildUrlBarData(gurl, true, formattedUrl);
}
String urlForDisplay = getUrlForDisplay();
if (!urlForDisplay.equals(formattedUrl)) {
return buildUrlBarData(gurl, false, urlForDisplay, formattedUrl);
}
return buildUrlBarData(gurl, false, formattedUrl);
}
}
private UrlBarData buildUrlBarData(GURL url, boolean isOfflinePage) {
return buildUrlBarData(url, isOfflinePage, url.getSpec());
}
private UrlBarData buildUrlBarData(GURL url, boolean isOfflinePage, String displayText) {
return buildUrlBarData(url, isOfflinePage, displayText, displayText);
}
private UrlBarData buildUrlBarData(
GURL url, boolean isOfflinePage, String displayText, String editingText) {
SpannableStringBuilder spannableDisplayText = null;
if (mNativeLocationBarModelAndroid != 0
&& displayText != null
&& displayText.length() > 0
&& shouldEmphasizeUrl()) {
final @BrandedColorScheme int brandedColorScheme =
OmniboxResourceProvider.getBrandedColorScheme(
mContext, isIncognitoBranded(), getPrimaryColor());
final @ColorInt int nonEmphasizedColor =
OmniboxResourceProvider.getUrlBarSecondaryTextColor(
mContext, brandedColorScheme);
final @ColorInt int emphasizedColor =
OmniboxResourceProvider.getUrlBarPrimaryTextColor(mContext, brandedColorScheme);
final @ColorInt int dangerColor =
OmniboxResourceProvider.getUrlBarDangerColor(mContext, brandedColorScheme);
final @ColorInt int secureColor =
OmniboxResourceProvider.getUrlBarSecureColor(mContext, brandedColorScheme);
AutocompleteSchemeClassifier autocompleteSchemeClassifier;
int securityLevel = getSecurityLevel(getTab(), isOfflinePage);
SpannableDisplayTextCacheKey cacheKey =
new SpannableDisplayTextCacheKey(
url.getSpec(),
displayText,
securityLevel,
nonEmphasizedColor,
emphasizedColor,
dangerColor,
secureColor);
SpannableStringBuilder cachedSpannableDisplayText =
mSpannableDisplayTextCache.get(cacheKey);
autocompleteSchemeClassifier = mChromeAutocompleteSchemeClassifier;
if (cachedSpannableDisplayText != null) {
return UrlBarData.forUrlAndText(url, cachedSpannableDisplayText, editingText);
} else {
spannableDisplayText = new SpannableStringBuilder(displayText);
OmniboxUrlEmphasizer.emphasizeUrl(
spannableDisplayText,
autocompleteSchemeClassifier,
getSecurityLevel(),
shouldEmphasizeHttpsScheme(),
nonEmphasizedColor,
emphasizedColor,
dangerColor,
secureColor);
mSpannableDisplayTextCache.put(cacheKey, spannableDisplayText);
}
}
return UrlBarData.forUrlAndText(url, spannableDisplayText, editingText);
}
/**
* @return True if the displayed URL should be emphasized, false if the displayed text
* already has formatting for emphasis applied.
*/
private boolean shouldEmphasizeUrl() {
// If the toolbar shows the publisher URL, it applies its own formatting for emphasis.
if (mTab == null) return true;
return TrustedCdn.getPublisherUrl(mTab) == null;
}
LruCache<SpannableDisplayTextCacheKey, SpannableStringBuilder> getCacheForTesting() {
return mSpannableDisplayTextCache;
}
/**
* @return Whether the light security theme should be used.
*/
@VisibleForTesting
public boolean shouldEmphasizeHttpsScheme() {
return !isUsingBrandColor() && !isIncognitoBranded();
}
@Override
public String getTitle() {
if (!hasTab()) return "";
String title = getTab().getTitle();
return TextUtils.isEmpty(title) ? title : title.trim();
}
public void notifyTitleChanged() {
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onTitleChanged();
}
}
@Override
public boolean isIncognito() {
return mIsOffTheRecord;
}
@Override
public boolean isIncognitoBranded() {
return mIsIncognitoBranded;
}
@Override
public boolean isOffTheRecord() {
return mIsOffTheRecord;
}
private void notifyIncognitoStateChanged() {
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onIncognitoStateChanged();
}
}
@Override
public Profile getProfile() {
return mProfile;
}
/**
* Sets the primary color and changes the state for isUsingBrandColor.
*
* @param color The primary color for the current tab.
*/
public void setPrimaryColor(int color) {
mPrimaryColor = color;
updateUsingBrandColor();
notifyPrimaryColorChanged();
}
private void updateUsingBrandColor() {
mIsUsingBrandColor =
!isIncognitoBranded()
&& mPrimaryColor
!= ChromeColors.getDefaultThemeColor(mContext, isIncognitoBranded())
&& hasTab()
&& !mTab.isNativePage();
}
@Override
public int getPrimaryColor() {
return mPrimaryColor;
}
@Override
public boolean isUsingBrandColor() {
return mIsUsingBrandColor;
}
public void notifyPrimaryColorChanged() {
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onPrimaryColorChanged();
}
}
@Override
public boolean isOfflinePage() {
return hasTab() && mOfflineStatus.isOfflinePage(mTab);
}
@Override
public boolean isPaintPreview() {
return hasTab() && TabbedPaintPreview.get(mTab).isShowing();
}
private int getPdfPageType() {
if (!hasTab()) {
return 0;
}
return PdfUtils.getPdfPageType(mTab.getNativePage());
}
@Override
public int getSecurityLevel() {
return getSecurityLevel(getTab(), isOfflinePage());
}
@Override
public int getPageClassification(boolean isPrefetch) {
if (mNativeLocationBarModelAndroid == 0) return PageClassification.INVALID_SPEC_VALUE;
return LocationBarModelJni.get()
.getPageClassification(mNativeLocationBarModelAndroid, isPrefetch);
}
@Override
public @DrawableRes int getSecurityIconResource(boolean isTablet) {
boolean isOfflinePage = isOfflinePage();
return getSecurityIconResource(
getSecurityLevel(getTab(), isOfflinePage),
!isTablet,
isOfflinePage,
isPaintPreview(),
getPdfPageType());
}
@Override
public @StringRes int getSecurityIconContentDescriptionResourceId() {
return SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(getSecurityLevel());
}
@VisibleForTesting
@ConnectionSecurityLevel
int getSecurityLevel(Tab tab, boolean isOfflinePage) {
if (tab == null || isOfflinePage) {
return ConnectionSecurityLevel.NONE;
}
@Nullable GURL publisherUrl = TrustedCdn.getPublisherUrl(tab);
if (publisherUrl != null) {
assert getSecurityLevelFromStateModel(tab.getWebContents())
!= ConnectionSecurityLevel.DANGEROUS;
return (publisherUrl.getScheme().equals(UrlConstants.HTTPS_SCHEME))
? ConnectionSecurityLevel.SECURE
: ConnectionSecurityLevel.WARNING;
}
return getSecurityLevelFromStateModel(tab.getWebContents());
}
@VisibleForTesting
@ConnectionSecurityLevel
int getSecurityLevelFromStateModel(WebContents webContents) {
int securityLevel = SecurityStateModel.getSecurityLevelForWebContents(webContents);
return securityLevel;
}
@VisibleForTesting
@DrawableRes
int getSecurityIconResource(
int securityLevel,
boolean isSmallDevice,
boolean isOfflinePage,
boolean isPaintPreview,
int pdfPageType) {
// Paint Preview appears on top of WebContents and shows a visual representation of the page
// that has been previously stored locally.
if (isPaintPreview) return R.drawable.omnibox_info;
// Checking for a preview first because one possible preview type is showing an offline page
// on a slow connection. In this case, the previews UI takes precedence.
if (isOfflinePage) {
return R.drawable.ic_offline_pin_24dp;
}
// Pdf page is a native page used to render downloaded pdf files.
// Show warning icon for pdf from insecure source (e.g. mixed content download).
if (pdfPageType == PdfPageType.TRANSIENT_INSECURE) {
return R.drawable.omnibox_not_secure_warning;
}
// Show info icon for other pdf pages.
if (pdfPageType == PdfPageType.TRANSIENT_SECURE || pdfPageType == PdfPageType.LOCAL) {
return R.drawable.omnibox_info;
}
// Return early if native initialization hasn't been done yet.
if ((securityLevel == ConnectionSecurityLevel.NONE
|| securityLevel == ConnectionSecurityLevel.WARNING)
&& mNativeLocationBarModelAndroid == 0) {
return R.drawable.omnibox_info;
}
boolean skipIconForNeutralState =
(mProfile != null
&& !SearchEngineUtils.getForProfile(mProfile)
.shouldShowSearchEngineLogo())
|| mNtpDelegate.isCurrentlyVisible();
return SecurityStatusIcon.getSecurityIconResource(
securityLevel,
isSmallDevice,
skipIconForNeutralState,
mOmniboxUpdatedConnectionSecurityIndicatorsEnabled);
}
@Override
public @ColorRes int getSecurityIconColorStateList() {
final @ColorInt int color = getPrimaryColor();
final @BrandedColorScheme int brandedColorScheme =
OmniboxResourceProvider.getBrandedColorScheme(
mContext, isIncognitoBranded(), color);
// Assign red color to security icon if the page shows security warning.
return getSecurityIconColorWithSecurityLevel(
getSecurityLevel(), brandedColorScheme, isIncognitoBranded());
}
/**
* Get the color for the security icon for different security levels. If we are using dark
* background (dark mode or incognito mode), we should return light red. If we are using light
* background (light mode, but not LIGHT_BRANDED_THEME), we should return dark red. The default
* brand color will be returned if no change is needed.
*
* @param connectionSecurityLevel The connection security level for the current website.
* @param brandedColorScheme The branded color scheme for the omnibox.
* @param isIncognito Whether the tab is in Incognito mode.
* @return The color resource for the security icon, returns -1 if doe snot need to change
* color.
*/
@VisibleForTesting
protected @ColorRes int getSecurityIconColorWithSecurityLevel(
@ConnectionSecurityLevel int connectionSecurityLevel,
@BrandedColorScheme int brandedColorScheme,
boolean isIncognito) {
// Return regular color scheme if the website does not show warning.
if (connectionSecurityLevel == ConnectionSecurityLevel.DANGEROUS) {
// Assign red color only on light or dark background including Incognito mode.
// We will not change the security icon to red when BrandedColorScheme is
// LIGHT_BRANDED_THEME for the purpose of improving contrast.
if (isIncognito) {
// Use light red for Incognito mode.
return R.color.baseline_error_80;
} else if (brandedColorScheme == BrandedColorScheme.APP_DEFAULT) {
// Use adaptive red for light and dark background.
return R.color.default_red;
}
}
return ThemeUtils.getThemedToolbarIconTintRes(brandedColorScheme);
}
public void notifySecurityStateChanged() {
if (mIsInSameDocNav && mAlreadyChangedSecurityStateForSameDocNav) {
return;
}
@ConnectionSecurityLevel int securityLevel = getSecurityLevel();
if (securityLevel == ConnectionSecurityLevel.DANGEROUS) {
recalculateFormattedUrls();
}
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onSecurityStateChanged();
}
mAlreadyChangedSecurityStateForSameDocNav = mIsInSameDocNav;
}
private void recalculateFormattedUrls() {
mFormattedFullUrl = calculateFormattedFullUrl();
mUrlForDisplay = calculateUrlForDisplay();
}
private String getFormattedFullUrl() {
return mFormattedFullUrl;
}
private String getUrlForDisplay() {
return mUrlForDisplay;
}
/** @return The formatted URL suitable for editing. */
protected String calculateFormattedFullUrl() {
if (mNativeLocationBarModelAndroid == 0) return "";
return LocationBarModelJni.get()
.getFormattedFullURL(mNativeLocationBarModelAndroid, LocationBarModel.this);
}
/** @return The formatted URL suitable for display only. */
protected String calculateUrlForDisplay() {
if (mNativeLocationBarModelAndroid == 0) return "";
return LocationBarModelJni.get()
.getURLForDisplay(mNativeLocationBarModelAndroid, LocationBarModel.this);
}
protected GURL getUrlOfVisibleNavigationEntry() {
if (mNativeLocationBarModelAndroid == 0) return GURL.emptyGURL();
if (mNtpDelegate.isCurrentlyVisible()) {
return getTab().getUrl();
}
return LocationBarModelJni.get()
.getUrlOfVisibleNavigationEntry(
mNativeLocationBarModelAndroid, LocationBarModel.this);
}
/** Notify changes for non static layout. */
public void updateForNonStaticLayout() {
notifyTitleChanged();
notifyUrlChanged();
notifyPrimaryColorChanged();
notifySecurityStateChanged();
}
public void notifyDidStartNavigation(boolean isSameDocument) {
resetSameDocNavFlags();
mIsInSameDocNav = isSameDocument;
}
public void notifyDidFinishNavigationEnd() {
resetSameDocNavFlags();
}
public void notifyOnCrash() {
resetSameDocNavFlags();
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onTabCrashed();
}
}
public void notifyContentChanged() {
resetSameDocNavFlags();
}
public void notifyWebContentsSwapped() {
resetSameDocNavFlags();
}
private void resetSameDocNavFlags() {
mIsInSameDocNav = false;
mAlreadyUpdatedUrlBarForSameDocNav = false;
mAlreadyChangedSecurityStateForSameDocNav = false;
}
@NativeMethods
interface Natives {
long init(LocationBarModel caller);
void destroy(long nativeLocationBarModelAndroid, LocationBarModel caller);
String getFormattedFullURL(long nativeLocationBarModelAndroid, LocationBarModel caller);
String getURLForDisplay(long nativeLocationBarModelAndroid, LocationBarModel caller);
GURL getUrlOfVisibleNavigationEntry(
long nativeLocationBarModelAndroid, LocationBarModel caller);
int getPageClassification(long nativeLocationBarModelAndroid, boolean isPrefetch);
}
public void onPageLoadStopped() {
for (LocationBarDataProvider.Observer observer : mLocationBarDataObservers) {
observer.onPageLoadStopped();
}
}
}