// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.toolbar; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Pair; import android.util.TypedValue; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.WindowDelegate; import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper; import org.chromium.chrome.browser.dom_distiller.DomDistillerServiceFactory; import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils; import org.chromium.chrome.browser.ntp.NativePageFactory; import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.omnibox.LocationBar; import org.chromium.chrome.browser.omnibox.LocationBarLayout; import org.chromium.chrome.browser.omnibox.UrlBar; import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; import org.chromium.chrome.browser.pageinfo.WebsiteSettingsPopup; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.ActionModeController.ActionBarDelegate; import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.chrome.browser.widget.TintedImageButton; import org.chromium.components.dom_distiller.core.DomDistillerService; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; import org.chromium.components.security_state.ConnectionSecurityLevel; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.interpolators.BakedBezierInterpolator; import org.chromium.ui.widget.Toast; import java.util.List; /** * The Toolbar layout to be used for a custom tab. This is used for both phone and tablet UIs. */ public class CustomTabToolbar extends ToolbarLayout implements LocationBar, View.OnLongClickListener { /** * A simple {@link FrameLayout} that prevents its children from getting touch events. This is * especially useful to prevent {@link UrlBar} from running custom touch logic since it is * read-only in custom tabs. */ public static class InterceptTouchLayout extends FrameLayout { private GestureDetector mGestureDetector; public InterceptTouchLayout(Context context, AttributeSet attrs) { super(context, attrs); mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (LibraryLoader.isInitialized()) { RecordUserAction.record("CustomTabs.TapUrlBar"); } return super.onSingleTapConfirmed(e); } }); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; } @Override public boolean onTouchEvent(MotionEvent event) { mGestureDetector.onTouchEvent(event); return super.onTouchEvent(event); } } private static final int TITLE_ANIM_DELAY_MS = 800; private static final int STATE_DOMAIN_ONLY = 0; private static final int STATE_TITLE_ONLY = 1; private static final int STATE_DOMAIN_AND_TITLE = 2; private View mLocationBarFrameLayout; private View mTitleUrlContainer; private UrlBar mUrlBar; private TextView mTitleBar; private TintedImageButton mSecurityButton; private ImageButton mCustomActionButton; private int mSecurityIconType; private ImageButton mCloseButton; // Whether dark tint should be applied to icons and text. private boolean mUseDarkColors = true; private ValueAnimator mBrandColorTransitionAnimation; private boolean mBrandColorTransitionActive; private CustomTabToolbarAnimationDelegate mAnimDelegate; private int mState = STATE_DOMAIN_ONLY; private String mFirstUrl; private boolean mShowsOfflinePage = false; private Runnable mTitleAnimationStarter = new Runnable() { @Override public void run() { mAnimDelegate.startTitleAnimation(getContext()); } }; /** * Constructor for getting this class inflated from an xml layout file. */ public CustomTabToolbar(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { super.onFinishInflate(); setBackground(new ColorDrawable( ApiCompatibilityUtils.getColor(getResources(), R.color.default_primary_color))); mUrlBar = (UrlBar) findViewById(R.id.url_bar); mUrlBar.setHint(""); mUrlBar.setDelegate(this); mUrlBar.setEnabled(false); mUrlBar.setAllowFocus(false); mTitleBar = (TextView) findViewById(R.id.title_bar); mLocationBarFrameLayout = findViewById(R.id.location_bar_frame_layout); mTitleUrlContainer = findViewById(R.id.title_url_container); mTitleUrlContainer.setOnLongClickListener(this); mSecurityButton = (TintedImageButton) findViewById(R.id.security_button); mSecurityIconType = ConnectionSecurityLevel.NONE; mCustomActionButton = (ImageButton) findViewById(R.id.action_button); mCustomActionButton.setOnLongClickListener(this); mCloseButton = (ImageButton) findViewById(R.id.close_button); mCloseButton.setOnLongClickListener(this); mAnimDelegate = new CustomTabToolbarAnimationDelegate(mSecurityButton, mTitleUrlContainer); } @Override protected int getToolbarHeightWithoutShadowResId() { return R.dimen.custom_tabs_control_container_height; } @Override public void initialize(ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController, AppMenuButtonHelper appMenuButtonHelper) { super.initialize(toolbarDataProvider, tabController, appMenuButtonHelper); updateVisualsForState(); } @Override public void onNativeLibraryReady() { super.onNativeLibraryReady(); mSecurityButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Tab currentTab = getToolbarDataProvider().getTab(); if (currentTab == null || currentTab.getWebContents() == null) return; Activity activity = currentTab.getWindowAndroid().getActivity().get(); if (activity == null) return; String publisherName = mState == STATE_TITLE_ONLY ? parsePublisherNameFromUrl(currentTab.getUrl()) : null; WebsiteSettingsPopup.show(activity, currentTab, publisherName, WebsiteSettingsPopup.OPENED_FROM_TOOLBAR); } }); } @Override public void setCloseButtonImageResource(Drawable drawable) { mCloseButton.setImageDrawable(drawable); } @Override public void setCustomTabCloseClickHandler(OnClickListener listener) { mCloseButton.setOnClickListener(listener); } @Override public void setCustomActionButton(Drawable drawable, String description, OnClickListener listener) { Resources resources = getResources(); // The height will be scaled to match spec while keeping the aspect ratio, so get the scaled // width through that. int sourceHeight = drawable.getIntrinsicHeight(); int sourceScaledHeight = resources.getDimensionPixelSize(R.dimen.toolbar_icon_height); int sourceWidth = drawable.getIntrinsicWidth(); int sourceScaledWidth = sourceWidth * sourceScaledHeight / sourceHeight; int minPadding = resources.getDimensionPixelSize(R.dimen.min_toolbar_icon_side_padding); int sidePadding = Math.max((2 * sourceScaledHeight - sourceScaledWidth) / 2, minPadding); int topPadding = mCustomActionButton.getPaddingTop(); int bottomPadding = mCustomActionButton.getPaddingBottom(); mCustomActionButton.setPadding(sidePadding, topPadding, sidePadding, bottomPadding); mCustomActionButton.setImageDrawable(drawable); mCustomActionButton.setContentDescription(description); mCustomActionButton.setOnClickListener(listener); mCustomActionButton.setVisibility(VISIBLE); updateButtonsTint(); } /** * @return The custom action button. For test purpose only. */ @VisibleForTesting public ImageButton getCustomActionButtonForTest() { return mCustomActionButton; } @Override public int getTabStripHeight() { return 0; } @Override public Tab getCurrentTab() { return getToolbarDataProvider().getTab(); } @Override public boolean shouldEmphasizeHttpsScheme() { int securityLevel = getSecurityLevel(); return securityLevel == ConnectionSecurityLevel.DANGEROUS || securityLevel == ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT; } @Override public void setShowTitle(boolean showTitle) { if (showTitle) { mState = STATE_DOMAIN_AND_TITLE; mAnimDelegate.prepareTitleAnim(mUrlBar, mTitleBar); } else { mState = STATE_DOMAIN_ONLY; } } @Override public void setUrlBarHidden(boolean hideUrlBar) { // Urlbar visibility cannot be toggled if it is the only visible element. if (mState == STATE_DOMAIN_ONLY) return; if (hideUrlBar && mState == STATE_DOMAIN_AND_TITLE) { mState = STATE_TITLE_ONLY; mAnimDelegate.setTitleAnimationEnabled(false); mUrlBar.setVisibility(View.GONE); mTitleBar.setVisibility(View.VISIBLE); LayoutParams lp = (LayoutParams) mTitleBar.getLayoutParams(); lp.bottomMargin = 0; mTitleBar.setLayoutParams(lp); mTitleBar.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.location_bar_url_text_size)); } else if (!hideUrlBar && mState == STATE_TITLE_ONLY) { mState = STATE_DOMAIN_AND_TITLE; mTitleBar.setVisibility(View.VISIBLE); mUrlBar.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.custom_tabs_url_text_size)); mUrlBar.setVisibility(View.VISIBLE); LayoutParams lp = (LayoutParams) mTitleBar.getLayoutParams(); lp.bottomMargin = getResources() .getDimensionPixelSize(R.dimen.custom_tabs_toolbar_vertical_padding); mTitleBar.setLayoutParams(lp); mTitleBar.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.custom_tabs_title_text_size)); updateSecurityIcon(getSecurityLevel()); } else { assert false : "Unreached state"; } } @Override public String getContentPublisher() { if (mState == STATE_TITLE_ONLY) { if (getToolbarDataProvider().getTab() == null) return null; return parsePublisherNameFromUrl(getToolbarDataProvider().getTab().getUrl()); } return null; } @Override public void setTitleToPageTitle() { Tab currentTab = getToolbarDataProvider().getTab(); if (currentTab == null || TextUtils.isEmpty(currentTab.getTitle())) { mTitleBar.setText(""); return; } String title = currentTab.getTitle(); // It takes some time to parse the title of the webcontent, and before that Tab#getTitle // always return the url. We postpone the title animation until the title is authentic. if ((mState == STATE_DOMAIN_AND_TITLE || mState == STATE_TITLE_ONLY) && !title.equals(currentTab.getUrl()) && !title.equals(UrlConstants.ABOUT_BLANK)) { // Delay the title animation until security icon animation finishes. ThreadUtils.postOnUiThreadDelayed(mTitleAnimationStarter, TITLE_ANIM_DELAY_MS); } mTitleBar.setText(title); } @Override protected void onNavigatedToDifferentPage() { super.onNavigatedToDifferentPage(); setTitleToPageTitle(); if (mState == STATE_TITLE_ONLY) { if (TextUtils.isEmpty(mFirstUrl)) { mFirstUrl = getToolbarDataProvider().getTab().getUrl(); } else { if (mFirstUrl.equals(getToolbarDataProvider().getTab().getUrl())) return; setUrlBarHidden(false); } } updateSecurityIcon(getSecurityLevel()); } @Override public void setUrlToPageUrl() { if (getCurrentTab() == null) { mUrlBar.setUrl("", null); return; } String url = getCurrentTab().getUrl().trim(); // Don't show anything for Chrome URLs and "about:blank". // If we have taken a pre-initialized WebContents, then the starting URL // is "about:blank". We should not display it. if (NativePageFactory.isNativePageUrl(url, getCurrentTab().isIncognito()) || UrlConstants.ABOUT_BLANK.equals(url)) { mUrlBar.setUrl("", null); return; } String displayText = getToolbarDataProvider().getText(); Pair<String, String> urlText = LocationBarLayout.splitPathFromUrlDisplayText(displayText); displayText = urlText.first; if (DomDistillerUrlUtils.isDistilledPage(url)) { if (isStoredArticle(url)) { Profile profile = getCurrentTab().getProfile(); DomDistillerService domDistillerService = DomDistillerServiceFactory.getForProfile(profile); String originalUrl = domDistillerService.getUrlForEntry( DomDistillerUrlUtils.getValueForKeyInUrl(url, "entry_id")); displayText = DomDistillerTabUtils.getFormattedUrlFromOriginalDistillerUrl(originalUrl); } else if (DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url) != null) { String originalUrl = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url); displayText = DomDistillerTabUtils.getFormattedUrlFromOriginalDistillerUrl(originalUrl); } } if (mUrlBar.setUrl(url, displayText)) { mUrlBar.deEmphasizeUrl(); mUrlBar.emphasizeUrl(); } } private boolean isStoredArticle(String url) { DomDistillerService domDistillerService = DomDistillerServiceFactory.getForProfile(Profile.getLastUsedProfile()); String entryIdFromUrl = DomDistillerUrlUtils.getValueForKeyInUrl(url, "entry_id"); if (TextUtils.isEmpty(entryIdFromUrl)) return false; return domDistillerService.hasEntry(entryIdFromUrl); } @Override public void updateLoadingState(boolean updateUrl) { if (updateUrl) setUrlToPageUrl(); updateSecurityIcon(getSecurityLevel()); } @Override public void updateVisualsForState() { Resources resources = getResources(); updateSecurityIcon(getSecurityLevel()); updateButtonsTint(); mUrlBar.setUseDarkTextColors(mUseDarkColors); int titleTextColor = mUseDarkColors ? ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_default_text) : ApiCompatibilityUtils.getColor(resources, R.color.url_emphasis_light_default_text); mTitleBar.setTextColor(titleTextColor); if (getProgressBar() != null) { if (!ColorUtils.isUsingDefaultToolbarColor(getResources(), getBackground().getColor())) { getProgressBar().setThemeColor(getBackground().getColor(), false); } else { getProgressBar().setBackgroundColor(ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_background)); getProgressBar().setForegroundColor(ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_foreground)); } } } private void updateButtonsTint() { mMenuButton.setTint(mUseDarkColors ? mDarkModeTint : mLightModeTint); if (mCloseButton.getDrawable() instanceof TintedDrawable) { ((TintedDrawable) mCloseButton.getDrawable()).setTint( mUseDarkColors ? mDarkModeTint : mLightModeTint); } if (mCustomActionButton.getDrawable() instanceof TintedDrawable) { ((TintedDrawable) mCustomActionButton.getDrawable()).setTint( mUseDarkColors ? mDarkModeTint : mLightModeTint); } if (mSecurityButton.getDrawable() instanceof TintedDrawable) { ((TintedDrawable) mSecurityButton.getDrawable()).setTint( mUseDarkColors ? mDarkModeTint : mLightModeTint); } } @Override public void setMenuButtonHelper(final AppMenuButtonHelper helper) { mMenuButton.setOnTouchListener(new OnTouchListener() { @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View v, MotionEvent event) { return helper.onTouch(v, event); } }); mMenuButton.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View view, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { return helper.onEnterKeyPress(view); } return false; } }); } @Override public View getMenuAnchor() { return mMenuButton; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); setTitleToPageTitle(); setUrlToPageUrl(); } @Override public ColorDrawable getBackground() { return (ColorDrawable) super.getBackground(); } @Override public void initializeControls(WindowDelegate windowDelegate, ActionBarDelegate delegate, WindowAndroid windowAndroid) { } private int getSecurityLevel() { if (getCurrentTab() == null) return ConnectionSecurityLevel.NONE; return getCurrentTab().getSecurityLevel(); } @Override public void updateSecurityIcon(int securityLevel) { if (mState == STATE_TITLE_ONLY) return; mSecurityIconType = securityLevel; boolean isSmallDevice = !DeviceFormFactor.isTablet(getContext()); boolean isOfflinePage = getCurrentTab() != null && getCurrentTab().isOfflinePage(); int id = LocationBarLayout.getSecurityIconResource( securityLevel, isSmallDevice, isOfflinePage); boolean showSecurityButton = true; if (id == 0) { // Hide the button if we don't have an actual icon to display. showSecurityButton = false; mSecurityButton.setImageDrawable(null); } else { // ImageView#setImageResource is no-op if given resource is the current one. mSecurityButton.setImageResource(id); mSecurityButton.setTint( LocationBarLayout.getColorStateList(securityLevel, getToolbarDataProvider(), getResources(), false /* omnibox is not opaque */)); } mShowsOfflinePage = isOfflinePage; if (showSecurityButton) { mAnimDelegate.showSecurityButton(); } else { mAnimDelegate.hideSecurityButton(); } mUrlBar.emphasizeUrl(); mUrlBar.invalidate(); } /** * For extending classes to override and carry out the changes related with the primary color * for the current tab changing. */ @Override protected void onPrimaryColorChanged(boolean shouldAnimate) { if (mBrandColorTransitionActive) mBrandColorTransitionAnimation.cancel(); final ColorDrawable background = getBackground(); final int initialColor = background.getColor(); final int finalColor = getToolbarDataProvider().getPrimaryColor(); if (background.getColor() == finalColor) return; mBrandColorTransitionAnimation = ValueAnimator.ofFloat(0, 1) .setDuration(ToolbarPhone.THEME_COLOR_TRANSITION_DURATION); mBrandColorTransitionAnimation.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE); mBrandColorTransitionAnimation.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); int red = (int) (Color.red(initialColor) + fraction * (Color.red(finalColor) - Color.red(initialColor))); int green = (int) (Color.green(initialColor) + fraction * (Color.green(finalColor) - Color.green(initialColor))); int blue = (int) (Color.blue(initialColor) + fraction * (Color.blue(finalColor) - Color.blue(initialColor))); background.setColor(Color.rgb(red, green, blue)); } }); mBrandColorTransitionAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mBrandColorTransitionActive = false; // Using the current background color instead of the final color in case this // animation was cancelled. This ensures the assets are updated to the visible // color. mUseDarkColors = !ColorUtils.shouldUseLightForegroundOnBackground(background.getColor()); updateVisualsForState(); } }); mBrandColorTransitionAnimation.start(); mBrandColorTransitionActive = true; if (!shouldAnimate) mBrandColorTransitionAnimation.end(); } @Override public View getContainerView() { return this; } @Override public void setDefaultTextEditActionModeCallback(ToolbarActionModeCallback callback) { mUrlBar.setCustomSelectionActionModeCallback(callback); } private void updateLayoutParams() { int startMargin = 0; int locationBarLayoutChildIndex = -1; for (int i = 0; i < getChildCount(); i++) { View childView = getChildAt(i); if (childView.getVisibility() != GONE) { LayoutParams childLayoutParams = (LayoutParams) childView.getLayoutParams(); if (ApiCompatibilityUtils.getMarginStart(childLayoutParams) != startMargin) { ApiCompatibilityUtils.setMarginStart(childLayoutParams, startMargin); childView.setLayoutParams(childLayoutParams); } if (childView == mLocationBarFrameLayout) { locationBarLayoutChildIndex = i; break; } int widthMeasureSpec; int heightMeasureSpec; if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec( getMeasuredWidth(), MeasureSpec.AT_MOST); } else if (childLayoutParams.width == LayoutParams.MATCH_PARENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec( getMeasuredWidth(), MeasureSpec.EXACTLY); } else { widthMeasureSpec = MeasureSpec.makeMeasureSpec( childLayoutParams.width, MeasureSpec.EXACTLY); } if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec( getMeasuredHeight(), MeasureSpec.AT_MOST); } else if (childLayoutParams.height == LayoutParams.MATCH_PARENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec( getMeasuredHeight(), MeasureSpec.EXACTLY); } else { heightMeasureSpec = MeasureSpec.makeMeasureSpec( childLayoutParams.height, MeasureSpec.EXACTLY); } childView.measure(widthMeasureSpec, heightMeasureSpec); startMargin += childView.getMeasuredWidth(); } } assert locationBarLayoutChildIndex != -1; int locationBarLayoutEndMargin = 0; for (int i = locationBarLayoutChildIndex + 1; i < getChildCount(); i++) { View childView = getChildAt(i); if (childView.getVisibility() != GONE) { locationBarLayoutEndMargin += childView.getMeasuredWidth(); } } LayoutParams urlLayoutParams = (LayoutParams) mLocationBarFrameLayout.getLayoutParams(); if (ApiCompatibilityUtils.getMarginEnd(urlLayoutParams) != locationBarLayoutEndMargin) { ApiCompatibilityUtils.setMarginEnd(urlLayoutParams, locationBarLayoutEndMargin); mLocationBarFrameLayout.setLayoutParams(urlLayoutParams); } // Update left margin of mTitleUrlContainer here to make sure the security icon is always // placed left of the urlbar. LayoutParams lp = (LayoutParams) mTitleUrlContainer.getLayoutParams(); if (mSecurityButton.getVisibility() == View.GONE) { lp.leftMargin = 0; } else { lp.leftMargin = mSecurityButton.getMeasuredWidth(); } mTitleUrlContainer.setLayoutParams(lp); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { updateLayoutParams(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public LocationBar getLocationBar() { return this; } @Override public boolean onLongClick(View v) { if (v == mCloseButton) { return showAccessibilityToast(v, getResources().getString(R.string.close_tab)); } else if (v == mCustomActionButton) { return showAccessibilityToast(v, mCustomActionButton.getContentDescription()); } else if (v == mTitleUrlContainer) { ClipboardManager clipboard = (ClipboardManager) getContext() .getSystemService(Context.CLIPBOARD_SERVICE); Tab tab = getCurrentTab(); if (tab == null) return false; String url = tab.getOriginalUrl(); ClipData clip = ClipData.newPlainText("url", url); clipboard.setPrimaryClip(clip); Toast.makeText(getContext(), R.string.url_copied, Toast.LENGTH_SHORT).show(); return true; } return false; } private static String parsePublisherNameFromUrl(String url) { // TODO(ianwen): Make it generic to parse url from URI path. http://crbug.com/599298 // The url should look like: https://www.google.com/amp/s/www.nyt.com/ampthml/blogs.html // or https://www.google.com/amp/www.nyt.com/ampthml/blogs.html. Uri uri = Uri.parse(url); List<String> segments = uri.getPathSegments(); if (segments.size() >= 3) { if (segments.get(1).length() > 1) return segments.get(1); return segments.get(2); } return url; } // Toolbar and LocationBar calls that are not relevant here. @Override public void setToolbarDataProvider(ToolbarDataProvider model) {} @Override public void onTextChangedForAutocomplete(boolean canInlineAutocomplete) {} @Override public void setUrlFocusChangeListener(UrlFocusChangeListener listener) {} @Override public void setUrlBarFocus(boolean shouldBeFocused) {} @Override public void showUrlBarCursorWithoutFocusAnimations() {} @Override public boolean isUrlBarFocused() { return false; } @Override public void selectAll() {} @Override public void revertChanges() {} @Override public long getFirstUrlBarFocusTime() { return 0; } @Override public void hideSuggestions() {} @Override public void updateMicButtonState() {} @Override public void onTabLoadingNTP(NewTabPage ntp) {} @Override public void setAutocompleteProfile(Profile profile) {} @Override public void showAppMenuUpdateBadge() {} @Override public boolean isShowingAppMenuUpdateBadge() { return false; } @Override public void removeAppMenuUpdateBadge(boolean animate) {} @Override protected void setAppMenuUpdateBadgeToVisible(boolean animate) {} @Override public View getMenuButtonWrapper() { // This class has no menu button wrapper, so return the menu button instead. return mMenuButton; } }