OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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; | 5 package org.chromium.chrome.browser; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.app.Dialog; | 8 import android.app.Dialog; |
9 import android.content.Context; | 9 import android.content.Context; |
10 import android.content.DialogInterface; | 10 import android.content.DialogInterface; |
11 import android.graphics.Color; | 11 import android.graphics.Color; |
12 import android.graphics.drawable.ColorDrawable; | 12 import android.graphics.drawable.ColorDrawable; |
13 import android.text.SpannableString; | 13 import android.text.SpannableString; |
14 import android.text.method.LinkMovementMethod; | 14 import android.text.method.LinkMovementMethod; |
15 import android.view.Gravity; | 15 import android.view.Gravity; |
16 import android.view.LayoutInflater; | 16 import android.view.LayoutInflater; |
17 import android.view.View; | 17 import android.view.View; |
18 import android.view.ViewGroup; | 18 import android.view.ViewGroup; |
19 import android.view.ViewGroup.LayoutParams; | 19 import android.view.ViewGroup.LayoutParams; |
20 import android.view.Window; | 20 import android.view.Window; |
21 import android.widget.AdapterView; | 21 import android.widget.AdapterView; |
22 import android.widget.ArrayAdapter; | 22 import android.widget.ArrayAdapter; |
23 import android.widget.Button; | 23 import android.widget.Button; |
| 24 import android.widget.ImageView; |
24 import android.widget.LinearLayout; | 25 import android.widget.LinearLayout; |
25 import android.widget.ListView; | 26 import android.widget.ListView; |
26 import android.widget.ProgressBar; | 27 import android.widget.ProgressBar; |
| 28 import android.widget.RelativeLayout; |
27 import android.widget.TextView; | 29 import android.widget.TextView; |
28 | 30 |
29 import org.chromium.base.ApiCompatibilityUtils; | 31 import org.chromium.base.ApiCompatibilityUtils; |
30 import org.chromium.base.VisibleForTesting; | 32 import org.chromium.base.VisibleForTesting; |
31 import org.chromium.chrome.R; | 33 import org.chromium.chrome.R; |
32 import org.chromium.chrome.browser.util.MathUtils; | 34 import org.chromium.chrome.browser.util.MathUtils; |
33 import org.chromium.ui.base.DeviceFormFactor; | 35 import org.chromium.ui.base.DeviceFormFactor; |
34 import org.chromium.ui.widget.TextViewWithClickableSpans; | 36 import org.chromium.ui.widget.TextViewWithClickableSpans; |
35 | 37 |
36 import java.util.HashMap; | 38 import java.util.HashMap; |
(...skipping 16 matching lines...) Expand all Loading... |
53 /** | 55 /** |
54 * Returns the user selection. | 56 * Returns the user selection. |
55 * | 57 * |
56 * @param id The id of the item selected. Blank if the dialog was closed | 58 * @param id The id of the item selected. Blank if the dialog was closed |
57 * without selecting anything. | 59 * without selecting anything. |
58 */ | 60 */ |
59 void onItemSelected(String id); | 61 void onItemSelected(String id); |
60 } | 62 } |
61 | 63 |
62 /** | 64 /** |
| 65 * A class representing an icon to be shown in a chooser row. |
| 66 */ |
| 67 public static class ItemChooserRowIcon { |
| 68 private int mNonSelectedIcon; |
| 69 // Icon when the row is selected. |
| 70 private int mSelectedIcon; |
| 71 private String mIconDescription; |
| 72 |
| 73 public ItemChooserRowIcon(int icon, int selectedIcon, String iconDescrip
tion) { |
| 74 mNonSelectedIcon = icon; |
| 75 mSelectedIcon = selectedIcon; |
| 76 mIconDescription = iconDescription; |
| 77 } |
| 78 |
| 79 @Override |
| 80 public boolean equals(Object obj) { |
| 81 if (!(obj instanceof ItemChooserRowIcon)) return false; |
| 82 if (this == obj) return true; |
| 83 ItemChooserRowIcon icon = (ItemChooserRowIcon) obj; |
| 84 return mNonSelectedIcon == icon.mNonSelectedIcon && mSelectedIcon ==
icon.mSelectedIcon |
| 85 && mIconDescription.equals(icon.mIconDescription); |
| 86 } |
| 87 |
| 88 @Override |
| 89 public String toString() { |
| 90 return mNonSelectedIcon + ":" + mSelectedIcon + ":" + mIconDescripti
on; |
| 91 } |
| 92 |
| 93 @Override |
| 94 public int hashCode() { |
| 95 return mNonSelectedIcon + mSelectedIcon + mIconDescription.hashCode(
); |
| 96 } |
| 97 } |
| 98 |
| 99 /** |
63 * A class representing one data row in the picker. | 100 * A class representing one data row in the picker. |
64 */ | 101 */ |
65 public static class ItemChooserRow { | 102 public static class ItemChooserRow { |
66 private final String mKey; | 103 private final String mKey; |
67 private String mDescription; | 104 private String mDescription; |
| 105 private ItemChooserRowIcon mIcon; |
| 106 |
| 107 public ItemChooserRow(String key, String description, ItemChooserRowIcon
icon) { |
| 108 mKey = key; |
| 109 mDescription = description; |
| 110 mIcon = icon; |
| 111 } |
68 | 112 |
69 public ItemChooserRow(String key, String description) { | 113 public ItemChooserRow(String key, String description) { |
70 mKey = key; | 114 this(key, description, null); |
71 mDescription = description; | |
72 } | 115 } |
73 | 116 |
74 @Override | 117 @Override |
75 public boolean equals(Object obj) { | 118 public boolean equals(Object obj) { |
76 if (!(obj instanceof ItemChooserRow)) return false; | 119 if (!(obj instanceof ItemChooserRow)) return false; |
77 if (this == obj) return true; | 120 if (this == obj) return true; |
78 ItemChooserRow item = (ItemChooserRow) obj; | 121 ItemChooserRow item = (ItemChooserRow) obj; |
79 return mKey.equals(item.mKey) && mDescription.equals(item.mDescripti
on); | 122 |
| 123 if (mIcon == null ^ item.mIcon == null) return false; |
| 124 |
| 125 if (mIcon != null && item.mIcon != null && !mIcon.equals(item.mIcon)
) return false; |
| 126 |
| 127 if (mKey.equals(item.mKey) && mDescription.equals(item.mDescription)
) return true; |
| 128 |
| 129 return false; |
80 } | 130 } |
81 | 131 |
82 @Override | 132 @Override |
83 public int hashCode() { | 133 public int hashCode() { |
84 return mKey.hashCode() + mDescription.hashCode(); | 134 return mKey.hashCode() + mDescription.hashCode() + mIcon.hashCode(); |
| 135 } |
| 136 |
| 137 @Override |
| 138 public String toString() { |
| 139 return mKey + ":" + mDescription + ":" + mIcon.toString(); |
85 } | 140 } |
86 } | 141 } |
87 | 142 |
88 /** | 143 /** |
89 * The labels to show in the dialog. | 144 * The labels to show in the dialog. |
90 */ | 145 */ |
91 public static class ItemChooserLabels { | 146 public static class ItemChooserLabels { |
92 // The title at the top of the dialog. | 147 // The title at the top of the dialog. |
93 public final CharSequence title; | 148 public final CharSequence title; |
94 // The message to show while there are no results. | 149 // The message to show while there are no results. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 public class ItemAdapter extends ArrayAdapter<ItemChooserRow> | 186 public class ItemAdapter extends ArrayAdapter<ItemChooserRow> |
132 implements AdapterView.OnItemClickListener { | 187 implements AdapterView.OnItemClickListener { |
133 private final LayoutInflater mInflater; | 188 private final LayoutInflater mInflater; |
134 | 189 |
135 // The background color of the highlighted item. | 190 // The background color of the highlighted item. |
136 private final int mBackgroundHighlightColor; | 191 private final int mBackgroundHighlightColor; |
137 | 192 |
138 // The color of the non-highlighted text. | 193 // The color of the non-highlighted text. |
139 private final int mDefaultTextColor; | 194 private final int mDefaultTextColor; |
140 | 195 |
| 196 // The color of disabled text. |
| 197 private final int mDisabledTextColor; |
| 198 |
141 // The zero-based index of the item currently selected in the dialog, | 199 // The zero-based index of the item currently selected in the dialog, |
142 // or -1 (INVALID_POSITION) if nothing is selected. | 200 // or -1 (INVALID_POSITION) if nothing is selected. |
143 private int mSelectedItem = ListView.INVALID_POSITION; | 201 private int mSelectedItem = ListView.INVALID_POSITION; |
144 | 202 |
145 // A set of keys that are marked as disabled in the dialog. | 203 // A set of keys that are marked as disabled in the dialog. |
146 private Set<String> mDisabledEntries = new HashSet<String>(); | 204 private Set<String> mDisabledEntries = new HashSet<String>(); |
147 | 205 |
148 // Item descriptions are counted in a map. | 206 // Item descriptions are counted in a map. |
149 private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); | 207 private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); |
150 | 208 |
151 // Map of keys to items so that we can access the items in O(1). | 209 // Map of keys to items so that we can access the items in O(1). |
152 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); | 210 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); |
153 | 211 |
154 public ItemAdapter(Context context, int resource) { | 212 public ItemAdapter(Context context, int resource) { |
155 super(context, resource); | 213 super(context, resource); |
156 | 214 |
157 mInflater = LayoutInflater.from(context); | 215 mInflater = LayoutInflater.from(context); |
158 | 216 |
159 mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContex
t().getResources(), | 217 mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContex
t().getResources(), |
160 R.color.light_active_color); | 218 R.color.light_active_color); |
161 mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getR
esources(), | 219 mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getR
esources(), |
162 R.color.default_text_color); | 220 R.color.default_text_color); |
| 221 mDisabledTextColor = ApiCompatibilityUtils.getColor( |
| 222 getContext().getResources(), R.color.primary_text_disabled_m
aterial_light); |
163 } | 223 } |
164 | 224 |
165 @Override | 225 @Override |
166 public boolean isEmpty() { | 226 public boolean isEmpty() { |
167 boolean isEmpty = super.isEmpty(); | 227 boolean isEmpty = super.isEmpty(); |
168 if (isEmpty) { | 228 if (isEmpty) { |
169 assert mKeyToItemMap.isEmpty(); | 229 assert mKeyToItemMap.isEmpty(); |
170 assert mDisabledEntries.isEmpty(); | 230 assert mDisabledEntries.isEmpty(); |
171 assert mItemDescriptionMap.isEmpty(); | 231 assert mItemDescriptionMap.isEmpty(); |
172 } else { | 232 } else { |
173 assert !mKeyToItemMap.isEmpty(); | 233 assert !mKeyToItemMap.isEmpty(); |
174 assert !mItemDescriptionMap.isEmpty(); | 234 assert !mItemDescriptionMap.isEmpty(); |
175 } | 235 } |
176 return isEmpty; | 236 return isEmpty; |
177 } | 237 } |
178 | 238 |
179 public void addOrUpdate(ItemChooserRow item) { | 239 public void addOrUpdate(ItemChooserRow item) { |
180 ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey); | 240 ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey); |
181 if (oldItem != null) { | 241 if (oldItem != null) { |
182 if (oldItem.equals(item)) { | 242 if (oldItem.equals(item)) { |
183 // No need to update anything. | 243 // No need to update anything. |
184 return; | 244 return; |
185 } | 245 } |
186 if (!oldItem.mDescription.equals(item.mDescription)) { | 246 if (!oldItem.mDescription.equals(item.mDescription)) { |
187 removeFromDescriptionsMap(oldItem.mDescription); | 247 removeFromDescriptionsMap(oldItem.mDescription); |
188 oldItem.mDescription = item.mDescription; | 248 oldItem.mDescription = item.mDescription; |
189 addToDescriptionsMap(oldItem.mDescription); | 249 addToDescriptionsMap(oldItem.mDescription); |
190 } | 250 } |
| 251 if (item.mIcon != null |
| 252 && (oldItem.mIcon == null || !oldItem.mIcon.equals(item.
mIcon))) { |
| 253 oldItem.mIcon = item.mIcon; |
| 254 } |
191 notifyDataSetChanged(); | 255 notifyDataSetChanged(); |
192 return; | 256 return; |
193 } | 257 } |
194 ItemChooserRow result = mKeyToItemMap.put(item.mKey, item); | 258 ItemChooserRow result = mKeyToItemMap.put(item.mKey, item); |
195 assert result == null; | 259 assert result == null; |
196 | 260 |
197 addToDescriptionsMap(item.mDescription); | 261 addToDescriptionsMap(item.mDescription); |
198 add(item); | 262 add(item); |
199 } | 263 } |
200 | 264 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 */ | 297 */ |
234 public String getDisplayText(int position) { | 298 public String getDisplayText(int position) { |
235 ItemChooserRow item = getItem(position); | 299 ItemChooserRow item = getItem(position); |
236 String description = item.mDescription; | 300 String description = item.mDescription; |
237 int counter = mItemDescriptionMap.get(description); | 301 int counter = mItemDescriptionMap.get(description); |
238 return counter == 1 ? description | 302 return counter == 1 ? description |
239 : mActivity.getString(R.string.item_chooser_item_name_with_i
d, description, | 303 : mActivity.getString(R.string.item_chooser_item_name_with_i
d, description, |
240 item.mKey); | 304 item.mKey); |
241 } | 305 } |
242 | 306 |
| 307 public ItemChooserRowIcon getIcon(int position) { |
| 308 ItemChooserRow item = getItem(position); |
| 309 return item.mIcon; |
| 310 } |
| 311 |
| 312 public boolean hasIcon(int position) { |
| 313 ItemChooserRow item = getItem(position); |
| 314 return item.mIcon != null; |
| 315 } |
| 316 |
243 /** | 317 /** |
244 * Sets whether the itam is enabled. Disabled items are grayed out. | 318 * Sets whether the itam is enabled. Disabled items are grayed out. |
245 * @param id The id of the item to affect. | 319 * @param id The id of the item to affect. |
246 * @param enabled Whether the item should be enabled or not. | 320 * @param enabled Whether the item should be enabled or not. |
247 */ | 321 */ |
248 public void setEnabled(String id, boolean enabled) { | 322 public void setEnabled(String id, boolean enabled) { |
249 if (enabled) { | 323 if (enabled) { |
250 mDisabledEntries.remove(id); | 324 mDisabledEntries.remove(id); |
251 } else { | 325 } else { |
252 mDisabledEntries.add(id); | 326 mDisabledEntries.add(id); |
(...skipping 12 matching lines...) Expand all Loading... |
265 return 1; | 339 return 1; |
266 } | 340 } |
267 | 341 |
268 @Override | 342 @Override |
269 public long getItemId(int position) { | 343 public long getItemId(int position) { |
270 return position; | 344 return position; |
271 } | 345 } |
272 | 346 |
273 @Override | 347 @Override |
274 public View getView(int position, View convertView, ViewGroup parent) { | 348 public View getView(int position, View convertView, ViewGroup parent) { |
275 TextView view; | 349 RelativeLayout view; |
276 if (convertView instanceof TextView) { | 350 if (convertView instanceof RelativeLayout) { |
277 view = (TextView) convertView; | 351 view = (RelativeLayout) convertView; |
278 } else { | 352 } else { |
279 view = (TextView) mInflater.inflate( | 353 view = (RelativeLayout) mInflater.inflate( |
280 R.layout.item_chooser_dialog_row, parent, false); | 354 R.layout.item_chooser_dialog_row, parent, false); |
281 } | 355 } |
282 | 356 |
283 // Set highlighting for currently selected item. | 357 boolean selected = position == mSelectedItem; |
284 if (position == mSelectedItem) { | 358 TextView description = (TextView) view.findViewById(R.id.description
); |
| 359 description.setText(getDisplayText(position)); |
| 360 |
| 361 if (selected) { |
285 view.setBackgroundColor(mBackgroundHighlightColor); | 362 view.setBackgroundColor(mBackgroundHighlightColor); |
286 view.setTextColor(Color.WHITE); | 363 description.setTextColor(Color.WHITE); |
287 } else { | 364 } else { |
288 view.setBackground(null); | 365 view.setBackground(null); |
289 if (!isEnabled(position)) { | 366 description.setTextColor( |
290 view.setTextColor(ApiCompatibilityUtils.getColor(getContext(
).getResources(), | 367 isEnabled(position) ? mDefaultTextColor : mDisabledTextC
olor); |
291 R.color.primary_text_disabled_material_light)); | |
292 } else { | |
293 view.setTextColor(mDefaultTextColor); | |
294 } | |
295 } | 368 } |
296 | 369 |
297 view.setText(getDisplayText(position)); | 370 LinearLayout imageContainer = (LinearLayout) view.findViewById(R.id.
imageContainer); |
| 371 imageContainer.setVisibility(hasIcon(position) ? View.VISIBLE : View
.GONE); |
| 372 if (hasIcon(position)) { |
| 373 ImageView icon = (ImageView) view.findViewById(R.id.icon); |
| 374 ItemChooserRowIcon rowIcon = getIcon(position); |
| 375 icon.setContentDescription(rowIcon.mIconDescription); |
| 376 icon.setImageResource(selected ? rowIcon.mSelectedIcon : rowIcon
.mNonSelectedIcon); |
| 377 } |
298 return view; | 378 return view; |
299 } | 379 } |
300 | 380 |
301 @Override | 381 @Override |
302 public void onItemClick(AdapterView<?> adapter, View view, int position,
long id) { | 382 public void onItemClick(AdapterView<?> adapter, View view, int position,
long id) { |
303 mSelectedItem = position; | 383 mSelectedItem = position; |
304 mConfirmButton.setEnabled(true); | 384 mConfirmButton.setEnabled(true); |
305 mItemAdapter.notifyDataSetChanged(); | 385 mItemAdapter.notifyDataSetChanged(); |
306 } | 386 } |
307 | 387 |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 } | 627 } |
548 | 628 |
549 /** | 629 /** |
550 * Returns the ItemAdapter associated with this class. For use with tests on
ly. | 630 * Returns the ItemAdapter associated with this class. For use with tests on
ly. |
551 */ | 631 */ |
552 @VisibleForTesting | 632 @VisibleForTesting |
553 public ItemAdapter getItemAdapterForTesting() { | 633 public ItemAdapter getItemAdapterForTesting() { |
554 return mItemAdapter; | 634 return mItemAdapter; |
555 } | 635 } |
556 } | 636 } |
OLD | NEW |