Chromium Code Reviews| Index: content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java |
| diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java |
| index 3313d8836f52aeab377845cde168aa4d226c6fa7..458d4ba4272f800f3bdb958fa3426a00f8a3b934 100644 |
| --- a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java |
| +++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java |
| @@ -5,100 +5,164 @@ |
| package org.chromium.content.browser.input; |
| import android.app.AlertDialog; |
| +import android.app.Dialog; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.res.TypedArray; |
| +import android.graphics.Rect; |
| import android.util.SparseBooleanArray; |
| +import android.view.Display; |
| +import android.view.Gravity; |
| import android.view.View; |
| +import android.view.View.MeasureSpec; |
| +import android.view.Window; |
| +import android.view.WindowManager; |
| import android.widget.AdapterView; |
| import android.widget.AdapterView.OnItemClickListener; |
| +import android.widget.FrameLayout; |
| +import android.widget.LinearLayout; |
| import android.widget.ListView; |
| import org.chromium.content.R; |
| import org.chromium.content.browser.ContentViewCore; |
| +import org.chromium.content.browser.DeviceUtils; |
| +import org.chromium.content.browser.RenderCoordinates; |
| import java.util.List; |
| /** |
| - * Handles the popup dialog for the <select> HTML tag support. |
| + * Handles the popup for the <select> HTML tag support. |
| */ |
| -public class SelectPopupDialog { |
| +public class SelectPopupDialog implements OnItemClickListener, |
|
Ted C
2014/04/12 01:10:27
With the amount of tablet specific checks, I think
|
| + DialogInterface.OnCancelListener, |
|
Ted C
2014/04/12 01:10:27
same about indenting, needs to be 8 from the start
|
| + DialogInterface.OnDismissListener { |
| + |
| private static final int[] SELECT_DIALOG_ATTRS = { |
| - R.attr.select_dialog_multichoice, |
| - R.attr.select_dialog_singlechoice |
| + R.attr.select_popup_multichoice, |
| + R.attr.select_popup_singlechoice |
| }; |
| + // Keep in sync with optionRowHeightForTouch in blink::PopupListBox. |
| + private static final int TABLET_POPUP_ROW_HEIGHT = 28; |
| + // Keep in sync with WebCore::styledMenuListInternalPadding. |
| + private static final int TABLET_POPUP_ROW_PADDING = 4; |
| + |
| // The dialog hosting the popup list view. |
| - private AlertDialog mListBoxPopup = null; |
| + private Dialog mListBoxPopup = null; |
| + private ListView mListView = null; |
| + private Rect mOriginRect = null; |
| private final ContentViewCore mContentViewCore; |
| private final Context mContext; |
| - private SelectPopupDialog(ContentViewCore contentViewCore, List<SelectPopupItem> items, |
| - boolean multiple, int[] selected) { |
| + private SelectPopupDialog(ContentViewCore contentViewCore, |
| + List<SelectPopupItem> items, double itemFontSize, boolean multiple, int[] selected) { |
| mContentViewCore = contentViewCore; |
| mContext = mContentViewCore.getContext(); |
| - final ListView listView = new ListView(mContext); |
| - listView.setCacheColorHint(0); |
| - AlertDialog.Builder b = new AlertDialog.Builder(mContext) |
| - .setView(listView) |
| - .setCancelable(true) |
| - .setInverseBackgroundForced(true); |
| + if (DeviceUtils.isTablet(mContext)) { |
| + mListBoxPopup = new Dialog(mContext, android.R.style.Theme_Translucent_NoTitleBar); |
|
Ted C
2014/04/12 01:10:27
Instead of using a regular Dialog, we should be us
keishi
2014/04/15 14:41:07
Done.
|
| + mListBoxPopup.requestWindowFeature(Window.FEATURE_NO_TITLE); |
| + mListBoxPopup.setContentView(R.layout.select_popup_dialog); |
| + mListBoxPopup.setCancelable(true); |
| + mListBoxPopup.setCanceledOnTouchOutside(true); |
| - if (multiple) { |
| - b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { |
| - @Override |
| - public void onClick(DialogInterface dialog, int which) { |
| - mContentViewCore.selectPopupMenuItems(getSelectedIndices(listView)); |
| + mListBoxPopup.findViewById(R.id.select_popup_shadow) |
| + .setOnClickListener(new View.OnClickListener() { |
| + public void onClick(View v) { |
|
Ted C
2014/04/12 01:10:27
needs @Override
|
| + mListBoxPopup.cancel(); |
| } |
| }); |
| - b.setNegativeButton(android.R.string.cancel, |
| - new DialogInterface.OnClickListener() { |
| - @Override |
| - public void onClick(DialogInterface dialog, int which) { |
| - mContentViewCore.selectPopupMenuItems(null); |
| - } |
| - }); |
| + |
| + mListView = (ListView) mListBoxPopup.findViewById(R.id.listView); |
| + } else { |
| + mListView = new ListView(mContext); |
| + mListView.setCacheColorHint(0); |
| + AlertDialog.Builder b = new AlertDialog.Builder(mContext) |
| + .setView(mListView) |
| + .setCancelable(true) |
| + .setInverseBackgroundForced(true); |
| + |
| + if (multiple) { |
| + b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { |
| + @Override |
| + public void onClick(DialogInterface dialog, int which) { |
| + mContentViewCore.selectPopupMenuItems(getSelectedIndices(mListView)); |
| + } |
| + }); |
| + b.setNegativeButton(android.R.string.cancel, |
| + new DialogInterface.OnClickListener() { |
| + @Override |
| + public void onClick(DialogInterface dialog, int which) { |
| + mContentViewCore.selectPopupMenuItems(null); |
| + } |
| + }); |
| + } |
| + mListBoxPopup = b.create(); |
| } |
| - mListBoxPopup = b.create(); |
| - final SelectPopupAdapter adapter = new SelectPopupAdapter( |
| - mContext, getSelectDialogLayout(multiple), items); |
| - listView.setAdapter(adapter); |
| - listView.setFocusableInTouchMode(true); |
| + setupListView(items, itemFontSize, multiple, selected); |
| + mListBoxPopup.setOnCancelListener(this); |
| + mListBoxPopup.setOnDismissListener(this); |
| + } |
| + |
| + private void setupListView(List<SelectPopupItem> items, double itemFontSize, boolean multiple, |
| + int[] selected) { |
|
Ted C
2014/04/12 01:10:27
indenting
|
| + int layout = R.layout.select_popup_item; |
| + if (!DeviceUtils.isTablet(mContext)) |
|
Ted C
2014/04/12 01:10:27
needs braces
|
| + layout = getSelectDialogLayout(multiple); |
| + final SelectPopupAdapter adapter = new SelectPopupAdapter(mContext, layout, items); |
| + if (DeviceUtils.isTablet(mContext)) { |
| + RenderCoordinates renderCoordinates = mContentViewCore.renderCoordinates(); |
| + adapter.setTextSize( |
| + renderCoordinates.fromLocalCssToPix((float)itemFontSize)); |
|
Ted C
2014/04/12 01:10:27
I'm not sure we want to scale these based on page
|
| + adapter.setMinHeight( |
| + (int)renderCoordinates.fromLocalCssToPix(TABLET_POPUP_ROW_HEIGHT)); |
| + adapter.setPadding( |
| + (int)renderCoordinates.fromLocalCssToPix(TABLET_POPUP_ROW_PADDING)); |
| + } |
| + mListView.setAdapter(adapter); |
| + mListView.setFocusableInTouchMode(true); |
| if (multiple) { |
| - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); |
| + mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); |
| for (int i = 0; i < selected.length; ++i) { |
| - listView.setItemChecked(selected[i], true); |
| + mListView.setItemChecked(selected[i], true); |
| } |
| } else { |
| - listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
| - listView.setOnItemClickListener(new OnItemClickListener() { |
| - @Override |
| - public void onItemClick(AdapterView<?> parent, View v, |
| - int position, long id) { |
| - mContentViewCore.selectPopupMenuItems(getSelectedIndices(listView)); |
| - mListBoxPopup.dismiss(); |
| - } |
| - }); |
| + mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
| + mListView.setOnItemClickListener(this); |
| if (selected.length > 0) { |
| - listView.setSelection(selected[0]); |
| - listView.setItemChecked(selected[0], true); |
| + mListView.setSelection(selected[0]); |
| + mListView.setItemChecked(selected[0], true); |
| } |
| } |
| - mListBoxPopup.setOnCancelListener(new DialogInterface.OnCancelListener() { |
| - @Override |
| - public void onCancel(DialogInterface dialog) { |
| - mContentViewCore.selectPopupMenuItems(null); |
| - } |
| - }); |
| + } |
| + |
| + @Override |
| + public void onItemClick(AdapterView<?> parent, View v, |
| + int position, long id) { |
| + mContentViewCore.selectPopupMenuItems(getSelectedIndices(mListView)); |
| + mListBoxPopup.dismiss(); |
| + } |
| + |
| + @Override |
| + public void onCancel(DialogInterface dialog) { |
| + if (DeviceUtils.isTablet(mContext)) { |
| + mContentViewCore.selectPopupMenuItems(getSelectedIndices(mListView)); |
| + } else { |
| + mContentViewCore.selectPopupMenuItems(null); |
| + } |
| + } |
| + |
| + @Override |
| + public void onDismiss(DialogInterface dialog) { |
| + mListBoxPopup = null; |
| } |
| private int getSelectDialogLayout(boolean isMultiChoice) { |
| int resourceId; |
| TypedArray styledAttributes = mContext.obtainStyledAttributes( |
| - R.style.SelectPopupDialog, SELECT_DIALOG_ATTRS); |
| + R.style.SelectPopup, SELECT_DIALOG_ATTRS); |
| resourceId = styledAttributes.getResourceId(isMultiChoice ? 0 : 1, 0); |
| styledAttributes.recycle(); |
| return resourceId; |
| @@ -121,27 +185,126 @@ public class SelectPopupDialog { |
| return indices; |
| } |
| + private int getListViewPreferredWidth() { |
| + SelectPopupAdapter adapter = (SelectPopupAdapter) mListView.getAdapter(); |
| + int maxWidth = 0; |
| + View view = null; |
| + FrameLayout fakeParent = new FrameLayout(mContext); |
| + for (int i = 0; i < adapter.getCount(); i++) { |
| + view = adapter.getView(i, view, fakeParent); |
|
Ted C
2014/04/12 01:10:27
Hmm..I think you might be able to pass null as the
keishi
2014/04/15 14:41:07
Done.
|
| + LinearLayout.LayoutParams params = |
| + new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, |
| + LinearLayout.LayoutParams.WRAP_CONTENT); |
|
Ted C
2014/04/12 01:10:27
java indenting
keishi
2014/04/15 14:41:07
Done.
|
| + view.setLayoutParams(params); |
| + view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); |
| + int width = view.getMeasuredWidth(); |
|
Ted C
2014/04/12 01:10:27
this could just be
maxWidth = Math.max(maxWidth,
keishi
2014/04/15 14:41:07
Done.
|
| + if (width > maxWidth) { |
| + maxWidth = width; |
| + } |
| + } |
| + return maxWidth; |
| + } |
| + |
| + private int getListViewTotalHeight(int width) { |
| + SelectPopupAdapter adapter = (SelectPopupAdapter) mListView.getAdapter(); |
| + int totalHeight = 0; |
| + View view = null; |
| + for (int i = 0; i < adapter.getCount(); i++) { |
| + view = adapter.getView(i, view, mListView); |
| + view.measure( |
| + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), |
|
Ted C
2014/04/12 01:10:27
these lines should be +4 indented
|
| + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); |
| + totalHeight += view.getMeasuredHeight(); |
| + } |
| + return totalHeight + (mListView.getDividerHeight() * (adapter.getCount() - 1)); |
| + } |
| + |
| + public void show(Rect originRect) { |
| + update(originRect); |
| + mListBoxPopup.show(); |
| + } |
| + |
| + public void hide() { |
| + mListBoxPopup.dismiss(); |
| + } |
| + |
| /** |
| - * Hides the select dialog. |
| + * Updates the popup position. |
| + * @param originRect The rect of the origin select element. If null the last originRect will be |
| + * reused. |
|
Ted C
2014/04/12 01:10:27
align this with "The rect" above
|
| */ |
| - public void hide() { |
| - mListBoxPopup.cancel(); |
| + public void update(Rect originRect) { |
| + if (!DeviceUtils.isTablet(mContext)) { |
|
Ted C
2014/04/12 01:10:27
I would make this a one liner since it is compact
|
| + return; |
| + } |
| + if (originRect != null) { |
| + mOriginRect = originRect; |
| + } |
| + Rect screenRect = new Rect(); |
| + Display d = mListBoxPopup.getWindow().getWindowManager().getDefaultDisplay(); |
| + d.getRectSize(screenRect); |
| + int horizontalMargin = mContext.getResources().getDimensionPixelSize( |
| + R.dimen.select_popup_horizontal_margin); |
| + int bottomMargin = mContext.getResources().getDimensionPixelSize( |
| + R.dimen.select_popup_bottom_margin); |
| + int borderWidth = mContext.getResources().getDimensionPixelSize( |
| + R.dimen.select_popup_border_width); |
| + |
| + Rect contentViewFrame = new Rect(); |
| + mContentViewCore.getContainerView().getWindowVisibleDisplayFrame(contentViewFrame); |
| + |
| + RenderCoordinates renderCoordinates = mContentViewCore.renderCoordinates(); |
| + Rect originRectOnScreen = new Rect( |
| + (int) renderCoordinates.fromLocalCssToPix(mOriginRect.left), |
| + ((int) (renderCoordinates.fromLocalCssToPix(mOriginRect.top) |
| + + renderCoordinates.getContentOffsetYPix())) + contentViewFrame.top, |
| + (int) renderCoordinates.fromLocalCssToPix(mOriginRect.right), |
| + ((int) (renderCoordinates.fromLocalCssToPix(mOriginRect.bottom) |
| + + renderCoordinates.getContentOffsetYPix())) + contentViewFrame.top); |
| + |
| + int availableSpaceAbove = originRectOnScreen.top; |
| + int availableSpaceBelow = screenRect.height() - originRectOnScreen.bottom; |
| + int availableSpace = Math.max(availableSpaceAbove, availableSpaceBelow); |
| + |
| + int dialogWidth = Math.max( |
| + getListViewPreferredWidth() + (horizontalMargin + borderWidth) * 2, |
| + originRectOnScreen.width() + horizontalMargin * 2); |
| + dialogWidth = Math.min(dialogWidth, screenRect.width()); |
| + int dialogHeight = Math.min( |
| + getListViewTotalHeight(dialogWidth - (horizontalMargin + borderWidth) * 2) + |
| + borderWidth * 2 + bottomMargin, |
| + availableSpace); |
| + |
| + WindowManager.LayoutParams wmlp = mListBoxPopup.getWindow().getAttributes(); |
| + wmlp.gravity = Gravity.TOP | Gravity.LEFT; |
| + wmlp.x = originRectOnScreen.left - horizontalMargin; |
| + wmlp.y = originRectOnScreen.bottom; |
| + wmlp.width = dialogWidth; |
| + wmlp.height = dialogHeight; |
| + if (availableSpaceBelow < dialogHeight && availableSpaceAbove > availableSpaceBelow) { |
| + wmlp.y = originRectOnScreen.top - dialogHeight + bottomMargin; |
| + } |
| + if (wmlp.x < 0) { |
| + wmlp.x = 0; |
| + } |
| + if (wmlp.x > screenRect.width() - dialogWidth) { |
| + wmlp.x = screenRect.right - dialogWidth; |
| + } |
| + mListBoxPopup.getWindow().setAttributes(wmlp); |
| } |
| /** |
| * Shows the popup menu triggered by the passed ContentView. |
| - * Hides any currently shown popup. |
| * @param items Items to show. |
| * @param multiple Whether the popup menu should support multi-select. |
| * @param selectedIndices Indices of selected items. |
| - * @return The select dialog created. |
| */ |
| - public static SelectPopupDialog show( |
| - ContentViewCore contentViewCore, List<SelectPopupItem> items, |
| - boolean multiple, int[] selectedIndices) { |
| - SelectPopupDialog dialog = new SelectPopupDialog( |
| - contentViewCore, items, multiple, selectedIndices); |
| - dialog.mListBoxPopup.show(); |
| - return dialog; |
| + public static SelectPopupDialog show(ContentViewCore contentViewCore, Rect originRect, |
| + List<SelectPopupItem> items, double itemFontSize, boolean multiple, |
| + int[] selectedIndices) { |
| + SelectPopupDialog popup = new SelectPopupDialog(contentViewCore, items, itemFontSize, |
| + multiple, selectedIndices); |
| + popup.show(originRect); |
| + return popup; |
| } |
| } |