blob: 1d69784263efa16178ea49b1a3c238ff073f3f04 [file] [log] [blame]
// Copyright 2018 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.omnibox.status;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import android.view.View;
import org.chromium.chrome.R;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Contains the controller logic of the Status component.
*/
class StatusMediator {
private final PropertyModel mModel;
private boolean mDarkTheme;
private boolean mUrlHasFocus;
private boolean mVerboseStatusAllowed;
private boolean mVerboseStatusSpaceAvailable;
private boolean mPageIsPreview;
private boolean mPageIsOffline;
private int mUrlMinWidth;
private int mSeparatorMinWidth;
private int mVerboseStatusTextMinWidth;
private @DrawableRes int mSecurityIconRes;
private @DrawableRes int mSecurityIconTintRes;
private @StringRes int mSecurityIconDescriptionRes;
private @DrawableRes int mNavigationIconRes;
private @DrawableRes int mNavigationIconTintRes;
private boolean mTestingIsSecurityButtonShown;
StatusMediator(PropertyModel model) {
mModel = model;
}
/**
* Toggle animations of icon changes.
*/
void setAnimationsEnabled(boolean enabled) {
mModel.set(StatusProperties.ANIMATIONS_ENABLED, enabled);
}
/**
* Specify navigation button image type.
*/
void setNavigationButtonType(@DrawableRes int imageRes) {
mNavigationIconRes = imageRes;
updateLocationBarIcon();
}
/**
* Specify whether displayed page is an offline page.
*/
void setPageIsOffline(boolean pageIsOffline) {
if (mPageIsOffline != pageIsOffline) {
mPageIsOffline = pageIsOffline;
updateStatusVisibility();
updateColorTheme();
}
}
/**
* Specify whether displayed page is a preview page.
*/
void setPageIsPreview(boolean pageIsPreview) {
if (mPageIsPreview != pageIsPreview) {
mPageIsPreview = pageIsPreview;
updateStatusVisibility();
updateColorTheme();
}
}
/**
* Specify icon displayed by the security chip.
*/
void setSecurityIconResource(@DrawableRes int securityIcon) {
mSecurityIconRes = securityIcon;
updateLocationBarIcon();
}
/**
* Specify tint of icon displayed by the security chip.
*/
void setSecurityIconTint(@ColorRes int tintList) {
mSecurityIconTintRes = tintList;
updateLocationBarIcon();
}
/**
* Specify tint of icon displayed by the security chip.
*/
void setSecurityIconDescription(@StringRes int desc) {
mSecurityIconDescriptionRes = desc;
updateLocationBarIcon();
}
/**
* Specify minimum width of the separator field.
*/
void setSeparatorFieldMinWidth(int width) {
mSeparatorMinWidth = width;
}
/**
* Specify object to receive status click events.
*
* @param listener Specifies target object to receive events.
*/
void setStatusClickListener(View.OnClickListener listener) {
mModel.set(StatusProperties.STATUS_CLICK_LISTENER, listener);
}
/**
* Update unfocused location bar width to determine shape and content of the
* Status view.
*/
void setUnfocusedLocationBarWidth(int width) {
// This unfocused width is used rather than observing #onMeasure() to avoid showing the
// verbose status when the animation to unfocus the URL bar has finished. There is a call to
// LocationBarLayout#onMeasure() after the URL focus animation has finished and before the
// location bar has received its updated width layout param.
int computedSpace = width - mUrlMinWidth - mSeparatorMinWidth;
boolean hasSpaceForStatus = width >= mVerboseStatusTextMinWidth;
if (hasSpaceForStatus) {
mModel.set(StatusProperties.VERBOSE_STATUS_TEXT_WIDTH, computedSpace);
}
if (hasSpaceForStatus != mVerboseStatusSpaceAvailable) {
mVerboseStatusSpaceAvailable = hasSpaceForStatus;
updateStatusVisibility();
}
}
/**
* Report URL focus change.
*/
void setUrlHasFocus(boolean urlHasFocus) {
if (mUrlHasFocus == urlHasFocus) return;
mUrlHasFocus = urlHasFocus;
updateStatusVisibility();
updateLocationBarIcon();
}
/**
* Specify minimum width of an URL field.
*/
void setUrlMinWidth(int width) {
mUrlMinWidth = width;
}
/**
* Toggle between dark and light UI color theme.
*/
void setUseDarkColors(boolean useDarkColors) {
if (mDarkTheme != useDarkColors) {
mDarkTheme = useDarkColors;
updateColorTheme();
}
}
/**
* Specify whether parent allows verbose status text.
*/
void setVerboseStatusTextAllowed(boolean isVerboseStatusTextAllowed) {
mVerboseStatusAllowed = isVerboseStatusTextAllowed;
updateStatusVisibility();
}
/**
* Specify minimum width of the verbose status text field.
*/
void setVerboseStatusTextMinWidth(int width) {
mVerboseStatusTextMinWidth = width;
}
/**
* Update visibility of the verbose status text field.
*/
private void updateStatusVisibility() {
@StringRes
int statusText = 0;
if (mPageIsPreview) {
statusText = R.string.location_bar_preview_lite_page_status;
} else if (mPageIsOffline) {
statusText = R.string.location_bar_verbose_status_offline;
}
// Decide whether presenting verbose status text makes sense.
boolean newVisibility = mVerboseStatusAllowed && mVerboseStatusSpaceAvailable
&& (!mUrlHasFocus) && (statusText != 0);
// Update status content only if it is visible.
// Note: PropertyModel will help us avoid duplicate updates with the
// same value.
if (newVisibility) {
mModel.set(StatusProperties.VERBOSE_STATUS_TEXT_STRING_RES, statusText);
}
mModel.set(StatusProperties.VERBOSE_STATUS_TEXT_VISIBLE, newVisibility);
}
/**
* Update color theme for all status components.
*/
private void updateColorTheme() {
@ColorRes
int separatorColor = mDarkTheme ? R.color.locationbar_status_separator_color
: R.color.locationbar_status_separator_color_light;
@ColorRes
int textColor = 0;
if (mPageIsPreview) {
// There will never be a Preview in Incognito and the site theme color is not used. So
// ignore useDarkColors.
textColor = R.color.locationbar_status_preview_color;
} else if (mPageIsOffline) {
textColor = mDarkTheme ? R.color.locationbar_status_offline_color
: R.color.locationbar_status_offline_color_light;
}
@ColorRes
int tintColor = mDarkTheme ? R.color.dark_mode_tint : R.color.light_mode_tint;
mModel.set(StatusProperties.SEPARATOR_COLOR_RES, separatorColor);
mNavigationIconTintRes = tintColor;
if (textColor != 0) mModel.set(StatusProperties.VERBOSE_STATUS_TEXT_COLOR_RES, textColor);
updateLocationBarIcon();
}
/**
* Reports whether security icon is shown.
*/
boolean testIsSecurityButtonShown() {
return mTestingIsSecurityButtonShown;
}
/**
* Update selection of icon presented on the location bar.
*
* - Navigation button is:
* - shown only on large form factor devices (tablets and up),
* - shown only if URL is focused.
*
* - Security icon is:
* - shown only if specified,
* - not shown if URL is focused.
*/
private void updateLocationBarIcon() {
if (mUrlHasFocus) {
mModel.set(StatusProperties.STATUS_ICON_RES, mNavigationIconRes);
mModel.set(StatusProperties.STATUS_ICON_TINT_RES, mNavigationIconTintRes);
mModel.set(StatusProperties.STATUS_ICON_DESCRIPTION_RES,
R.string.accessibility_toolbar_btn_site_info);
mModel.set(StatusProperties.STATUS_ICON_ACCESSIBILITY_TOAST_RES, 0);
mTestingIsSecurityButtonShown = false;
return;
}
if (!mUrlHasFocus && mSecurityIconRes != 0) {
mModel.set(StatusProperties.STATUS_ICON_RES, mSecurityIconRes);
mModel.set(StatusProperties.STATUS_ICON_TINT_RES, mSecurityIconTintRes);
mModel.set(StatusProperties.STATUS_ICON_DESCRIPTION_RES, mSecurityIconDescriptionRes);
mModel.set(
StatusProperties.STATUS_ICON_ACCESSIBILITY_TOAST_RES, R.string.menu_page_info);
mTestingIsSecurityButtonShown = true;
return;
}
mTestingIsSecurityButtonShown = false;
mModel.set(StatusProperties.STATUS_ICON_RES, 0);
}
}