OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.contextmenu; | 5 package org.chromium.chrome.browser.contextmenu; |
6 | 6 |
7 import android.app.Dialog; | 7 import android.app.Dialog; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.DialogInterface; | 9 import android.content.DialogInterface; |
10 import android.content.res.Resources; | |
11 import android.graphics.Bitmap; | |
12 import android.graphics.Canvas; | |
13 import android.graphics.Shader; | |
14 import android.graphics.drawable.BitmapDrawable; | |
15 import android.graphics.drawable.Drawable; | |
10 import android.support.design.widget.TabLayout; | 16 import android.support.design.widget.TabLayout; |
11 import android.support.v4.view.ViewPager; | 17 import android.support.v4.view.ViewPager; |
12 import android.support.v7.app.AlertDialog; | 18 import android.support.v7.app.AlertDialog; |
13 import android.text.TextUtils; | 19 import android.text.TextUtils; |
14 import android.util.Pair; | 20 import android.util.Pair; |
15 import android.view.LayoutInflater; | 21 import android.view.LayoutInflater; |
16 import android.view.View; | 22 import android.view.View; |
17 import android.view.ViewGroup; | 23 import android.view.ViewGroup; |
18 import android.widget.AdapterView; | 24 import android.widget.AdapterView; |
19 import android.widget.BaseAdapter; | 25 import android.widget.BaseAdapter; |
26 import android.widget.ImageView; | |
20 import android.widget.ListView; | 27 import android.widget.ListView; |
21 import android.widget.TextView; | 28 import android.widget.TextView; |
22 | 29 |
23 import org.chromium.base.ApiCompatibilityUtils; | 30 import org.chromium.base.ApiCompatibilityUtils; |
24 import org.chromium.base.Callback; | 31 import org.chromium.base.Callback; |
25 import org.chromium.base.VisibleForTesting; | 32 import org.chromium.base.VisibleForTesting; |
26 import org.chromium.chrome.R; | 33 import org.chromium.chrome.R; |
27 | 34 |
28 import java.util.ArrayList; | 35 import java.util.ArrayList; |
29 import java.util.List; | 36 import java.util.List; |
30 | 37 |
31 /** | 38 /** |
32 * A custom dialog that separates each group into separate tabs. It uses a dialo g instead. | 39 * A custom dialog that separates each group into separate tabs. It uses a dialo g instead. |
33 */ | 40 */ |
34 public class TabularContextMenuUi implements ContextMenuUi, AdapterView.OnItemCl ickListener { | 41 public class TabularContextMenuUi implements ContextMenuUi, AdapterView.OnItemCl ickListener { |
35 private Dialog mDialog; | 42 private Dialog mDialog; |
36 private Callback<Integer> mCallback; | 43 private Callback<Integer> mCallback; |
37 private int mMenuItemHeight; | 44 private int mMenuItemHeight; |
45 private final ContextMenuHelper mContextMenuHelper; | |
46 | |
47 /** | |
48 * A context menu that sperates types by tabs. | |
49 * @param contextMenuHelper The {@link ContextMenuHelper} is used to retriev e the thumbnail | |
50 * natively from the Context Menu Helper. | |
51 */ | |
52 TabularContextMenuUi(ContextMenuHelper contextMenuHelper) { | |
Ted C
2017/03/31 16:19:33
I don't think this class should take the ContextMe
JJ
2017/03/31 18:43:59
Done.
| |
53 mContextMenuHelper = contextMenuHelper; | |
54 } | |
38 | 55 |
39 @Override | 56 @Override |
40 public void displayMenu(Context context, ContextMenuParams params, | 57 public void displayMenu(Context context, ContextMenuParams params, |
41 List<Pair<Integer, List<ContextMenuItem>>> items, Callback<Integer> onItemClicked, | 58 List<Pair<Integer, List<ContextMenuItem>>> items, Callback<Integer> onItemClicked, |
42 final Runnable onMenuShown, final Runnable onMenuClosed) { | 59 final Runnable onMenuShown, final Runnable onMenuClosed) { |
43 mCallback = onItemClicked; | 60 mCallback = onItemClicked; |
44 mDialog = createDialog(context, params, items); | 61 mDialog = createDialog(context, params, items); |
45 mDialog.getWindow().setBackgroundDrawable(ApiCompatibilityUtils.getDrawa ble( | 62 mDialog.getWindow().setBackgroundDrawable(ApiCompatibilityUtils.getDrawa ble( |
46 context.getResources(), R.drawable.bg_find_toolbar_popup)); | 63 context.getResources(), R.drawable.bg_find_toolbar_popup)); |
47 | 64 |
(...skipping 28 matching lines...) Expand all Loading... | |
76 dialog.setContentView(createPagerView(context, params, itemGroups)); | 93 dialog.setContentView(createPagerView(context, params, itemGroups)); |
77 return dialog; | 94 return dialog; |
78 } | 95 } |
79 | 96 |
80 /** | 97 /** |
81 * Creates the view of a context menu. Based off the Context Type, it'll adj ust the list of | 98 * Creates the view of a context menu. Based off the Context Type, it'll adj ust the list of |
82 * items and display only the ones that'll be on that specific group. | 99 * items and display only the ones that'll be on that specific group. |
83 * @param context Used to get the resources of an item. | 100 * @param context Used to get the resources of an item. |
84 * @param params used to create the header text. | 101 * @param params used to create the header text. |
85 * @param items A set of Items to display in a context menu. Filtered based off the type. | 102 * @param items A set of Items to display in a context menu. Filtered based off the type. |
86 * @return Returns a filled LinearLayout with all the context menu items | 103 * @param isImage Whether or not the view should have an image layout or not . |
104 * @param maxCount The maximum amount of {@link ContextMenuItem}s that could exist in this view | |
105 * or any other views calculated in the context menu. Used t o estimate the size | |
106 * of the list. | |
107 * @return Returns a filled LinearLayout with all the context menu items. | |
87 */ | 108 */ |
88 @VisibleForTesting | 109 @VisibleForTesting |
89 ViewGroup createContextMenuPageUi( | 110 ViewGroup createContextMenuPageUi(Context context, ContextMenuParams params, |
90 Context context, ContextMenuParams params, List<ContextMenuItem> ite ms, int maxCount) { | 111 List<ContextMenuItem> items, boolean isImage, int maxCount) { |
91 ViewGroup baseLayout = (ViewGroup) LayoutInflater.from(context).inflate( | 112 ViewGroup baseLayout = (ViewGroup) LayoutInflater.from(context).inflate( |
92 R.layout.tabular_context_menu_page, null); | 113 R.layout.tabular_context_menu_page, null); |
93 ListView listView = (ListView) baseLayout.findViewById(R.id.selectable_i tems); | 114 ListView listView = (ListView) baseLayout.findViewById(R.id.selectable_i tems); |
94 displayHeaderIfVisibleItems(params, baseLayout); | 115 |
116 if (isImage) { | |
117 displayImageHeader(baseLayout, params, context.getResources()); | |
118 } else { | |
119 displayHeaderIfVisibleItems(params, baseLayout); | |
120 } | |
95 | 121 |
96 // Set the list adapter and get the height to display it appropriately i n a dialog. | 122 // Set the list adapter and get the height to display it appropriately i n a dialog. |
97 TabularContextMenuListAdapter listAdapter = | 123 TabularContextMenuListAdapter listAdapter = |
98 new TabularContextMenuListAdapter(items, context); | 124 new TabularContextMenuListAdapter(items, context); |
99 ViewGroup.LayoutParams layoutParams = listView.getLayoutParams(); | 125 ViewGroup.LayoutParams layoutParams = listView.getLayoutParams(); |
100 layoutParams.height = measureApproximateListViewHeight(listView, listAda pter, maxCount); | 126 layoutParams.height = measureApproximateListViewHeight(listView, listAda pter, maxCount); |
101 listView.setLayoutParams(layoutParams); | 127 listView.setLayoutParams(layoutParams); |
102 listView.setAdapter(listAdapter); | 128 listView.setAdapter(listAdapter); |
103 listView.setOnItemClickListener(this); | 129 listView.setOnItemClickListener(this); |
104 | 130 |
105 return baseLayout; | 131 return baseLayout; |
106 } | 132 } |
107 | 133 |
108 private void displayHeaderIfVisibleItems(ContextMenuParams params, ViewGroup baseLayout) { | 134 private void displayHeaderIfVisibleItems(ContextMenuParams params, ViewGroup baseLayout) { |
109 String headerText = ChromeContextMenuPopulator.createHeaderText(params); | 135 String headerText = ChromeContextMenuPopulator.createHeaderText(params); |
110 final TextView headerTextView = | 136 final TextView headerTextView = |
111 (TextView) baseLayout.findViewById(R.id.context_header_text); | 137 (TextView) baseLayout.findViewById(R.id.context_header_text); |
112 if (TextUtils.isEmpty(headerText)) { | 138 if (TextUtils.isEmpty(headerText)) { |
139 baseLayout.findViewById(R.id.context_header_layout).setVisibility(Vi ew.GONE); | |
113 headerTextView.setVisibility(View.GONE); | 140 headerTextView.setVisibility(View.GONE); |
114 baseLayout.findViewById(R.id.context_divider).setVisibility(View.GON E); | 141 baseLayout.findViewById(R.id.context_divider).setVisibility(View.GON E); |
115 return; | 142 return; |
116 } | 143 } |
117 headerTextView.setVisibility(View.VISIBLE); | 144 headerTextView.setVisibility(View.VISIBLE); |
118 headerTextView.setText(headerText); | 145 headerTextView.setText(headerText); |
119 headerTextView.setOnClickListener(new View.OnClickListener() { | 146 headerTextView.setOnClickListener(new View.OnClickListener() { |
120 @Override | 147 @Override |
121 public void onClick(View view) { | 148 public void onClick(View view) { |
122 if (headerTextView.getMaxLines() == Integer.MAX_VALUE) { | 149 if (headerTextView.getMaxLines() == Integer.MAX_VALUE) { |
123 headerTextView.setMaxLines(1); | 150 headerTextView.setMaxLines(1); |
124 headerTextView.setEllipsize(TextUtils.TruncateAt.END); | 151 headerTextView.setEllipsize(TextUtils.TruncateAt.END); |
125 } else { | 152 } else { |
126 headerTextView.setMaxLines(Integer.MAX_VALUE); | 153 headerTextView.setMaxLines(Integer.MAX_VALUE); |
127 headerTextView.setEllipsize(null); | 154 headerTextView.setEllipsize(null); |
128 } | 155 } |
129 } | 156 } |
130 }); | 157 }); |
131 } | 158 } |
132 | 159 |
160 private void displayImageHeader( | |
161 ViewGroup baseLayout, ContextMenuParams params, Resources resources) { | |
162 displayHeaderIfVisibleItems(params, baseLayout); | |
163 // #displayHeaderIfVisibleItems() sets these two views to GONE if the he ader text is | |
164 // empty but they should still be visible because we have an image to di splay. | |
165 baseLayout.findViewById(R.id.context_header_layout).setVisibility(View.V ISIBLE); | |
166 baseLayout.findViewById(R.id.context_divider).setVisibility(View.VISIBLE ); | |
167 | |
168 final ImageView imageView = (ImageView) baseLayout.findViewById(R.id.con text_header_image); | |
169 TextView headerTextView = (TextView) baseLayout.findViewById(R.id.contex t_header_text); | |
170 // We'd prefer the header text is the title text instead of the link tex t for images. | |
171 String headerText = params.getTitleText(); | |
172 if (!TextUtils.isEmpty(headerText)) { | |
173 headerTextView.setText(headerText); | |
174 } | |
175 setBackgroundForImageView(imageView, resources); | |
176 mContextMenuHelper.getThumbnail(new ContextMenuHelper.OnThumbnailReceive dListener() { | |
177 @Override | |
178 public void onThumbnailReceived(Bitmap bitmap) { | |
179 imageView.setImageBitmap(bitmap); | |
180 } | |
181 }); | |
182 } | |
183 | |
184 /** | |
185 * This creates a checkerboard style background displayed before the image i s shown. | |
186 */ | |
187 private void setBackgroundForImageView(ImageView imageView, Resources resour ces) { | |
188 Drawable drawable = | |
189 ApiCompatibilityUtils.getDrawable(resources, R.drawable.checkerb oard_background); | |
190 Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), | |
191 drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); | |
192 Canvas canvas = new Canvas(bitmap); | |
193 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); | |
194 drawable.draw(canvas); | |
195 BitmapDrawable bm = new BitmapDrawable(resources, bitmap); | |
196 bm.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); | |
197 imageView.setVisibility(View.VISIBLE); | |
198 imageView.setBackground(bm); | |
199 } | |
200 | |
133 /** | 201 /** |
134 * To save time measuring the height, this method gets an item if the height has not been | 202 * To save time measuring the height, this method gets an item if the height has not been |
135 * previous measured and multiplies it by count of the total amount of items . It is fine if the | 203 * previous measured and multiplies it by count of the total amount of items . It is fine if the |
136 * height too small as the ListView will scroll through the other values. | 204 * height too small as the ListView will scroll through the other values. |
137 * @param listView The ListView to measure the surrounding padding. | 205 * @param listView The ListView to measure the surrounding padding. |
138 * @param listAdapter The adapter which contains the items within the list. | 206 * @param listAdapter The adapter which contains the items within the list. |
139 * @return Returns the combined height of the padding of the ListView and th e approximate height | 207 * @return Returns the combined height of the padding of the ListView and th e approximate height |
140 * of the ListView based off the an item. | 208 * of the ListView based off the an item. |
141 */ | 209 */ |
142 private int measureApproximateListViewHeight( | 210 private int measureApproximateListViewHeight( |
(...skipping 22 matching lines...) Expand all Loading... | |
165 View view = LayoutInflater.from(context).inflate(R.layout.tabular_contex t_menu, null); | 233 View view = LayoutInflater.from(context).inflate(R.layout.tabular_contex t_menu, null); |
166 | 234 |
167 List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>(); | 235 List<Pair<String, ViewGroup>> viewGroups = new ArrayList<>(); |
168 int maxCount = 0; | 236 int maxCount = 0; |
169 for (int i = 0; i < itemGroups.size(); i++) { | 237 for (int i = 0; i < itemGroups.size(); i++) { |
170 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); | 238 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); |
171 maxCount = Math.max(maxCount, itemGroup.second.size()); | 239 maxCount = Math.max(maxCount, itemGroup.second.size()); |
172 } | 240 } |
173 for (int i = 0; i < itemGroups.size(); i++) { | 241 for (int i = 0; i < itemGroups.size(); i++) { |
174 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); | 242 Pair<Integer, List<ContextMenuItem>> itemGroup = itemGroups.get(i); |
243 boolean isImage = itemGroup.first == R.string.contextmenu_image_titl e; | |
Ted C
2017/03/31 16:19:33
Hmm...looking at this I think we might want to pas
JJ
2017/03/31 18:43:59
Added but I'd give a word of caution it's more of
| |
175 viewGroups.add(new Pair<>(context.getString(itemGroup.first), | 244 viewGroups.add(new Pair<>(context.getString(itemGroup.first), |
176 createContextMenuPageUi(context, params, itemGroup.second, m axCount))); | 245 createContextMenuPageUi(context, params, itemGroup.second, i sImage, maxCount))); |
177 } | 246 } |
178 TabularContextMenuViewPager pager = | 247 TabularContextMenuViewPager pager = |
179 (TabularContextMenuViewPager) view.findViewById(R.id.custom_page r); | 248 (TabularContextMenuViewPager) view.findViewById(R.id.custom_page r); |
180 pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups)); | 249 pager.setAdapter(new TabularContextMenuPagerAdapter(viewGroups)); |
181 | 250 |
182 TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout); | 251 TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout); |
183 if (itemGroups.size() <= 1) { | 252 if (itemGroups.size() <= 1) { |
184 tabLayout.setVisibility(View.GONE); | 253 tabLayout.setVisibility(View.GONE); |
185 } | 254 } |
186 tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.custom_p ager)); | 255 tabLayout.setupWithViewPager((ViewPager) view.findViewById(R.id.custom_p ager)); |
187 | 256 |
188 return view; | 257 return view; |
189 } | 258 } |
190 | 259 |
191 @Override | 260 @Override |
192 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { | 261 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { |
193 mDialog.dismiss(); | 262 mDialog.dismiss(); |
194 mCallback.onResult((int) id); | 263 mCallback.onResult((int) id); |
195 } | 264 } |
196 } | 265 } |
OLD | NEW |