This source file includes following definitions.
- onBannerRemoved
- onBannerBlocked
- onBannerDismissEvent
- onBannerInstallEvent
- onFireIntent
- create
- initialize
- initializeControls
- setAccessibilityInformation
- onClick
- onViewSwipedAway
- onViewClicked
- onViewPressed
- onIntentCompleted
- onInstallFinished
- createLayoutParams
- removeFromParent
- dismiss
- destroy
- updateButtonAppearance
- getIconSize
- onTouchEvent
- onAttachedToWindow
- onDetachedFromWindow
- onConfigurationChanged
- onMeasure
- onLayout
- measureChildForSpace
- measureChildForSpaceExactly
- getMarginWidth
- getWidthWithMargins
- getMarginHeight
- getHeightWithMargins
package org.chromium.chrome.browser.banners;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.content.browser.ContentView;
import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.base.WindowAndroid.IntentCallback;
public class AppBannerView extends SwipableOverlayView
implements View.OnClickListener, InstallerDelegate.Observer, IntentCallback {
private static final String TAG = "AppBannerView";
public static interface Observer {
public void onBannerRemoved(AppBannerView banner);
public void onBannerBlocked(AppBannerView banner, String url, String packageName);
public void onBannerDismissEvent(AppBannerView banner, int dismissType);
public void onBannerInstallEvent(AppBannerView banner, int eventType);
public boolean onFireIntent(AppBannerView banner, PendingIntent intent);
}
private static final int INSTALL_STATE_NOT_INSTALLED = 0;
private static final int INSTALL_STATE_INSTALLING = 1;
private static final int INSTALL_STATE_INSTALLED = 2;
private static final int BANNER_LAYOUT = R.layout.app_banner_view;
private final boolean mIsLayoutLTR;
private AppBannerView.Observer mObserver;
private AppData mAppData;
private ImageView mIconView;
private TextView mTitleView;
private Button mInstallButtonView;
private RatingView mRatingView;
private View mLogoView;
private View mBannerHighlightView;
private ImageButton mCloseButtonView;
private int mDefinedMaxWidth;
private int mPaddingCard;
private int mPaddingControls;
private int mMarginLeft;
private int mMarginRight;
private int mMarginBottom;
private int mTouchSlop;
private boolean mIsBannerPressed;
private float mInitialXForHighlight;
private final Rect mBackgroundDrawablePadding;
private boolean mWasInstallDialogShown;
private InstallerDelegate mInstallTask;
private int mInstallState;
public static AppBannerView create(ContentView contentView, Observer observer, AppData data) {
Context context = contentView.getContext().getApplicationContext();
AppBannerView banner =
(AppBannerView) LayoutInflater.from(context).inflate(BANNER_LAYOUT, null);
banner.initialize(observer, data);
banner.addToView(contentView);
return banner;
}
public AppBannerView(Context context, AttributeSet attrs) {
super(context, attrs);
mIsLayoutLTR = !LocalizationUtils.isLayoutRtl();
mBackgroundDrawablePadding = new Rect();
mBackgroundDrawablePadding.left = ApiCompatibilityUtils.getPaddingStart(this);
mBackgroundDrawablePadding.right = ApiCompatibilityUtils.getPaddingEnd(this);
mBackgroundDrawablePadding.top = getPaddingTop();
mBackgroundDrawablePadding.bottom = getPaddingBottom();
mInstallState = INSTALL_STATE_NOT_INSTALLED;
}
private void initialize(Observer observer, AppData data) {
mObserver = observer;
mAppData = data;
initializeControls();
}
private void initializeControls() {
Resources res = getResources();
mDefinedMaxWidth = res.getDimensionPixelSize(R.dimen.app_banner_max_width);
mPaddingCard = res.getDimensionPixelSize(R.dimen.app_banner_padding);
mPaddingControls = res.getDimensionPixelSize(R.dimen.app_banner_padding_controls);
mMarginLeft = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides)
- mBackgroundDrawablePadding.left;
mMarginRight = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides)
- mBackgroundDrawablePadding.right;
mMarginBottom = res.getDimensionPixelSize(R.dimen.app_banner_margin_bottom)
- mBackgroundDrawablePadding.bottom;
if (getLayoutParams() != null) {
MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
params.leftMargin = mMarginLeft;
params.rightMargin = mMarginRight;
params.bottomMargin = mMarginBottom;
}
mIconView = (ImageView) findViewById(R.id.app_icon);
mTitleView = (TextView) findViewById(R.id.app_title);
mInstallButtonView = (Button) findViewById(R.id.app_install_button);
mRatingView = (RatingView) findViewById(R.id.app_rating);
mLogoView = findViewById(R.id.store_logo);
mBannerHighlightView = findViewById(R.id.banner_highlight);
mCloseButtonView = (ImageButton) findViewById(R.id.close_button);
assert mIconView != null;
assert mTitleView != null;
assert mInstallButtonView != null;
assert mLogoView != null;
assert mRatingView != null;
assert mBannerHighlightView != null;
assert mCloseButtonView != null;
mInstallButtonView.setOnClickListener(this);
mCloseButtonView.setOnClickListener(this);
mTitleView.setText(mAppData.title());
mIconView.setImageDrawable(mAppData.icon());
mRatingView.initialize(mAppData.rating());
setAccessibilityInformation();
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
updateButtonAppearance();
}
private void setAccessibilityInformation() {
String bannerText = getContext().getString(
R.string.app_banner_view_accessibility, mAppData.title(), mAppData.rating());
setContentDescription(bannerText);
}
@Override
public void onClick(View view) {
if (mObserver == null) return;
if (Math.abs(getTranslationX()) > ZERO_THRESHOLD
|| Math.abs(getTranslationY()) > ZERO_THRESHOLD) {
return;
}
if (view == mInstallButtonView) {
if (mInstallState == INSTALL_STATE_INSTALLING) return;
mInstallButtonView.setEnabled(false);
if (mInstallState == INSTALL_STATE_NOT_INSTALLED) {
if (!mWasInstallDialogShown) {
mObserver.onBannerInstallEvent(this, AppBannerMetricsIds.INSTALL_TRIGGERED);
mWasInstallDialogShown = true;
}
if (mObserver.onFireIntent(this, mAppData.installIntent())) {
createVerticalSnapAnimation(false);
} else {
Log.e(TAG, "Failed to fire install intent.");
dismiss(AppBannerMetricsIds.DISMISS_ERROR);
}
} else if (mInstallState == INSTALL_STATE_INSTALLED) {
String packageName = mAppData.packageName();
PackageManager packageManager = getContext().getPackageManager();
Intent appIntent = packageManager.getLaunchIntentForPackage(packageName);
try {
getContext().startActivity(appIntent);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Failed to find app package: " + packageName);
}
dismiss(AppBannerMetricsIds.DISMISS_APP_OPEN);
}
} else if (view == mCloseButtonView) {
if (mObserver != null) {
mObserver.onBannerBlocked(this, mAppData.siteUrl(), mAppData.packageName());
}
dismiss(AppBannerMetricsIds.DISMISS_CLOSE_BUTTON);
}
}
@Override
protected void onViewSwipedAway() {
if (mObserver == null) return;
mObserver.onBannerDismissEvent(this, AppBannerMetricsIds.DISMISS_BANNER_SWIPE);
mObserver.onBannerBlocked(this, mAppData.siteUrl(), mAppData.packageName());
}
@Override
protected void onViewClicked() {
try {
IntentSender sender = mAppData.detailsIntent().getIntentSender();
getContext().startIntentSender(sender, new Intent(), 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Failed to launch details intent.");
}
dismiss(AppBannerMetricsIds.DISMISS_BANNER_CLICK);
}
@Override
protected void onViewPressed(MotionEvent event) {
mInitialXForHighlight = event.getRawX();
mIsBannerPressed = true;
mBannerHighlightView.setVisibility(View.VISIBLE);
}
@Override
public void onIntentCompleted(WindowAndroid window, int resultCode,
ContentResolver contentResolver, Intent data) {
if (isDismissed()) return;
createVerticalSnapAnimation(true);
if (resultCode == Activity.RESULT_OK) {
mObserver.onBannerInstallEvent(this, AppBannerMetricsIds.INSTALL_STARTED);
PackageManager pm = getContext().getPackageManager();
mInstallTask =
new InstallerDelegate(Looper.getMainLooper(), pm, this, mAppData.packageName());
mInstallTask.start();
mInstallState = INSTALL_STATE_INSTALLING;
}
updateButtonAppearance();
}
@Override
public void onInstallFinished(InstallerDelegate monitor, boolean success) {
if (isDismissed() || mInstallTask != monitor) return;
if (success) {
mObserver.onBannerInstallEvent(this, AppBannerMetricsIds.INSTALL_COMPLETED);
mInstallState = INSTALL_STATE_INSTALLED;
updateButtonAppearance();
} else {
dismiss(AppBannerMetricsIds.DISMISS_INSTALL_TIMEOUT);
}
}
@Override
protected ViewGroup.MarginLayoutParams createLayoutParams() {
ViewGroup.MarginLayoutParams params = super.createLayoutParams();
params.setMargins(mMarginLeft, 0, mMarginRight, mMarginBottom);
return params;
}
@Override
boolean removeFromParent() {
if (super.removeFromParent()) {
mObserver.onBannerRemoved(this);
destroy();
return true;
}
return false;
}
public void dismiss(int eventType) {
if (isDismissed() || mObserver == null) return;
dismiss(eventType == AppBannerMetricsIds.DISMISS_CLOSE_BUTTON);
mObserver.onBannerDismissEvent(this, eventType);
}
public void destroy() {
if (!isDismissed()) dismiss(AppBannerMetricsIds.DISMISS_ERROR);
if (mInstallTask != null) {
mInstallTask.cancel();
mInstallTask = null;
}
}
void updateButtonAppearance() {
if (mInstallButtonView == null) return;
Resources res = getResources();
int fgColor;
String text;
if (mInstallState == INSTALL_STATE_INSTALLED) {
ApiCompatibilityUtils.setBackgroundForView(mInstallButtonView,
res.getDrawable(R.drawable.app_banner_button_open));
fgColor = res.getColor(R.color.app_banner_open_button_fg);
text = res.getString(R.string.app_banner_open);
} else {
ApiCompatibilityUtils.setBackgroundForView(mInstallButtonView,
res.getDrawable(R.drawable.app_banner_button_install));
fgColor = res.getColor(R.color.app_banner_install_button_fg);
if (mInstallState == INSTALL_STATE_NOT_INSTALLED) {
text = mAppData.installButtonText();
mInstallButtonView.setContentDescription(
getContext().getString(R.string.app_banner_install_accessibility, text));
} else {
text = res.getString(R.string.app_banner_installing);
}
}
mInstallButtonView.setTextColor(fgColor);
mInstallButtonView.setText(text);
mInstallButtonView.setEnabled(mInstallState != INSTALL_STATE_INSTALLING);
}
static int getIconSize(Context context) {
return context.getResources().getDimensionPixelSize(R.dimen.app_banner_icon_size);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if (mIsBannerPressed) {
float xDifference = Math.abs(event.getRawX() - mInitialXForHighlight);
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
|| (action == MotionEvent.ACTION_MOVE && xDifference > mTouchSlop)) {
mIsBannerPressed = false;
mBannerHighlightView.setVisibility(View.INVISIBLE);
}
}
return super.onTouchEvent(event);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ObjectAnimator.ofFloat(this, "alpha", getAlpha(), 1.f).setDuration(
MS_ANIMATION_DURATION).start();
setVisibility(VISIBLE);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
setAlpha(0.0f);
setVisibility(INVISIBLE);
}
@Override
protected void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
if (isDismissed()) return;
int newDefinedWidth = getResources().getDimensionPixelSize(R.dimen.app_banner_max_width);
if (mDefinedMaxWidth == newDefinedWidth) return;
while (getChildCount() > 0) removeViewAt(0);
mIconView = null;
mTitleView = null;
mInstallButtonView = null;
mRatingView = null;
mLogoView = null;
mBannerHighlightView = null;
AppBannerView cannibalized =
(AppBannerView) LayoutInflater.from(getContext()).inflate(BANNER_LAYOUT, null);
while (cannibalized.getChildCount() > 0) {
View child = cannibalized.getChildAt(0);
cannibalized.removeViewAt(0);
addView(child);
}
initializeControls();
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Resources res = getResources();
float density = res.getDisplayMetrics().density;
int screenSmallestWidth = (int) (res.getConfiguration().smallestScreenWidthDp * density);
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int bannerWidth = Math.min(Math.min(specWidth, mDefinedMaxWidth), screenSmallestWidth);
int bgPaddingWidth = mBackgroundDrawablePadding.left + mBackgroundDrawablePadding.right;
int bgPaddingHeight = mBackgroundDrawablePadding.top + mBackgroundDrawablePadding.bottom;
final int maxControlWidth = bannerWidth - bgPaddingWidth - (mPaddingCard * 2);
int specHeight = MeasureSpec.getSize(heightMeasureSpec);
int reasonableHeight = maxControlWidth / 4;
int paddingHeight = bgPaddingHeight + (mPaddingCard * 2);
final int maxControlHeight = Math.min(specHeight, reasonableHeight) - paddingHeight;
final int maxStackedControlHeight = maxControlWidth / 3;
measureChildForSpace(mIconView, maxControlWidth, maxControlHeight);
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i) != mIconView) {
measureChildForSpace(getChildAt(i), maxControlWidth, maxStackedControlHeight);
}
}
int iconStackHeight = getHeightWithMargins(mIconView);
int logoStackHeight = getHeightWithMargins(mTitleView) + mPaddingControls
+ getHeightWithMargins(mRatingView) + getHeightWithMargins(mLogoView);
int buttonStackHeight = getHeightWithMargins(mTitleView) + mPaddingControls
+ getHeightWithMargins(mInstallButtonView);
int biggestStackHeight =
Math.max(iconStackHeight, Math.max(logoStackHeight, buttonStackHeight));
final int iconSize = biggestStackHeight;
measureChildForSpaceExactly(mIconView, iconSize, iconSize);
final int contentWidth =
maxControlWidth - getWidthWithMargins(mIconView) - mPaddingControls;
final int contentHeight = biggestStackHeight - mPaddingControls;
measureChildForSpace(mInstallButtonView, contentWidth, contentHeight);
measureChildForSpace(mLogoView, contentWidth, contentHeight);
final int ratingWidth = contentWidth;
final int ratingHeight = contentHeight - getHeightWithMargins(mLogoView);
measureChildForSpace(mRatingView, ratingWidth, ratingHeight);
final int closeWidth = contentWidth;
final int closeHeight = contentHeight - getHeightWithMargins(mInstallButtonView);
measureChildForSpace(mCloseButtonView, closeWidth, closeHeight);
int biggerStack = Math.max(getHeightWithMargins(mInstallButtonView),
getHeightWithMargins(mLogoView) + getHeightWithMargins(mRatingView));
final int titleWidth = contentWidth - getWidthWithMargins(mCloseButtonView) + mPaddingCard;
final int titleHeight = contentHeight - biggerStack;
measureChildForSpace(mTitleView, titleWidth, titleHeight);
int bannerPadding = mBackgroundDrawablePadding.top + mBackgroundDrawablePadding.bottom
+ (mPaddingCard * 2);
int bannerHeight = biggestStackHeight + bannerPadding;
setMeasuredDimension(bannerWidth, bannerHeight);
final int cardWidth = bannerWidth - bgPaddingWidth;
final int cardHeight = bannerHeight - bgPaddingHeight;
measureChildForSpaceExactly(mBannerHighlightView, cardWidth, cardHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int top = mBackgroundDrawablePadding.top;
int bottom = getMeasuredHeight() - mBackgroundDrawablePadding.bottom;
int start = mBackgroundDrawablePadding.left;
int end = getMeasuredWidth() - mBackgroundDrawablePadding.right;
mBannerHighlightView.layout(start, top, end, bottom);
if (mCloseButtonView.getVisibility() == VISIBLE) {
int closeWidth = mCloseButtonView.getMeasuredWidth();
int closeTop =
top + ((MarginLayoutParams) mCloseButtonView.getLayoutParams()).topMargin;
int closeBottom = closeTop + mCloseButtonView.getMeasuredHeight();
int closeRight = mIsLayoutLTR ? end : (getMeasuredWidth() - end + closeWidth);
int closeLeft = closeRight - closeWidth;
mCloseButtonView.layout(closeLeft, closeTop, closeRight, closeBottom);
}
top += mPaddingCard;
bottom -= mPaddingCard;
start += mPaddingCard;
end -= mPaddingCard;
int iconWidth = mIconView.getMeasuredWidth();
int iconLeft = mIsLayoutLTR ? start : (getMeasuredWidth() - start - iconWidth);
mIconView.layout(iconLeft, top, iconLeft + iconWidth, top + mIconView.getMeasuredHeight());
start += getWidthWithMargins(mIconView);
end -= mPaddingControls;
bottom -= mPaddingControls;
int titleWidth = mTitleView.getMeasuredWidth();
int titleTop = top + ((MarginLayoutParams) mTitleView.getLayoutParams()).topMargin;
int titleBottom = titleTop + mTitleView.getMeasuredHeight();
int titleLeft = mIsLayoutLTR ? start : (getMeasuredWidth() - start - titleWidth);
mTitleView.layout(titleLeft, titleTop, titleLeft + titleWidth, titleBottom);
int textBaseline = mTitleView.getLineBounds(mTitleView.getLineCount() - 1, null);
top = titleTop + textBaseline
+ ((MarginLayoutParams) mTitleView.getLayoutParams()).bottomMargin;
int starWidth = mRatingView.getMeasuredWidth();
int starTop = top + ((MarginLayoutParams) mRatingView.getLayoutParams()).topMargin;
int starBottom = starTop + mRatingView.getMeasuredHeight();
int starLeft = mIsLayoutLTR ? start : (getMeasuredWidth() - start - starWidth);
mRatingView.layout(starLeft, starTop, starLeft + starWidth, starBottom);
int logoWidth = mLogoView.getMeasuredWidth();
int logoBottom = bottom - ((MarginLayoutParams) mLogoView.getLayoutParams()).bottomMargin;
int logoTop = logoBottom - mLogoView.getMeasuredHeight();
int logoLeft = mIsLayoutLTR ? start : (getMeasuredWidth() - start - logoWidth);
mLogoView.layout(logoLeft, logoTop, logoLeft + logoWidth, logoBottom);
int buttonHeight = mInstallButtonView.getMeasuredHeight();
int buttonWidth = mInstallButtonView.getMeasuredWidth();
int buttonRight = mIsLayoutLTR ? end : (getMeasuredWidth() - end + buttonWidth);
int buttonLeft = buttonRight - buttonWidth;
mInstallButtonView.layout(buttonLeft, bottom - buttonHeight, buttonRight, bottom);
}
private void measureChildForSpace(View child, int availableWidth, int availableHeight) {
availableWidth -= getMarginWidth(child);
availableHeight -= getMarginHeight(child);
int childWidth = child.getLayoutParams().width;
int childHeight = child.getLayoutParams().height;
if (childWidth >= 0) availableWidth = Math.min(availableWidth, childWidth);
if (childHeight >= 0) availableHeight = Math.min(availableHeight, childHeight);
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
int heightSpec = MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.AT_MOST);
child.measure(widthSpec, heightSpec);
}
private void measureChildForSpaceExactly(View child, int availableWidth, int availableHeight) {
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.EXACTLY);
child.measure(widthSpec, heightSpec);
}
private static int getMarginWidth(View view) {
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
return params.leftMargin + params.rightMargin;
}
private static int getWidthWithMargins(View view) {
return view.getMeasuredWidth() + getMarginWidth(view);
}
private static int getMarginHeight(View view) {
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
return params.topMargin + params.bottomMargin;
}
private static int getHeightWithMargins(View view) {
return view.getMeasuredHeight() + getMarginHeight(view);
}
}