Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java |
| index aad64929e610ffe9f6c6f4fa709ff49f395705dd..12bcfc835c50f5f92d13a10c042849b18bc28bc0 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerView.java |
| @@ -6,14 +6,14 @@ package org.chromium.chrome.browser.banners; |
| import android.animation.ObjectAnimator; |
| import android.content.Context; |
| +import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.graphics.Point; |
| -import android.graphics.drawable.ClipDrawable; |
| -import android.graphics.drawable.Drawable; |
| +import android.graphics.Rect; |
| import android.util.AttributeSet; |
| -import android.view.Gravity; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| +import android.view.ViewGroup; |
| import android.widget.Button; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| @@ -35,20 +35,23 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| */ |
| public static interface Observer { |
| /** |
| - * Called when the BannerView is dismissed. |
| - * @param banner BannerView being dismissed. |
| + * Called when the banner is dismissed. |
| + * @param banner Banner being dismissed. |
| */ |
| public void onBannerDismissed(AppBannerView banner); |
| /** |
| - * Called when the button has been clicked. |
| - * @param banner BannerView firing the event. |
| + * Called when the install button has been clicked. |
| + * @param banner Banner firing the event. |
| */ |
| public void onButtonClicked(AppBannerView banner); |
| - } |
| - // Maximum number of stars in the rating. |
| - private static final int NUM_STARS = 5; |
| + /** |
| + * Called when something other than the button is clicked. |
| + * @param banner Banner firing the event. |
| + */ |
| + public void onBannerClicked(AppBannerView banner); |
| + } |
| // XML layout for the BannerView. |
| private static final int BANNER_LAYOUT = R.layout.app_banner_view; |
| @@ -56,21 +59,18 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| // True if the layout is in left-to-right layout mode (regular mode). |
| private final boolean mIsLayoutLTR; |
| - // Class to alert when the BannerView is dismissed. |
| + // Class to alert about BannerView events. |
| private Observer mObserver; |
|
newt (away)
2014/02/19 21:52:49
For clarity's sake, can you change this to:
p
gone
2014/02/19 23:31:43
Done.
|
| // Views comprising the app banner. |
| private ImageView mIconView; |
| private TextView mTitleView; |
| private Button mButtonView; |
| - private ImageView mRatingView; |
| + private RatingView mRatingView; |
| private ImageView mLogoView; |
| - private ClipDrawable mRatingClipperDrawable; |
| // Information about the package. |
| - private String mUrl; |
| - private String mPackageName; |
| - private float mAppRating; |
| + private AppData mAppData; |
| // Variables used during layout calculations and saved to avoid reallocations. |
| private final Point mSpaceMain; |
| @@ -78,21 +78,27 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| private final Point mSpaceForRating; |
| private final Point mSpaceForTitle; |
| + // Dimension values. |
| + private int mDefinedMaxWidth; |
| + private int mPaddingContent; |
| + private int mMarginSide; |
| + private int mMarginBottom; |
| + |
| + // Initial padding values. |
| + private final Rect mInitialPadding; |
| + |
| /** |
| * Creates a BannerView and adds it to the given ContentView. |
| - * @param contentView ContentView to display the BannerView for. |
| - * @param observer Class that is alerted for BannerView events. |
| - * @param icon Icon to display for the app. |
| - * @param title Title of the app. |
| - * @param rating Rating of the app. |
| - * @param buttonText Text to show on the button. |
| + * @param contentView ContentView to display the AppBannerView for. |
| + * @param observer Class that is alerted for AppBannerView events. |
| + * @param data Data about the app. |
| + * @return The created banner. |
| */ |
| - public static AppBannerView create(ContentView contentView, Observer observer, String url, |
| - String packageName, String title, Drawable icon, float rating, String buttonText) { |
| + public static AppBannerView create(ContentView contentView, Observer observer, AppData data) { |
|
newt (away)
2014/02/19 21:52:49
yay, shorter param list!
|
| Context context = contentView.getContext().getApplicationContext(); |
| AppBannerView banner = |
| (AppBannerView) LayoutInflater.from(context).inflate(BANNER_LAYOUT, null); |
| - banner.initialize(observer, url, packageName, title, icon, rating, buttonText); |
| + banner.initialize(observer, data); |
| banner.addToView(contentView); |
| return banner; |
| } |
| @@ -107,27 +113,56 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| mSpaceForLogo = new Point(); |
| mSpaceForRating = new Point(); |
| mSpaceForTitle = new Point(); |
| + |
| + // Store the Drawable's padding. |
|
newt (away)
2014/02/19 21:52:49
Huh? Which Drawable's padding?
gone
2014/02/19 23:31:43
Clarified.
newt (away)
2014/02/20 01:32:22
Ah, ha! It makes sense. Danke schoen!
|
| + mInitialPadding = new Rect(); |
| + mInitialPadding.left = getPaddingStart(); |
| + mInitialPadding.right = getPaddingEnd(); |
| + mInitialPadding.top = getPaddingTop(); |
| + mInitialPadding.bottom = getPaddingBottom(); |
| } |
| /** |
| * Initialize the banner with information about the package. |
| - * @param observer Class to alert about changes to the banner. |
| - * @param title Title of the package. |
| - * @param icon Icon for the package. |
| - * @param rating Play store rating for the package. |
| - * @param buttonText Text to show on the button. |
| + * @param observer Class to alert about changes to the banner. |
| + * @param data Information about the app being advertised. |
| */ |
| - private void initialize(Observer observer, String url, String packageName, |
| - String title, Drawable icon, float rating, String buttonText) { |
| + private void initialize(Observer observer, AppData data) { |
| mObserver = observer; |
| - mUrl = url; |
| - mPackageName = packageName; |
| + mAppData = data; |
| + initializeControls(); |
| + } |
| + |
| + private void initializeControls() { |
| + // Cache the banner dimensions, adjusting margins for drop shadows defined in the Drawable. |
|
newt (away)
2014/02/19 21:52:49
still confused :/ ... Which Drawable?
gone
2014/02/19 23:31:43
Explained up top.
|
| + // The Drawable is defined to have the same margin on both the left and right. |
| + Resources res = getResources(); |
| + mDefinedMaxWidth = res.getDimensionPixelSize(R.dimen.app_banner_max_width); |
| + mPaddingContent = res.getDimensionPixelSize(R.dimen.app_banner_padding_content); |
| + mMarginSide = res.getDimensionPixelSize(R.dimen.app_banner_margin_sides) |
| + - mInitialPadding.left; |
| + mMarginBottom = res.getDimensionPixelSize(R.dimen.app_banner_margin_bottom) |
| + - mInitialPadding.bottom; |
| + if (getLayoutParams() != null) { |
| + MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); |
| + params.leftMargin = mMarginSide; |
| + params.rightMargin = mMarginSide; |
| + params.bottomMargin = mMarginBottom; |
| + } |
| + |
| + // Add onto the padding defined by the Drawable's drop shadow. |
| + int padding = res.getDimensionPixelSize(R.dimen.app_banner_padding); |
| + int paddingStart = mInitialPadding.left + padding; |
| + int paddingTop = mInitialPadding.top + padding; |
| + int paddingEnd = mInitialPadding.right + padding; |
| + int paddingBottom = mInitialPadding.bottom + padding; |
| + setPadding(paddingStart, paddingTop, paddingEnd, paddingBottom); |
|
newt (away)
2014/02/19 21:52:49
Do you mean:
ApiCompatibilityUtils.setPadding
gone
2014/02/19 23:31:43
Done.
|
| // Pull out all of the controls we are expecting. |
| mIconView = (ImageView) findViewById(R.id.app_icon); |
| mTitleView = (TextView) findViewById(R.id.app_title); |
| mButtonView = (Button) findViewById(R.id.app_install_button); |
| - mRatingView = (ImageView) findViewById(R.id.app_rating); |
| + mRatingView = (RatingView) findViewById(R.id.app_rating); |
| mLogoView = (ImageView) findViewById(R.id.store_logo); |
| assert mIconView != null; |
| assert mTitleView != null; |
| @@ -139,33 +174,30 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| mButtonView.setOnClickListener(this); |
| // Configure the controls with the package information. |
| - mTitleView.setText(title); |
| - mIconView.setImageDrawable(icon); |
| - mAppRating = rating; |
| - mButtonView.setText(buttonText); |
| - initializeRatingView(); |
| - } |
| + mTitleView.setText(mAppData.title); |
| + mIconView.setImageDrawable(mAppData.icon); |
| + mRatingView.initialize(mAppData.rating); |
| - private void initializeRatingView() { |
| - // Set up the stars Drawable. |
| - Drawable ratingDrawable = getResources().getDrawable(R.drawable.app_banner_rating); |
| - mRatingClipperDrawable = |
| - new ClipDrawable(ratingDrawable, Gravity.START, ClipDrawable.HORIZONTAL); |
| - mRatingView.setImageDrawable(mRatingClipperDrawable); |
| - |
| - // Clips the ImageView for the ratings so that it shows an appropriate number of stars. |
| - // Ratings are rounded to the nearest 0.5 increment, like in the Play Store. |
| - float roundedRating = Math.round(mAppRating * 2) / 2.0f; |
| - float percentageRating = roundedRating / NUM_STARS; |
| - int clipLevel = (int) (percentageRating * 10000); |
| - mRatingClipperDrawable.setLevel(clipLevel); |
| + // Update the button state. |
| + updateButtonState(); |
| } |
| @Override |
| public void onClick(View view) { |
| - if (mObserver != null && view == mButtonView) { |
| - mObserver.onButtonClicked(this); |
| - } |
| + if (mObserver != null && view == mButtonView) mObserver.onButtonClicked(this); |
| + } |
| + |
| + @Override |
| + protected void onViewClicked() { |
| + if (mObserver != null) mObserver.onBannerClicked(this); |
| + } |
| + |
| + @Override |
| + protected ViewGroup.MarginLayoutParams createLayoutParams() { |
| + // Define the margin around the entire banner that accounts for the drop shadow. |
| + ViewGroup.MarginLayoutParams params = super.createLayoutParams(); |
| + params.setMargins(mMarginSide, 0, mMarginSide, mMarginBottom); |
| + return params; |
| } |
| /** |
| @@ -180,19 +212,41 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| } |
| /** |
| - * @return The URL that the banner was created for. |
| + * Returns data for the app the banner is being shown for. |
| + * @return The AppData being used by the banner. |
| */ |
| - String getUrl() { |
| - return mUrl; |
| + AppData getAppData() { |
|
newt (away)
2014/02/19 21:52:49
return a const reference:
const AppData& getA
gone
2014/02/19 23:31:43
Added TODO. (not really)
|
| + return mAppData; |
| } |
| /** |
| - * @return The package that the banner is displaying information for. |
| + * Updates the text and color of the button displayed on the button. |
| + * @param state Install state of the package. |
| */ |
| - String getPackageName() { |
| - return mPackageName; |
| + void updateButtonState() { |
| + if (mButtonView == null) return; |
| + |
| + int textStyle; |
| + int color; |
| + if (mAppData.installState == AppData.INSTALL_STATE_INSTALLED) { |
| + textStyle = R.style.AppBannerOpenButton; |
| + color = getContext().getResources().getColor(R.color.app_banner_open_button_bg); |
| + mButtonView.setText(R.string.app_banner_open); |
| + } else { |
| + textStyle = R.style.AppBannerInstallButton; |
| + color = getContext().getResources().getColor(R.color.app_banner_install_button_bg); |
| + if (mAppData.installState == AppData.INSTALL_STATE_NOT_INSTALLED) { |
| + mButtonView.setText(mAppData.installButtonText); |
|
newt (away)
2014/02/19 21:52:49
Can mAppData.installButtonText have different valu
gone
2014/02/19 23:31:43
It changes based on the app's price, as well. The
|
| + } else { |
| + mButtonView.setText(R.string.app_banner_installing); |
| + } |
| + } |
| + |
| + mButtonView.setTextAppearance(getContext(), textStyle); |
| + mButtonView.setBackgroundColor(color); |
| } |
| + |
|
newt (away)
2014/02/19 21:52:49
remove extra line
gone
2014/02/19 23:31:43
Done.
|
| /** |
| * Determine how big an icon needs to be for the Layout. |
| * @param context Context to grab resources from. |
| @@ -222,6 +276,33 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| setVisibility(INVISIBLE); |
| } |
| + @Override |
| + protected void onConfigurationChanged(Configuration config) { |
| + super.onConfigurationChanged(config); |
| + |
|
newt (away)
2014/02/19 21:52:49
I'd explain why you need to override onConfigurati
gone
2014/02/19 23:31:43
Done.
|
| + // If the card's maximum width hasn't changed, the individual views can't have, either. |
| + int newDefinedWidth = getResources().getDimensionPixelSize(R.dimen.app_banner_max_width); |
| + if (mDefinedMaxWidth == newDefinedWidth) return; |
| + |
| + // Cannibalize another version of this layout to get Views using the new resources. |
| + while (getChildCount() > 0) removeViewAt(0); |
| + mIconView = null; |
| + mTitleView = null; |
| + mButtonView = null; |
| + mRatingView = null; |
| + mLogoView = null; |
| + |
| + AppBannerView cannibalized = |
|
newt (away)
2014/02/19 21:52:49
A+ for variable naming
|
| + (AppBannerView) LayoutInflater.from(getContext()).inflate(BANNER_LAYOUT, null); |
| + while (cannibalized.getChildCount() > 0) { |
|
newt (away)
2014/02/19 21:52:49
Which child views depend on the screen size? Do yo
gone
2014/02/19 23:31:43
Pretty much all of them. The font size changes, t
|
| + View child = cannibalized.getChildAt(0); |
| + cannibalized.removeViewAt(0); |
| + addView(child); |
| + } |
| + initializeControls(); |
| + requestLayout(); |
| + } |
| + |
| /** |
| * Measurement for components of the banner are performed using the following procedure: |
| * |
| @@ -250,9 +331,8 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| Resources res = getResources(); |
| float density = res.getDisplayMetrics().density; |
| int screenSmallestWidth = (int) (res.getConfiguration().smallestScreenWidthDp * density); |
| - int definedMaxWidth = (int) res.getDimension(R.dimen.app_banner_max_width); |
| int specWidth = MeasureSpec.getSize(widthMeasureSpec); |
| - int maxWidth = Math.min(Math.min(specWidth, definedMaxWidth), screenSmallestWidth); |
| + int maxWidth = Math.min(Math.min(specWidth, mDefinedMaxWidth), screenSmallestWidth); |
| int maxHeight = MeasureSpec.getSize(heightMeasureSpec); |
| // Track how much space is available for the banner content. |
| @@ -265,6 +345,10 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| mSpaceMain.x -= getChildWidthWithMargins(mIconView); |
| mSpaceMain.y = getChildHeightWithMargins(mIconView) + getPaddingTop() + getPaddingBottom(); |
| + // Additional padding is defined by the mock for non-icon content on the end and bottom. |
| + mSpaceMain.x -= mPaddingContent; |
| + mSpaceMain.y -= mPaddingContent; |
| + |
| // Measure the install button, which sits in the bottom-right corner. |
| measureChildForSpace(mButtonView, mSpaceMain); |
| @@ -282,16 +366,8 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| mSpaceForTitle.x = mSpaceMain.x; |
| mSpaceForTitle.y = mSpaceMain.y - getChildHeightWithMargins(mLogoView) |
| - getChildHeightWithMargins(mRatingView); |
| - mTitleView.setMaxLines(2); |
| measureChildForSpace(mTitleView, mSpaceForTitle); |
| - // Ensure the text doesn't get cut in half through one of the lines. |
| - int requiredHeight = mTitleView.getLineHeight() * mTitleView.getLineCount(); |
| - if (getChildHeightWithMargins(mTitleView) < requiredHeight) { |
| - mTitleView.setMaxLines(1); |
| - measureChildForSpace(mTitleView, mSpaceForTitle); |
| - } |
| - |
| // Set the measured dimensions for the banner. |
| int measuredHeight = mIconView.getMeasuredHeight() + getPaddingTop() + getPaddingBottom(); |
| setMeasuredDimension(maxWidth, measuredHeight); |
| @@ -303,6 +379,8 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| */ |
| @Override |
| protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| + super.onLayout(changed, l, t, r, b); |
| + |
| int top = getPaddingTop(); |
| int bottom = getMeasuredHeight() - getPaddingBottom(); |
| int start = ApiCompatibilityUtils.getPaddingStart(this); |
| @@ -314,13 +392,22 @@ public class AppBannerView extends SwipableOverlayView implements View.OnClickLi |
| mIconView.layout(iconLeft, top, iconLeft + iconWidth, top + mIconView.getMeasuredHeight()); |
| start += getChildWidthWithMargins(mIconView); |
| - // Lay out the app title text. The TextView seems to internally account for its margins. |
| + // Factor in the additional padding. |
| + end -= mPaddingContent; |
| + bottom -= mPaddingContent; |
| + |
| + // Lay out the app title text. |
| int titleWidth = mTitleView.getMeasuredWidth(); |
| - int titleTop = top; |
| - int titleBottom = titleTop + getChildHeightWithMargins(mTitleView); |
| + 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); |
| - top += getChildHeightWithMargins(mTitleView); |
| + |
| + // The mock shows the margin eating into the descender area of the TextView. |
| + Rect bounds = new Rect(); |
|
newt (away)
2014/02/19 21:52:49
I bet android lint will complain about "new Rect()
gone
2014/02/19 23:31:43
Leftover, deleted.
|
| + int textBaseline = mTitleView.getLineBounds(mTitleView.getLineCount() - 1, bounds); |
| + top = titleTop + textBaseline |
| + + ((MarginLayoutParams) mTitleView.getLayoutParams()).bottomMargin; |
| // Lay out the app rating below the title. |
| int starWidth = mRatingView.getMeasuredWidth(); |