blob: e3751dab936672811e9a9b3e1d920641afd82dba [file] [log] [blame]
// Copyright (c) 2013 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.autofill;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.NUM_SECTIONS;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.SECTION_BILLING;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.SECTION_CC;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.SECTION_CC_BILLING;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.SECTION_EMAIL;
import static org.chromium.chrome.browser.autofill.AutofillDialogConstants.SECTION_SHIPPING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Property;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import org.chromium.chrome.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This is the parent layout that contains the layouts for different states of
* autofill dialog. In principle it shouldn't contain any logic related with the
* actual workflow, but rather respond to any UI update messages coming to it
* from the AutofillDialog.
*/
public class AutofillDialogView extends FrameLayout {
private static final int ANIMATION_DURATION_MS = 600;
static final int INVALID_LAYOUT = -1;
static final int LAYOUT_EDITING_EMAIL = 0;
static final int LAYOUT_EDITING_SHIPPING = 1;
static final int LAYOUT_EDITING_CC = 2;
static final int LAYOUT_EDITING_BILLING = 3;
static final int LAYOUT_EDITING_CC_BILLING = 4;
static final int LAYOUT_FETCHING = 5;
static final int LAYOUT_STEADY = 6;
private final Runnable mDismissSteadyLayoutRunnable = new Runnable() {
@Override
public void run() {
mSteadyLayout.setVisibility(GONE);
}
};
private final Property<AutofillDialogView, Float> mContentPropertyHeight =
new Property<AutofillDialogView, Float>(Float.class, "") {
@Override
public Float get(AutofillDialogView view) {
return view.getVisibleContentHeight();
}
@Override
public void set(AutofillDialogView view, Float height) {
view.setVisibleContentHeight(height);
}
};
private AutofillDialog mDialog;
private Spinner[] mSpinners = new Spinner[NUM_SECTIONS];
private AutofillDialogMenuAdapter[] mAdapters = new AutofillDialogMenuAdapter[NUM_SECTIONS];
private ViewGroup mSteadyLayout;
private ViewGroup[] mEditLayouts = new ViewGroup[NUM_SECTIONS];
private int mCurrentLayout = -1;
private OnItemSelectedListener mOnItemSelectedListener;
private OnItemEditButtonClickedListener mOnItemEditButtonClickedListener;
private View mTitle;
private View mContent;
private View mFooter;
private boolean mTransitionAnimationPlaying;
private float mVisibleContentHeight;
private ObjectAnimator mCurrentHeightAnimator;
private AnimationSet mCurrentLayoutAnimation;
private Drawable mBackground = new ColorDrawable(Color.LTGRAY);
private boolean mAnimateOnNextLayoutChange = false;
private int mCurrentOrientation;
private int mFrameHeight;
private int mFrameWidth;
/**
* Interface definition for a callback to be invoked when an "Edit" button
* in the AutofillDialogMenuAdapter is clicked.
*/
public interface OnItemEditButtonClickedListener {
/**
* Callback method to be invoked when an "Edit" button has been clicked.
* @param section The dialog section associated with the adapter.
* @param position The position of the view in the adapter
*/
void onItemEditButtonClicked(int section, int position);
}
public AutofillDialogView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
}
@Override
protected void onFinishInflate () {
mSteadyLayout = (ViewGroup) findViewById(R.id.general_layout);
mTitle = findViewById(R.id.title);
mContent = findViewById(R.id.content);
mFooter = findViewById(R.id.footer);
for (int i = 0; i < AutofillDialogConstants.NUM_SECTIONS; i++) {
mEditLayouts[i] = (ViewGroup) findViewById(
AutofillDialogUtils.getLayoutIDForSection(i));
int id = AutofillDialogUtils.getSpinnerIDForSection(i);
mSpinners[i] = (Spinner) findViewById(id);
}
int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
for (int i = 0; i < NUM_SECTIONS; i++) {
(mEditLayouts[i]).measure(spec, spec);
}
findViewById(R.id.loading_icon).measure(spec, spec);
mContent.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (mAnimateOnNextLayoutChange && mCurrentHeightAnimator != null
&& !mCurrentHeightAnimator.isStarted()) {
mCurrentHeightAnimator.start();
mAnimateOnNextLayoutChange = false;
if (mCurrentLayoutAnimation != null && !mCurrentLayoutAnimation.hasStarted()) {
mCurrentLayoutAnimation.start();
}
}
}
});
mVisibleContentHeight = getAdjustedContentLayoutHeight(LAYOUT_FETCHING, null);
changeLayoutTo(LAYOUT_FETCHING);
}
/**
* Sets the controller dialog for this content view and initializes the view.
* @param dialog The autofill Dialog that should be set as the controller.
*/
public void initialize(AutofillDialog dialog) {
mDialog = dialog;
mDialog.getWindow().getDecorView().setBackgroundResource(0);
FrameLayout.LayoutParams layoutParams =
(android.widget.FrameLayout.LayoutParams) getLayoutParams();
mCurrentOrientation = getResources().getConfiguration().orientation;
mFrameHeight = getResources().getDimensionPixelSize(R.dimen.autofill_dialog_max_height);
layoutParams.height = mFrameHeight;
mFrameWidth = getResources().getDimensionPixelSize(R.dimen.autofill_dialog_width);
layoutParams.width = mFrameWidth;
requestLayout();
}
@Override
protected void onConfigurationChanged (Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mCurrentOrientation == newConfig.orientation) return;
mCurrentOrientation = newConfig.orientation;
FrameLayout.LayoutParams layoutParams =
(android.widget.FrameLayout.LayoutParams) getLayoutParams();
mFrameHeight = getResources().getDimensionPixelSize(R.dimen.autofill_dialog_max_height);
layoutParams.height = mFrameHeight;
requestLayout();
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (!mTransitionAnimationPlaying || child.getId() != R.id.content) {
return super.drawChild(canvas, child, drawingTime);
}
float top = mContent.getTop() + getTranslationForHiddenContentHeight();
float bottom = mContent.getBottom() - getTranslationForHiddenContentHeight();
canvas.save();
canvas.clipRect(getLeft(), top, getRight(), bottom);
boolean result = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return result;
}
@Override
public void onDraw(Canvas canvas) {
if (mTransitionAnimationPlaying) {
mTitle.setTranslationY(getTranslationForHiddenContentHeight());
mContent.setTranslationY(getTranslationForHiddenContentHeight());
mFooter.setTranslationY(-getTranslationForHiddenContentHeight());
}
canvas.save();
mBackground.setBounds(getLeft() ,(int) (mTitle.getTop() + mTitle.getTranslationY()),
getRight(),(int) (mFooter.getBottom() + mFooter.getTranslationY()));
mBackground.draw(canvas);
canvas.restore();
super.onDraw(canvas);
}
/**
* Prompts the content view to create the adapters for each section. This is
* separated to be able to control the timing in a flexible manner.
*/
public void createAdapters() {
for (int i = 0; i < AutofillDialogConstants.NUM_SECTIONS; i++) {
AutofillDialogMenuAdapter adapter =
new AutofillDialogMenuAdapter(i, getContext(),
new ArrayList<AutofillDialogMenuItem>());
adapter.setOnItemEditButtonClickedListener(mOnItemEditButtonClickedListener);
mAdapters[i] = adapter;
mSpinners[i].setAdapter(adapter);
}
initializeSpinner(SECTION_SHIPPING, AutofillDialogConstants.ADDRESS_HOME_COUNTRY);
initializeSpinner(SECTION_BILLING, AutofillDialogConstants.ADDRESS_BILLING_COUNTRY);
initializeSpinner(SECTION_CC, AutofillDialogConstants.CREDIT_CARD_EXP_MONTH);
initializeSpinner(SECTION_CC, AutofillDialogConstants.CREDIT_CARD_EXP_4_DIGIT_YEAR);
}
private void initializeSpinner(int section, int field) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
R.layout.autofill_editing_spinner_item);
adapter.addAll(Arrays.asList(mDialog.getListForField(field)));
((Spinner) findViewById(AutofillDialogUtils
.getViewIDForField(section, field))).setAdapter(adapter);
}
/**
* Initializes the labels for each section.
* @param labels The label strings to be used for each section.
*/
public void initializeLabelsForEachSection(String[] labels) {
TextView labelView;
for (int i = 0; i < labels.length && i < NUM_SECTIONS; i++) {
labelView = (TextView) findViewById(AutofillDialogUtils.getLabelIDForSection(i));
labelView.setText(labels[i]);
}
}
private int getMeasuredTitleHeight() {
return mTitle.getMeasuredHeight();
}
private int getMeasuredFooterHeight() {
return mFooter.getMeasuredHeight();
}
private float getTranslationForHiddenContentHeight() {
return (mContent.getMeasuredHeight() - mVisibleContentHeight) / 2;
}
private int getAdjustedContentLayoutHeight(int mode, View layout) {
assert mode != INVALID_LAYOUT;
int measuredContentHeight;
if (mode == LAYOUT_STEADY) {
measuredContentHeight = mSteadyLayout.getMeasuredHeight();
} else if (mode == LAYOUT_FETCHING) {
measuredContentHeight = findViewById(R.id.loading_icon).getMeasuredHeight();
} else {
if (mode == LAYOUT_EDITING_CC_BILLING) {
// For CC_BILLING we have to measure again since it contains both CC and
// BILLING also. The last measure may be for just one of them.
// TODO(yusufo): Do this if the mode that was measured before is wrong.
int widthSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
layout.measure(widthSpec, heightSpec);
}
measuredContentHeight = layout.getMeasuredHeight();
}
return Math.min(measuredContentHeight,
getMeasuredHeight() - getMeasuredTitleHeight() - getMeasuredFooterHeight());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// When the new layout height is higher than the old one in a transition, we end up with a
// a nonzero translation value at the end of the animation, since we set translations only
// while we are animating we set them back to zero here on a measure.
mTitle.setTranslationY(0);
mContent.setTranslationY(0);
mFooter.setTranslationY(0);
Rect outRect = new Rect();
mDialog.getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect);
Resources resources = getResources();
mFrameHeight = Math.min(
resources.getDimensionPixelSize(R.dimen.autofill_dialog_max_height),
outRect.height() - 2 * resources.getDimensionPixelSize(
R.dimen.autofill_dialog_vertical_margin));
int widthSpec = MeasureSpec.makeMeasureSpec(mFrameWidth, MeasureSpec.EXACTLY);
int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
measureChild(mTitle, widthSpec, heightSpec);
measureChild(mFooter, widthSpec, heightSpec);
heightSpec = MeasureSpec.makeMeasureSpec(
mFrameHeight - getMeasuredTitleHeight() - getMeasuredFooterHeight(),
MeasureSpec.AT_MOST);
mContent.measure(widthSpec, heightSpec);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
for (int i = 0; i < NUM_SECTIONS; i++) {
mSpinners[i].setDropDownWidth(mSpinners[i].getMeasuredWidth());
mSpinners[i].setDropDownVerticalOffset(-mSpinners[i].getMeasuredHeight());
}
}
setMeasuredDimension(mFrameWidth, mFrameHeight);
}
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
int totalHeight = getMeasuredTitleHeight()
+ getMeasuredFooterHeight() + mContent.getMeasuredHeight();
int verticalSpacing = (getMeasuredHeight() - totalHeight) / 2 ;
mTitle.layout(left, verticalSpacing, right, getMeasuredTitleHeight() + verticalSpacing);
mContent.layout(left, mTitle.getBottom(), right,
mTitle.getBottom() + mContent.getMeasuredHeight());
mFooter.layout(left, mContent.getBottom(), right, bottom - verticalSpacing);
}
/**
* Set the listener for all the dropdown members in the layout.
* @param listener The listener object to attach to the dropdowns.
*/
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
mOnItemSelectedListener = listener;
for (int i = 0; i < NUM_SECTIONS; i++) mSpinners[i].setOnItemSelectedListener(listener);
}
/**
* Set the listener for all the dropdown members in the layout.
* @param listener The listener object to attach to the dropdowns.
*/
public void setOnItemEditButtonClickedListener(OnItemEditButtonClickedListener listener) {
mOnItemEditButtonClickedListener = listener;
for (int i = 0; i < NUM_SECTIONS; i++) {
if (mAdapters[i] != null) {
mAdapters[i].setOnItemEditButtonClickedListener(listener);
}
}
}
/**
* @return Whether the current layout is one of the editing layouts.
*/
public boolean isInEditingMode() {
return mCurrentLayout != INVALID_LAYOUT
&& mCurrentLayout != LAYOUT_STEADY
&& mCurrentLayout != LAYOUT_FETCHING;
}
/**
* @return The current section if we are in editing mode, INVALID_SECTION otherwise.
*/
public int getCurrentSection() {
return getSectionForLayoutMode(mCurrentLayout);
}
/**
* Updates the legal documents footer.
* @param legalDocumentsText The text to show, or a null/empty string.
*/
public void updateLegalDocumentsText(String legalDocumentsText) {
TextView legalView = (TextView) findViewById(R.id.terms_info);
if (TextUtils.isEmpty(legalDocumentsText)) {
legalView.setVisibility(View.GONE);
return;
}
legalView.setText(legalDocumentsText);
legalView.setVisibility(View.VISIBLE);
}
/**
* Updates a dropdown with the given items and adds default items to the end.
* @param section The dialog section.
* @param suggestionText The suggestion text.
* @param suggestionIcon The suggestion icon.
* @param suggestionTextExtra The suggestion text extra.
* @param suggestionIconExtra The suggestion icon extra.
* @param items The {@link AutofillDialogMenuItem} array to update the dropdown with.
* @param selectedMenuItem The index of the selected menu item, or -1.
*/
public void updateMenuItemsForSection(int section,
String suggestionText, Bitmap suggestionIcon,
String suggestionTextExtra, Bitmap suggestionIconExtra,
List<AutofillDialogMenuItem> items, final int selectedMenuItem) {
final Spinner spinner = mSpinners[section];
// Set the listener to null and reset it after updating the menu items to avoid getting an
// onItemSelected call when the first item is selected after updating the items.
spinner.setOnItemSelectedListener(null);
AutofillDialogMenuAdapter adapter = mAdapters[section];
adapter.clear();
adapter.setSuggestionExtra(suggestionTextExtra,
createFieldIconDrawable(suggestionIconExtra));
adapter.addAll(items);
spinner.setSelection(selectedMenuItem);
spinner.post(new Runnable() {
@Override
public void run() {
spinner.setOnItemSelectedListener(mOnItemSelectedListener);
}
});
}
/**
* Updates a dropdown selection.
* @param section The dialog section.
* @param selectedMenuItem The index of the selected menu item, or -1.
*/
public void updateMenuSelectionForSection(int section, int selectedMenuItem) {
final Spinner spinner = mSpinners[section];
spinner.setSelection(selectedMenuItem);
}
/**
* Transitions the layout shown to a given layout.
* @param mode The layout mode to transition to.
*/
public void changeLayoutTo(int mode) {
assert(mode != INVALID_LAYOUT);
if (mode == mCurrentLayout || mode == INVALID_LAYOUT) return;
mCurrentLayout = mode;
removeCallbacks(mDismissSteadyLayoutRunnable);
setVisibilityForEditLayouts(false);
if (mode == LAYOUT_FETCHING) {
mSteadyLayout.setVisibility(GONE);
findViewById(R.id.loading_icon).setVisibility(VISIBLE);
return;
}
findViewById(R.id.loading_icon).setVisibility(GONE);
mSteadyLayout.setVisibility(VISIBLE);
if (mode == LAYOUT_STEADY) return;
View centeredLayout = mEditLayouts[getSectionForLayoutMode(mode)];
if (mode == LAYOUT_EDITING_CC_BILLING) {
mEditLayouts[SECTION_CC].setVisibility(VISIBLE);
mEditLayouts[SECTION_BILLING].setVisibility(VISIBLE);
} else if (mode == LAYOUT_EDITING_CC || mode == LAYOUT_EDITING_BILLING) {
mEditLayouts[SECTION_CC_BILLING].setVisibility(VISIBLE);
}
centeredLayout.setVisibility(VISIBLE);
final float fromHeight = mSteadyLayout.getMeasuredHeight();
final float toHeight = getAdjustedContentLayoutHeight(mode, centeredLayout);
PropertyValuesHolder pvhVisibleHeight = PropertyValuesHolder.ofFloat(
mContentPropertyHeight, fromHeight, toHeight);
mCurrentHeightAnimator =
ObjectAnimator.ofPropertyValuesHolder(this, pvhVisibleHeight);
mCurrentHeightAnimator.setDuration(ANIMATION_DURATION_MS);
mCurrentHeightAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
invalidate();
}
});
mCurrentHeightAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
mTransitionAnimationPlaying = true;
}
@Override
public void onAnimationEnd(Animator animator) {
mTransitionAnimationPlaying = false;
mVisibleContentHeight = toHeight;
}
});
mCurrentLayoutAnimation = addTranslateAnimations(mode);
mCurrentLayoutAnimation.addAnimation(addAppearAnimationForEditLayout(mode, centeredLayout));
mAnimateOnNextLayoutChange = true;
postDelayed(mDismissSteadyLayoutRunnable, ANIMATION_DURATION_MS);
mCurrentLayout = mode;
}
private void setVisibilityForEditLayouts(boolean visible) {
int visibility = visible ? VISIBLE : GONE;
for (int i = 0; i < NUM_SECTIONS; i++) {
if (mEditLayouts[i] != null) mEditLayouts[i].setVisibility(visibility);
}
}
/**
* Sets the visibility for all items related with the given section.
* @param section The section that will change visibility.
* @param visible Whether the section should be visible.
*/
public void setVisibilityForSection(int section, boolean visible) {
int visibility = visible ? VISIBLE : GONE;
mSpinners[section].setVisibility(visibility);
View labelView = findViewById(AutofillDialogUtils.getLabelIDForSection(section));
if (labelView != null) labelView.setVisibility(visibility);
}
/**
* @param bitmap A bitmap.
* @return A drawable with the dimensions of a field icon and the contents from the bitmap.
*/
public BitmapDrawable createFieldIconDrawable(Bitmap bitmap) {
if (bitmap == null) return null;
Resources resources = getContext().getResources();
BitmapDrawable drawable = new BitmapDrawable(resources, bitmap);
int width = resources.getDimensionPixelSize(R.dimen.autofill_field_icon_width);
int height = resources.getDimensionPixelSize(R.dimen.autofill_field_icon_height);
drawable.setBounds(0, 0, width, height);
return drawable;
}
private AnimationSet addAppearAnimationForEditLayout(int mode, View layout) {
View centerView = mSpinners[getSectionForLayoutMode(mode)];
float yOffset = centerView.getY() - (float) centerView.getHeight() / 2;
TranslateAnimation toLocationAnimation = new TranslateAnimation(0, 0, yOffset, 0);
toLocationAnimation.setDuration(ANIMATION_DURATION_MS);
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 1, 0, 1,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(ANIMATION_DURATION_MS);
AnimationSet appearAnimation = new AnimationSet(true);
appearAnimation.addAnimation(toLocationAnimation);
appearAnimation.addAnimation(scaleAnimation);
layout.setAnimation(appearAnimation);
return appearAnimation;
}
private AnimationSet addTranslateAnimations(int mode) {
float distance = getResources().
getDimensionPixelSize(R.dimen.autofill_translation_anim_distance);
TranslateAnimation toTopAnimation = new TranslateAnimation(0, 0, 0, -distance);
toTopAnimation.setDuration(ANIMATION_DURATION_MS);
TranslateAnimation toBottomAnimation = new TranslateAnimation(0, 0, 0, distance);
toBottomAnimation.setDuration(ANIMATION_DURATION_MS);
for (int i = 0; i < mSteadyLayout.getChildCount(); i++) {
View currentChild = mSteadyLayout.getChildAt(i);
if (currentChild.getVisibility() == GONE) continue;
if (currentChild.getTop() <=
mSpinners[getSectionForLayoutMode(mode)].getTop()) {
currentChild.setAnimation(toTopAnimation);
} else {
currentChild.setAnimation(toBottomAnimation);
}
}
AnimationSet combined = new AnimationSet(true);
combined.addAnimation(toBottomAnimation);
combined.addAnimation(toTopAnimation);
return combined;
}
private static int getSectionForLayoutMode(int mode) {
switch (mode) {
case LAYOUT_EDITING_EMAIL:
return SECTION_EMAIL;
case LAYOUT_EDITING_CC:
return SECTION_CC;
case LAYOUT_EDITING_BILLING:
return SECTION_BILLING;
case LAYOUT_EDITING_CC_BILLING:
return SECTION_CC_BILLING;
case LAYOUT_EDITING_SHIPPING:
return SECTION_SHIPPING;
default:
assert(false);
return AutofillDialogUtils.INVALID_SECTION;
}
}
/**
* Returns the layout mode for editing the given section.
* @param section The section to look up.
* @return The layout mode for editing the given section.
*/
public static int getLayoutModeForSection(int section) {
assert(section != AutofillDialogUtils.INVALID_SECTION);
for (int i = 0; i < AutofillDialogConstants.NUM_SECTIONS; i++) {
if (getSectionForLayoutMode(i) == section) return i;
}
assert(false);
return INVALID_LAYOUT;
}
/**
* @return The current visible content height.
*/
public float getVisibleContentHeight() {
return mVisibleContentHeight;
}
/**
* Sets the visible content height. This value is used for setting the clipRect for the canvas
* in layout transitions.
* @param height The value to use for the visible content height.
*/
public void setVisibleContentHeight(float height) {
mVisibleContentHeight = height;
}
private static class AutofillDialogMenuAdapter extends ArrayAdapter<AutofillDialogMenuItem> {
private int mSection;
private OnItemEditButtonClickedListener mOnItemEditButtonClickedListener;
private String mSuggestionTextExtra;
private BitmapDrawable mSuggestionIconExtraDrawable;
public AutofillDialogMenuAdapter(
int section,
Context context,
List<AutofillDialogMenuItem> objects) {
super(context, R.layout.autofill_menu_item, objects);
mSection = section;
}
public void setOnItemEditButtonClickedListener(OnItemEditButtonClickedListener listener) {
mOnItemEditButtonClickedListener = listener;
}
public void setSuggestionExtra(String suggestionTextExtra,
BitmapDrawable suggestionIconExtraDrawable) {
mSuggestionTextExtra = suggestionTextExtra;
mSuggestionIconExtraDrawable = suggestionIconExtraDrawable;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return initView(position, convertView, parent, false,
AutofillDialogUtils.getItemLayoutIDForSection(mSection));
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return initView(position, convertView, parent, true, R.layout.autofill_menu_item);
}
private View initView(
final int position, View convertView, final ViewGroup parent, boolean isDropDown,
int layoutId) {
if (convertView == null) {
convertView = View.inflate(getContext(), layoutId, null);
}
AutofillDialogMenuItem item = getItem(position);
ImageView icon = (ImageView) convertView.findViewById(R.id.cc_icon);
TextView line1 = (TextView) convertView.findViewById(R.id.adapter_item_line_1);
TextView line2 = (TextView) convertView.findViewById(R.id.adapter_item_line_2);
Button button = (Button) convertView.findViewById(R.id.adapter_item_edit_button);
EditText extraEdit = (EditText) convertView.findViewById(R.id.cvc_challenge);
if (icon != null) {
if (item.mIcon != null) {
icon.setImageBitmap(item.mIcon);
icon.setVisibility(VISIBLE);
} else {
icon.setImageBitmap(null);
icon.setVisibility(GONE);
}
}
if (line1 != null) line1.setText(item.mLine1);
if (line2 != null) {
if (!TextUtils.isEmpty(item.mLine2)) {
line2.setVisibility(VISIBLE);
line2.setText(item.mLine2);
} else {
line2.setVisibility(GONE);
}
}
if (extraEdit != null) {
if (!isDropDown && !TextUtils.isEmpty(mSuggestionTextExtra)) {
extraEdit.setVisibility(VISIBLE);
extraEdit.setHint(mSuggestionTextExtra);
extraEdit.setCompoundDrawables(
null, null, mSuggestionIconExtraDrawable, null);
} else {
extraEdit.setVisibility(GONE);
}
}
if (button != null) {
if (isDropDown && item.mShowButton) {
button.setText(item.mButtonLabelResourceId);
button.setOnClickListener(new OnClickListener() {
// TODO(aruslan): http://crbug.com/236101.
@Override
public void onClick(View view) {
View root = parent.getRootView();
root.dispatchKeyEvent(
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
root.dispatchKeyEvent(
new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
assert mOnItemEditButtonClickedListener != null;
if (mOnItemEditButtonClickedListener != null) {
mOnItemEditButtonClickedListener.onItemEditButtonClicked(
mSection, position);
}
}
});
button.setVisibility(VISIBLE);
} else {
button.setOnClickListener(null);
button.setVisibility(GONE);
}
}
return convertView;
}
}
}