Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java

Issue 2271413002: bluetooth: Implement RSSI indicator on android (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bluetooth-impl-rssi-tx-power
Patch Set: Copyright and clean up Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.graphics.drawable.Drawable;
13 import android.text.SpannableString; 14 import android.text.SpannableString;
14 import android.text.method.LinkMovementMethod; 15 import android.text.method.LinkMovementMethod;
15 import android.view.Gravity; 16 import android.view.Gravity;
16 import android.view.LayoutInflater; 17 import android.view.LayoutInflater;
17 import android.view.View; 18 import android.view.View;
18 import android.view.ViewGroup; 19 import android.view.ViewGroup;
19 import android.view.ViewGroup.LayoutParams; 20 import android.view.ViewGroup.LayoutParams;
20 import android.view.Window; 21 import android.view.Window;
21 import android.widget.AdapterView; 22 import android.widget.AdapterView;
22 import android.widget.ArrayAdapter; 23 import android.widget.ArrayAdapter;
23 import android.widget.Button; 24 import android.widget.Button;
25 import android.widget.ImageView;
24 import android.widget.LinearLayout; 26 import android.widget.LinearLayout;
25 import android.widget.ListView; 27 import android.widget.ListView;
26 import android.widget.ProgressBar; 28 import android.widget.ProgressBar;
29 import android.widget.RelativeLayout;
27 import android.widget.TextView; 30 import android.widget.TextView;
28 31
29 import org.chromium.base.ApiCompatibilityUtils; 32 import org.chromium.base.ApiCompatibilityUtils;
30 import org.chromium.base.VisibleForTesting; 33 import org.chromium.base.VisibleForTesting;
31 import org.chromium.chrome.R; 34 import org.chromium.chrome.R;
32 import org.chromium.chrome.browser.util.MathUtils; 35 import org.chromium.chrome.browser.util.MathUtils;
33 import org.chromium.ui.base.DeviceFormFactor; 36 import org.chromium.ui.base.DeviceFormFactor;
34 import org.chromium.ui.widget.TextViewWithClickableSpans; 37 import org.chromium.ui.widget.TextViewWithClickableSpans;
35 38
36 import java.util.HashMap; 39 import java.util.HashMap;
(...skipping 16 matching lines...) Expand all
53 /** 56 /**
54 * Returns the user selection. 57 * Returns the user selection.
55 * 58 *
56 * @param id The id of the item selected. Blank if the dialog was closed 59 * @param id The id of the item selected. Blank if the dialog was closed
57 * without selecting anything. 60 * without selecting anything.
58 */ 61 */
59 void onItemSelected(String id); 62 void onItemSelected(String id);
60 } 63 }
61 64
62 /** 65 /**
66 * A class representing an icon to be shown in a chooser row.
67 */
68 public static class ItemChooserRowIcon {
Ian Wen 2016/09/26 18:12:48 I would vote for using level list drawable instead
juncai 2016/09/26 18:49:01 Question: if we use LevelListDrawable here, can ot
Ian Wen 2016/09/26 21:39:33 The dialog can store just a drawable, and it can s
ortuno 2016/09/26 23:34:48 Some context: ItemChooserDialog is a class that i
Ian Wen 2016/09/27 04:22:41 Thanks for the explanation! If you are worried ab
ortuno 2016/10/04 07:16:18 Thanks for the article and CL :) I really apprecia
69 private Drawable mNonSelectedIcon;
70 // Icon when the row is selected.
71 private Drawable mSelectedIcon;
72 private String mIconDescription;
73
74 public ItemChooserRowIcon(
75 Drawable nonSelectedIcon, Drawable selectedIcon, String iconDesc ription) {
76 mNonSelectedIcon = nonSelectedIcon;
77 mSelectedIcon = selectedIcon;
78 mIconDescription = iconDescription;
79 }
80
81 @Override
82 public boolean equals(Object obj) {
83 if (!(obj instanceof ItemChooserRowIcon)) return false;
84 if (this == obj) return true;
85 ItemChooserRowIcon icon = (ItemChooserRowIcon) obj;
86 return mNonSelectedIcon.getConstantState().equals(
87 icon.mNonSelectedIcon.getConstantState())
88 && mSelectedIcon.getConstantState().equals(
89 icon.mSelectedIcon.getConstantState())
90 && mIconDescription.equals(icon.mIconDescription);
91 }
92
93 @Override
94 public String toString() {
95 return mNonSelectedIcon + ":" + mSelectedIcon + ":" + mIconDescripti on;
96 }
97
98 @Override
99 public int hashCode() {
100 return mNonSelectedIcon.hashCode() + mSelectedIcon.hashCode()
101 + mIconDescription.hashCode();
102 }
103 }
104
105 /**
63 * A class representing one data row in the picker. 106 * A class representing one data row in the picker.
64 */ 107 */
65 public static class ItemChooserRow { 108 public static class ItemChooserRow {
66 private final String mKey; 109 private final String mKey;
67 private String mDescription; 110 private String mDescription;
111 private ItemChooserRowIcon mIcon;
112
113 public ItemChooserRow(String key, String description, ItemChooserRowIcon icon) {
114 mKey = key;
115 mDescription = description;
116 mIcon = icon;
117 }
68 118
69 public ItemChooserRow(String key, String description) { 119 public ItemChooserRow(String key, String description) {
70 mKey = key; 120 this(key, description, null);
71 mDescription = description;
72 } 121 }
73 122
74 @Override 123 @Override
75 public boolean equals(Object obj) { 124 public boolean equals(Object obj) {
76 if (!(obj instanceof ItemChooserRow)) return false; 125 if (!(obj instanceof ItemChooserRow)) return false;
77 if (this == obj) return true; 126 if (this == obj) return true;
78 ItemChooserRow item = (ItemChooserRow) obj; 127 ItemChooserRow item = (ItemChooserRow) obj;
79 return mKey.equals(item.mKey) && mDescription.equals(item.mDescripti on); 128
129 if (mIcon == null ^ item.mIcon == null) return false;
130
131 if (mIcon != null && item.mIcon != null && !mIcon.equals(item.mIcon) ) return false;
132
133 if (mKey.equals(item.mKey) && mDescription.equals(item.mDescription) ) return true;
134
135 return false;
80 } 136 }
81 137
82 @Override 138 @Override
83 public int hashCode() { 139 public int hashCode() {
84 return mKey.hashCode() + mDescription.hashCode(); 140 return mKey.hashCode() + mDescription.hashCode() + mIcon.hashCode();
141 }
142
143 @Override
144 public String toString() {
145 return mKey + ":" + mDescription + ":" + mIcon.toString();
85 } 146 }
86 } 147 }
87 148
88 /** 149 /**
89 * The labels to show in the dialog. 150 * The labels to show in the dialog.
90 */ 151 */
91 public static class ItemChooserLabels { 152 public static class ItemChooserLabels {
92 // The title at the top of the dialog. 153 // The title at the top of the dialog.
93 public final CharSequence title; 154 public final CharSequence title;
94 // The message to show while there are no results. 155 // The message to show while there are no results.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 public class ItemAdapter extends ArrayAdapter<ItemChooserRow> 192 public class ItemAdapter extends ArrayAdapter<ItemChooserRow>
132 implements AdapterView.OnItemClickListener { 193 implements AdapterView.OnItemClickListener {
133 private final LayoutInflater mInflater; 194 private final LayoutInflater mInflater;
134 195
135 // The background color of the highlighted item. 196 // The background color of the highlighted item.
136 private final int mBackgroundHighlightColor; 197 private final int mBackgroundHighlightColor;
137 198
138 // The color of the non-highlighted text. 199 // The color of the non-highlighted text.
139 private final int mDefaultTextColor; 200 private final int mDefaultTextColor;
140 201
202 // The color of disabled text.
203 private final int mDisabledTextColor;
204
205 // Indicates whether rows will contain an icon.
206 private boolean mUsingIcon;
207
141 // The zero-based index of the item currently selected in the dialog, 208 // The zero-based index of the item currently selected in the dialog,
142 // or -1 (INVALID_POSITION) if nothing is selected. 209 // or -1 (INVALID_POSITION) if nothing is selected.
143 private int mSelectedItem = ListView.INVALID_POSITION; 210 private int mSelectedItem = ListView.INVALID_POSITION;
144 211
145 // A set of keys that are marked as disabled in the dialog. 212 // A set of keys that are marked as disabled in the dialog.
146 private Set<String> mDisabledEntries = new HashSet<String>(); 213 private Set<String> mDisabledEntries = new HashSet<String>();
147 214
148 // Item descriptions are counted in a map. 215 // Item descriptions are counted in a map.
149 private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); 216 private Map<String, Integer> mItemDescriptionMap = new HashMap<>();
150 217
151 // Map of keys to items so that we can access the items in O(1). 218 // Map of keys to items so that we can access the items in O(1).
152 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); 219 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>();
153 220
154 public ItemAdapter(Context context, int resource) { 221 public ItemAdapter(Context context, int resource, boolean usingIcon) {
155 super(context, resource); 222 super(context, resource);
156 223
157 mInflater = LayoutInflater.from(context); 224 mInflater = LayoutInflater.from(context);
158 225
226 mUsingIcon = usingIcon;
227
159 mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContex t().getResources(), 228 mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContex t().getResources(),
160 R.color.light_active_color); 229 R.color.light_active_color);
161 mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getR esources(), 230 mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getR esources(),
162 R.color.default_text_color); 231 R.color.default_text_color);
232 mDisabledTextColor = ApiCompatibilityUtils.getColor(
233 getContext().getResources(), R.color.primary_text_disabled_m aterial_light);
163 } 234 }
164 235
165 @Override 236 @Override
166 public boolean isEmpty() { 237 public boolean isEmpty() {
167 boolean isEmpty = super.isEmpty(); 238 boolean isEmpty = super.isEmpty();
168 if (isEmpty) { 239 if (isEmpty) {
169 assert mKeyToItemMap.isEmpty(); 240 assert mKeyToItemMap.isEmpty();
170 assert mDisabledEntries.isEmpty(); 241 assert mDisabledEntries.isEmpty();
171 assert mItemDescriptionMap.isEmpty(); 242 assert mItemDescriptionMap.isEmpty();
172 } else { 243 } else {
173 assert !mKeyToItemMap.isEmpty(); 244 assert !mKeyToItemMap.isEmpty();
174 assert !mItemDescriptionMap.isEmpty(); 245 assert !mItemDescriptionMap.isEmpty();
175 } 246 }
176 return isEmpty; 247 return isEmpty;
177 } 248 }
178 249
179 public void addOrUpdate(ItemChooserRow item) { 250 public void addOrUpdate(ItemChooserRow item) {
180 ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey); 251 ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey);
181 if (oldItem != null) { 252 if (oldItem != null) {
182 if (oldItem.equals(item)) { 253 if (oldItem.equals(item)) {
183 // No need to update anything. 254 // No need to update anything.
184 return; 255 return;
185 } 256 }
186 if (!oldItem.mDescription.equals(item.mDescription)) { 257 if (!oldItem.mDescription.equals(item.mDescription)) {
187 removeFromDescriptionsMap(oldItem.mDescription); 258 removeFromDescriptionsMap(oldItem.mDescription);
188 oldItem.mDescription = item.mDescription; 259 oldItem.mDescription = item.mDescription;
189 addToDescriptionsMap(oldItem.mDescription); 260 addToDescriptionsMap(oldItem.mDescription);
190 } 261 }
262 if (item.mIcon != null
263 && (oldItem.mIcon == null || !oldItem.mIcon.equals(item. mIcon))) {
264 oldItem.mIcon = item.mIcon;
265 }
191 notifyDataSetChanged(); 266 notifyDataSetChanged();
192 return; 267 return;
193 } 268 }
194 ItemChooserRow result = mKeyToItemMap.put(item.mKey, item); 269 ItemChooserRow result = mKeyToItemMap.put(item.mKey, item);
195 assert result == null; 270 assert result == null;
196 271
197 addToDescriptionsMap(item.mDescription); 272 addToDescriptionsMap(item.mDescription);
198 add(item); 273 add(item);
199 } 274 }
200 275
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 */ 308 */
234 public String getDisplayText(int position) { 309 public String getDisplayText(int position) {
235 ItemChooserRow item = getItem(position); 310 ItemChooserRow item = getItem(position);
236 String description = item.mDescription; 311 String description = item.mDescription;
237 int counter = mItemDescriptionMap.get(description); 312 int counter = mItemDescriptionMap.get(description);
238 return counter == 1 ? description 313 return counter == 1 ? description
239 : mActivity.getString(R.string.item_chooser_item_name_with_i d, description, 314 : mActivity.getString(R.string.item_chooser_item_name_with_i d, description,
240 item.mKey); 315 item.mKey);
241 } 316 }
242 317
318 public ItemChooserRowIcon getIcon(int position) {
319 ItemChooserRow item = getItem(position);
320 return item.mIcon;
321 }
322
323 public boolean hasIcon(int position) {
324 ItemChooserRow item = getItem(position);
325 return item.mIcon != null;
326 }
327
243 /** 328 /**
244 * Sets whether the itam is enabled. Disabled items are grayed out. 329 * Sets whether the itam is enabled. Disabled items are grayed out.
245 * @param id The id of the item to affect. 330 * @param id The id of the item to affect.
246 * @param enabled Whether the item should be enabled or not. 331 * @param enabled Whether the item should be enabled or not.
247 */ 332 */
248 public void setEnabled(String id, boolean enabled) { 333 public void setEnabled(String id, boolean enabled) {
249 if (enabled) { 334 if (enabled) {
250 mDisabledEntries.remove(id); 335 mDisabledEntries.remove(id);
251 } else { 336 } else {
252 mDisabledEntries.add(id); 337 mDisabledEntries.add(id);
(...skipping 12 matching lines...) Expand all
265 return 1; 350 return 1;
266 } 351 }
267 352
268 @Override 353 @Override
269 public long getItemId(int position) { 354 public long getItemId(int position) {
270 return position; 355 return position;
271 } 356 }
272 357
273 @Override 358 @Override
274 public View getView(int position, View convertView, ViewGroup parent) { 359 public View getView(int position, View convertView, ViewGroup parent) {
275 TextView view; 360 RelativeLayout view;
276 if (convertView instanceof TextView) { 361 if (convertView instanceof RelativeLayout) {
277 view = (TextView) convertView; 362 view = (RelativeLayout) convertView;
278 } else { 363 } else {
279 view = (TextView) mInflater.inflate( 364 view = (RelativeLayout) mInflater.inflate(
280 R.layout.item_chooser_dialog_row, parent, false); 365 R.layout.item_chooser_dialog_row, parent, false);
281 } 366 }
282 367
283 // Set highlighting for currently selected item. 368 boolean selected = position == mSelectedItem;
284 if (position == mSelectedItem) { 369 TextView description = (TextView) view.findViewById(R.id.description );
370 description.setText(getDisplayText(position));
371
372 if (selected) {
285 view.setBackgroundColor(mBackgroundHighlightColor); 373 view.setBackgroundColor(mBackgroundHighlightColor);
286 view.setTextColor(Color.WHITE); 374 description.setTextColor(Color.WHITE);
287 } else { 375 } else {
288 view.setBackground(null); 376 view.setBackground(null);
289 if (!isEnabled(position)) { 377 description.setTextColor(
290 view.setTextColor(ApiCompatibilityUtils.getColor(getContext( ).getResources(), 378 isEnabled(position) ? mDefaultTextColor : mDisabledTextC olor);
291 R.color.primary_text_disabled_material_light));
292 } else {
293 view.setTextColor(mDefaultTextColor);
294 }
295 } 379 }
296 380
297 view.setText(getDisplayText(position)); 381 LinearLayout imageContainer = (LinearLayout) view.findViewById(R.id. imageContainer);
382 if (mUsingIcon) {
383 ImageView icon = (ImageView) view.findViewById(R.id.icon);
384 if (hasIcon(position)) {
385 imageContainer.setVisibility(View.VISIBLE);
386 ItemChooserRowIcon rowIcon = getIcon(position);
387 icon.setContentDescription(rowIcon.mIconDescription);
Ian Wen 2016/09/26 18:12:48 If you choose to use level drawable, you might wan
388 icon.setImageDrawable(
389 selected ? rowIcon.mSelectedIcon : rowIcon.mNonSelec tedIcon);
390 } else {
391 imageContainer.setVisibility(View.INVISIBLE);
392 icon.setContentDescription(null);
393 icon.setImageDrawable(null);
394 }
395 } else {
396 imageContainer.setVisibility(View.GONE);
397 }
298 return view; 398 return view;
299 } 399 }
300 400
301 @Override 401 @Override
302 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { 402 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
303 mSelectedItem = position; 403 mSelectedItem = position;
304 mConfirmButton.setEnabled(true); 404 mConfirmButton.setEnabled(true);
305 mItemAdapter.notifyDataSetChanged(); 405 mItemAdapter.notifyDataSetChanged();
306 } 406 }
307 407
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 // The maximum height of the listview in the dialog (in dp). 456 // The maximum height of the listview in the dialog (in dp).
357 private static final int MAX_HEIGHT_DP = (int) (LIST_ROW_HEIGHT_DP * 8.5); 457 private static final int MAX_HEIGHT_DP = (int) (LIST_ROW_HEIGHT_DP * 8.5);
358 458
359 /** 459 /**
360 * Creates the ItemChooserPopup and displays it (and starts waiting for data ). 460 * Creates the ItemChooserPopup and displays it (and starts waiting for data ).
361 * 461 *
362 * @param activity Activity which is used for launching a dialog. 462 * @param activity Activity which is used for launching a dialog.
363 * @param callback The callback used to communicate back what was selected. 463 * @param callback The callback used to communicate back what was selected.
364 * @param labels The labels to show in the dialog. 464 * @param labels The labels to show in the dialog.
365 */ 465 */
366 public ItemChooserDialog( 466 public ItemChooserDialog(Activity activity, ItemSelectedCallback callback,
367 Activity activity, ItemSelectedCallback callback, ItemChooserLabels labels) { 467 ItemChooserLabels labels, boolean usingIcon) {
368 mActivity = activity; 468 mActivity = activity;
369 mItemSelectedCallback = callback; 469 mItemSelectedCallback = callback;
370 mLabels = labels; 470 mLabels = labels;
371 471
372 LinearLayout dialogContainer = (LinearLayout) LayoutInflater.from(mActiv ity).inflate( 472 LinearLayout dialogContainer = (LinearLayout) LayoutInflater.from(mActiv ity).inflate(
373 R.layout.item_chooser_dialog, null); 473 R.layout.item_chooser_dialog, null);
374 474
375 mListView = (ListView) dialogContainer.findViewById(R.id.items); 475 mListView = (ListView) dialogContainer.findViewById(R.id.items);
376 mProgressBar = (ProgressBar) dialogContainer.findViewById(R.id.progress) ; 476 mProgressBar = (ProgressBar) dialogContainer.findViewById(R.id.progress) ;
377 mStatus = (TextView) dialogContainer.findViewById(R.id.status); 477 mStatus = (TextView) dialogContainer.findViewById(R.id.status);
(...skipping 13 matching lines...) Expand all
391 mConfirmButton.setEnabled(false); 491 mConfirmButton.setEnabled(false);
392 mConfirmButton.setOnClickListener(new View.OnClickListener() { 492 mConfirmButton.setOnClickListener(new View.OnClickListener() {
393 @Override 493 @Override
394 public void onClick(View v) { 494 public void onClick(View v) {
395 mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedIte mKey()); 495 mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedIte mKey());
396 mDialog.setOnDismissListener(null); 496 mDialog.setOnDismissListener(null);
397 mDialog.dismiss(); 497 mDialog.dismiss();
398 } 498 }
399 }); 499 });
400 500
401 mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_r ow); 501 mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_r ow, usingIcon);
402 mListView.setAdapter(mItemAdapter); 502 mListView.setAdapter(mItemAdapter);
403 mListView.setEmptyView(mEmptyMessage); 503 mListView.setEmptyView(mEmptyMessage);
404 mListView.setOnItemClickListener(mItemAdapter); 504 mListView.setOnItemClickListener(mItemAdapter);
405 mListView.setDivider(null); 505 mListView.setDivider(null);
406 setState(State.STARTING); 506 setState(State.STARTING);
407 507
408 // The list is the main element in the dialog and it should grow and 508 // The list is the main element in the dialog and it should grow and
409 // shrink according to the size of the screen available. 509 // shrink according to the size of the screen available.
410 View listViewContainer = dialogContainer.findViewById(R.id.container); 510 View listViewContainer = dialogContainer.findViewById(R.id.container);
411 listViewContainer.setLayoutParams(new LinearLayout.LayoutParams( 511 listViewContainer.setLayoutParams(new LinearLayout.LayoutParams(
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 } 647 }
548 648
549 /** 649 /**
550 * Returns the ItemAdapter associated with this class. For use with tests on ly. 650 * Returns the ItemAdapter associated with this class. For use with tests on ly.
551 */ 651 */
552 @VisibleForTesting 652 @VisibleForTesting
553 public ItemAdapter getItemAdapterForTesting() { 653 public ItemAdapter getItemAdapterForTesting() {
554 return mItemAdapter; 654 return mItemAdapter;
555 } 655 }
556 } 656 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698