Chromium Code Reviews| 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.LinearLayout; | 24 import android.widget.LinearLayout; |
| 25 import android.widget.ListView; | 25 import android.widget.ListView; |
| 26 import android.widget.ProgressBar; | 26 import android.widget.ProgressBar; |
| 27 import android.widget.TextView; | 27 import android.widget.TextView; |
| 28 | 28 |
| 29 import org.chromium.base.ApiCompatibilityUtils; | |
| 30 import org.chromium.base.VisibleForTesting; | 29 import org.chromium.base.VisibleForTesting; |
| 31 import org.chromium.chrome.R; | 30 import org.chromium.chrome.R; |
| 32 import org.chromium.chrome.browser.util.MathUtils; | 31 import org.chromium.chrome.browser.util.MathUtils; |
| 33 import org.chromium.ui.base.DeviceFormFactor; | 32 import org.chromium.ui.base.DeviceFormFactor; |
| 34 import org.chromium.ui.widget.TextViewWithClickableSpans; | 33 import org.chromium.ui.widget.TextViewWithClickableSpans; |
| 35 | 34 |
| 36 import java.util.HashMap; | 35 import java.util.HashMap; |
| 37 import java.util.HashSet; | 36 import java.util.HashSet; |
| 38 import java.util.Map; | 37 import java.util.Map; |
| 39 import java.util.Set; | 38 import java.util.Set; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 55 * | 54 * |
| 56 * @param id The id of the item selected. Blank if the dialog was closed | 55 * @param id The id of the item selected. Blank if the dialog was closed |
| 57 * without selecting anything. | 56 * without selecting anything. |
| 58 */ | 57 */ |
| 59 void onItemSelected(String id); | 58 void onItemSelected(String id); |
| 60 } | 59 } |
| 61 | 60 |
| 62 /** | 61 /** |
| 63 * A class representing one data row in the picker. | 62 * A class representing one data row in the picker. |
| 64 */ | 63 */ |
| 65 public static class ItemChooserRow { | 64 public static class ItemChooserRow { |
|
Ted C
2016/10/20 21:50:18
should/can this class be private now?
ortuno
2016/10/21 02:14:07
Done.
| |
| 66 private final String mKey; | 65 private final String mKey; |
| 67 private String mDescription; | 66 private String mDescription; |
| 68 | 67 |
| 69 public ItemChooserRow(String key, String description) { | 68 public ItemChooserRow(String key, String description) { |
| 70 mKey = key; | 69 mKey = key; |
| 71 mDescription = description; | 70 mDescription = description; |
| 72 } | 71 } |
| 73 | 72 |
| 74 @Override | 73 public boolean hasSameContents(String key, String description) { |
|
Ted C
2016/10/20 21:50:18
non-private methods should have javadoc
ortuno
2016/10/21 02:14:07
Tests use hasSameContents and a follow up patch wi
| |
| 75 public boolean equals(Object obj) { | 74 if (!mKey.equals(key)) return false; |
|
Ted C
2016/10/20 21:50:18
use TextUtils.equals
ortuno
2016/10/21 02:14:07
Done.
| |
| 76 if (!(obj instanceof ItemChooserRow)) return false; | 75 if (!mDescription.equals(description)) return false; |
| 77 if (this == obj) return true; | 76 return true; |
| 78 ItemChooserRow item = (ItemChooserRow) obj; | |
| 79 return mKey.equals(item.mKey) && mDescription.equals(item.mDescripti on); | |
| 80 } | |
| 81 | |
| 82 @Override | |
| 83 public int hashCode() { | |
| 84 return mKey.hashCode() + mDescription.hashCode(); | |
| 85 } | 77 } |
| 86 } | 78 } |
| 87 | 79 |
| 88 /** | 80 /** |
| 89 * The labels to show in the dialog. | 81 * The labels to show in the dialog. |
| 90 */ | 82 */ |
| 91 public static class ItemChooserLabels { | 83 public static class ItemChooserLabels { |
| 92 // The title at the top of the dialog. | 84 // The title at the top of the dialog. |
| 93 public final CharSequence title; | 85 public final CharSequence title; |
| 94 // The message to show while there are no results. | 86 // The message to show while there are no results. |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 114 this.searching = searching; | 106 this.searching = searching; |
| 115 this.noneFound = noneFound; | 107 this.noneFound = noneFound; |
| 116 this.statusActive = statusActive; | 108 this.statusActive = statusActive; |
| 117 this.statusIdleNoneFound = statusIdleNoneFound; | 109 this.statusIdleNoneFound = statusIdleNoneFound; |
| 118 this.statusIdleSomeFound = statusIdleSomeFound; | 110 this.statusIdleSomeFound = statusIdleSomeFound; |
| 119 this.positiveButton = positiveButton; | 111 this.positiveButton = positiveButton; |
| 120 } | 112 } |
| 121 } | 113 } |
| 122 | 114 |
| 123 /** | 115 /** |
| 116 * Item holder for performance boost. | |
| 117 */ | |
| 118 private static class ViewHolder { | |
| 119 private TextView mTextView; | |
| 120 | |
| 121 public ViewHolder(View view) { | |
| 122 mTextView = (TextView) view.findViewById(R.id.description); | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 /** | |
| 124 * The various states the dialog can represent. | 127 * The various states the dialog can represent. |
| 125 */ | 128 */ |
| 126 private enum State { STARTING, PROGRESS_UPDATE_AVAILABLE, DISCOVERY_IDLE } | 129 private enum State { STARTING, PROGRESS_UPDATE_AVAILABLE, DISCOVERY_IDLE } |
| 127 | 130 |
| 128 /** | 131 /** |
| 129 * An adapter for keeping track of which items to show in the dialog. | 132 * An adapter for keeping track of which items to show in the dialog. |
| 130 */ | 133 */ |
| 131 public class ItemAdapter extends ArrayAdapter<ItemChooserRow> | 134 public class ItemAdapter extends ArrayAdapter<ItemChooserRow> |
| 132 implements AdapterView.OnItemClickListener { | 135 implements AdapterView.OnItemClickListener { |
| 133 private final LayoutInflater mInflater; | 136 private final LayoutInflater mInflater; |
| 134 | 137 |
| 135 // The background color of the highlighted item. | |
| 136 private final int mBackgroundHighlightColor; | |
| 137 | |
| 138 // The color of the non-highlighted text. | |
| 139 private final int mDefaultTextColor; | |
| 140 | |
| 141 // The zero-based index of the item currently selected in the dialog, | 138 // The zero-based index of the item currently selected in the dialog, |
| 142 // or -1 (INVALID_POSITION) if nothing is selected. | 139 // or -1 (INVALID_POSITION) if nothing is selected. |
| 143 private int mSelectedItem = ListView.INVALID_POSITION; | 140 private int mSelectedItem = ListView.INVALID_POSITION; |
| 144 | 141 |
| 145 // A set of keys that are marked as disabled in the dialog. | 142 // A set of keys that are marked as disabled in the dialog. |
| 146 private Set<String> mDisabledEntries = new HashSet<String>(); | 143 private Set<String> mDisabledEntries = new HashSet<String>(); |
| 147 | 144 |
| 148 // Item descriptions are counted in a map. | 145 // Item descriptions are counted in a map. |
| 149 private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); | 146 private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); |
| 150 | 147 |
| 151 // Map of keys to items so that we can access the items in O(1). | 148 // Map of keys to items so that we can access the items in O(1). |
| 152 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); | 149 private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); |
| 153 | 150 |
| 154 public ItemAdapter(Context context, int resource) { | 151 public ItemAdapter(Context context, int resource) { |
| 155 super(context, resource); | 152 super(context, resource); |
| 156 | 153 |
| 157 mInflater = LayoutInflater.from(context); | 154 mInflater = LayoutInflater.from(context); |
| 158 | |
| 159 mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContex t().getResources(), | |
| 160 R.color.light_active_color); | |
| 161 mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getR esources(), | |
| 162 R.color.default_text_color); | |
| 163 } | 155 } |
| 164 | 156 |
| 165 @Override | 157 @Override |
| 166 public boolean isEmpty() { | 158 public boolean isEmpty() { |
| 167 boolean isEmpty = super.isEmpty(); | 159 boolean isEmpty = super.isEmpty(); |
| 168 if (isEmpty) { | 160 if (isEmpty) { |
| 169 assert mKeyToItemMap.isEmpty(); | 161 assert mKeyToItemMap.isEmpty(); |
| 170 assert mDisabledEntries.isEmpty(); | 162 assert mDisabledEntries.isEmpty(); |
| 171 assert mItemDescriptionMap.isEmpty(); | 163 assert mItemDescriptionMap.isEmpty(); |
| 172 } else { | 164 } else { |
| 173 assert !mKeyToItemMap.isEmpty(); | 165 assert !mKeyToItemMap.isEmpty(); |
| 174 assert !mItemDescriptionMap.isEmpty(); | 166 assert !mItemDescriptionMap.isEmpty(); |
| 175 } | 167 } |
| 176 return isEmpty; | 168 return isEmpty; |
| 177 } | 169 } |
| 178 | 170 |
| 179 public void addOrUpdate(ItemChooserRow item) { | 171 public void addOrUpdate(String key, String description) { |
| 180 ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey); | 172 ItemChooserRow oldItem = mKeyToItemMap.get(key); |
| 181 if (oldItem != null) { | 173 if (oldItem != null) { |
| 182 if (oldItem.equals(item)) { | 174 if (oldItem.hasSameContents(key, description)) { |
| 183 // No need to update anything. | 175 // No need to update anything. |
| 184 return; | 176 return; |
| 185 } | 177 } |
| 186 if (!oldItem.mDescription.equals(item.mDescription)) { | 178 |
| 179 if (!oldItem.mDescription.equals(description)) { | |
|
Ted C
2016/10/20 21:50:18
I would use TextUtils.equals here instead (incase
ortuno
2016/10/21 02:14:07
Ah good idea. I didn't know about TextUtils. Done.
| |
| 187 removeFromDescriptionsMap(oldItem.mDescription); | 180 removeFromDescriptionsMap(oldItem.mDescription); |
| 188 oldItem.mDescription = item.mDescription; | 181 oldItem.mDescription = description; |
| 189 addToDescriptionsMap(oldItem.mDescription); | 182 addToDescriptionsMap(oldItem.mDescription); |
| 190 } | 183 } |
| 184 | |
| 191 notifyDataSetChanged(); | 185 notifyDataSetChanged(); |
| 192 return; | 186 return; |
| 193 } | 187 } |
| 194 ItemChooserRow result = mKeyToItemMap.put(item.mKey, item); | |
| 195 assert result == null; | |
| 196 | 188 |
| 197 addToDescriptionsMap(item.mDescription); | 189 assert !mKeyToItemMap.containsKey(key); |
| 198 add(item); | 190 ItemChooserRow newItem = new ItemChooserRow(key, description); |
| 191 mKeyToItemMap.put(key, newItem); | |
| 192 | |
| 193 addToDescriptionsMap(newItem.mDescription); | |
| 194 add(newItem); | |
| 199 } | 195 } |
| 200 | 196 |
| 201 @Override | 197 public void remove(String key) { |
|
Ted C
2016/10/20 21:50:18
I would try to avoid overloads of names in the pub
ortuno
2016/10/21 02:14:07
Done.
| |
| 202 public void remove(ItemChooserRow item) { | 198 ItemChooserRow oldItem = mKeyToItemMap.remove(key); |
| 203 ItemChooserRow oldItem = mKeyToItemMap.remove(item.mKey); | |
| 204 if (oldItem == null) return; | 199 if (oldItem == null) return; |
| 205 int oldItemPosition = getPosition(oldItem); | 200 int oldItemPosition = getPosition(oldItem); |
| 206 // If the removed item is the item that is currently selected, desel ect it | 201 // If the removed item is the item that is currently selected, desel ect it |
| 207 // and disable the confirm button. Otherwise if the removed item is before | 202 // and disable the confirm button. Otherwise if the removed item is before |
| 208 // the currently selected item, the currently selected item's index needs | 203 // the currently selected item, the currently selected item's index needs |
| 209 // to be adjusted by one. | 204 // to be adjusted by one. |
| 210 if (oldItemPosition == mSelectedItem) { | 205 if (oldItemPosition == mSelectedItem) { |
| 211 mSelectedItem = ListView.INVALID_POSITION; | 206 mSelectedItem = ListView.INVALID_POSITION; |
| 212 mConfirmButton.setEnabled(false); | 207 mConfirmButton.setEnabled(false); |
| 213 } else if (oldItemPosition < mSelectedItem) { | 208 } else if (oldItemPosition < mSelectedItem) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 return 1; | 280 return 1; |
| 286 } | 281 } |
| 287 | 282 |
| 288 @Override | 283 @Override |
| 289 public long getItemId(int position) { | 284 public long getItemId(int position) { |
| 290 return position; | 285 return position; |
| 291 } | 286 } |
| 292 | 287 |
| 293 @Override | 288 @Override |
| 294 public View getView(int position, View convertView, ViewGroup parent) { | 289 public View getView(int position, View convertView, ViewGroup parent) { |
| 295 TextView view; | 290 ViewHolder row; |
| 296 if (convertView instanceof TextView) { | 291 if (convertView == null) { |
| 297 view = (TextView) convertView; | 292 convertView = mInflater.inflate(R.layout.item_chooser_dialog_row , parent, false); |
| 293 row = new ViewHolder(convertView); | |
| 294 convertView.setTag(row); | |
| 298 } else { | 295 } else { |
| 299 view = (TextView) mInflater.inflate( | 296 row = (ViewHolder) convertView.getTag(); |
| 300 R.layout.item_chooser_dialog_row, parent, false); | |
| 301 } | 297 } |
| 302 | 298 |
| 303 // Set highlighting for currently selected item. | 299 row.mTextView.setEnabled(isEnabled(position)); |
| 304 if (position == mSelectedItem) { | 300 row.mTextView.setText(getDisplayText(position)); |
| 305 view.setBackgroundColor(mBackgroundHighlightColor); | |
| 306 view.setTextColor(Color.WHITE); | |
| 307 } else { | |
| 308 view.setBackground(null); | |
| 309 if (!isEnabled(position)) { | |
| 310 view.setTextColor(ApiCompatibilityUtils.getColor(getContext( ).getResources(), | |
| 311 R.color.primary_text_disabled_material_light)); | |
| 312 } else { | |
| 313 view.setTextColor(mDefaultTextColor); | |
| 314 } | |
| 315 } | |
| 316 | 301 |
| 317 view.setText(getDisplayText(position)); | 302 return convertView; |
| 318 return view; | |
| 319 } | 303 } |
| 320 | 304 |
| 321 @Override | 305 @Override |
| 322 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { | 306 public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { |
| 323 mSelectedItem = position; | 307 mSelectedItem = position; |
| 324 mConfirmButton.setEnabled(true); | 308 mConfirmButton.setEnabled(true); |
| 325 mItemAdapter.notifyDataSetChanged(); | 309 notifyDataSetChanged(); |
| 326 } | 310 } |
| 327 | 311 |
| 328 private void addToDescriptionsMap(String description) { | 312 private void addToDescriptionsMap(String description) { |
| 329 int count = mItemDescriptionMap.containsKey(description) | 313 int count = mItemDescriptionMap.containsKey(description) |
| 330 ? mItemDescriptionMap.get(description) | 314 ? mItemDescriptionMap.get(description) |
| 331 : 0; | 315 : 0; |
| 332 mItemDescriptionMap.put(description, count + 1); | 316 mItemDescriptionMap.put(description, count + 1); |
| 333 } | 317 } |
| 334 | 318 |
| 335 private void removeFromDescriptionsMap(String description) { | 319 private void removeFromDescriptionsMap(String description) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 public void onClick(View v) { | 398 public void onClick(View v) { |
| 415 mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedIte mKey()); | 399 mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedIte mKey()); |
| 416 mDialog.setOnDismissListener(null); | 400 mDialog.setOnDismissListener(null); |
| 417 mDialog.dismiss(); | 401 mDialog.dismiss(); |
| 418 } | 402 } |
| 419 }); | 403 }); |
| 420 | 404 |
| 421 mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_r ow); | 405 mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_r ow); |
| 422 mItemAdapter.setNotifyOnChange(true); | 406 mItemAdapter.setNotifyOnChange(true); |
| 423 mListView.setAdapter(mItemAdapter); | 407 mListView.setAdapter(mItemAdapter); |
| 408 mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); | |
| 424 mListView.setEmptyView(mEmptyMessage); | 409 mListView.setEmptyView(mEmptyMessage); |
| 425 mListView.setOnItemClickListener(mItemAdapter); | 410 mListView.setOnItemClickListener(mItemAdapter); |
| 426 mListView.setDivider(null); | 411 mListView.setDivider(null); |
| 427 setState(State.STARTING); | 412 setState(State.STARTING); |
| 428 | 413 |
| 429 // The list is the main element in the dialog and it should grow and | 414 // The list is the main element in the dialog and it should grow and |
| 430 // shrink according to the size of the screen available. | 415 // shrink according to the size of the screen available. |
| 431 View listViewContainer = dialogContainer.findViewById(R.id.container); | 416 View listViewContainer = dialogContainer.findViewById(R.id.container); |
| 432 listViewContainer.setLayoutParams(new LinearLayout.LayoutParams( | 417 listViewContainer.setLayoutParams(new LinearLayout.LayoutParams( |
| 433 LayoutParams.MATCH_PARENT, | 418 LayoutParams.MATCH_PARENT, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 } | 464 } |
| 480 | 465 |
| 481 mDialog.show(); | 466 mDialog.show(); |
| 482 } | 467 } |
| 483 | 468 |
| 484 public void dismiss() { | 469 public void dismiss() { |
| 485 mDialog.dismiss(); | 470 mDialog.dismiss(); |
| 486 } | 471 } |
| 487 | 472 |
| 488 /** | 473 /** |
| 489 * Add an item to the end of the list to show in the dialog if the item | 474 * Adds an item to the end of the list to show in the dialog if the item |
| 490 * was not in the chooser. Otherwise update the items description. | 475 * was not in the chooser. Otherwise updates the items description. |
| 491 * | 476 * |
| 492 * @param item The item to be added to the end of the chooser or updated. | 477 * @param key Unique identifier for that item. |
| 493 */ | 478 * @param description Text in the row. |
| 494 public void addOrUpdateItem(ItemChooserRow item) { | 479 */ |
| 480 public void addOrUpdateItem(String key, String description) { | |
| 495 mProgressBar.setVisibility(View.GONE); | 481 mProgressBar.setVisibility(View.GONE); |
| 496 mItemAdapter.addOrUpdate(item); | 482 mItemAdapter.addOrUpdate(key, description); |
| 497 setState(State.PROGRESS_UPDATE_AVAILABLE); | 483 setState(State.PROGRESS_UPDATE_AVAILABLE); |
| 498 } | 484 } |
| 499 | 485 |
| 500 /** | 486 /** |
| 501 * Remove an item that is shown in the dialog. | 487 * Removes an item that is shown in the dialog. |
| 502 * | 488 * |
| 503 * @param item The item to be removed in the chooser. | 489 * @param key Unique identifier for the item. |
| 504 */ | 490 */ |
| 505 public void removeItemFromList(ItemChooserRow item) { | 491 public void removeItemFromList(String key) { |
| 506 mItemAdapter.remove(item); | 492 mItemAdapter.remove(key); |
| 507 setState(State.DISCOVERY_IDLE); | 493 setState(State.DISCOVERY_IDLE); |
| 508 } | 494 } |
| 509 | 495 |
| 510 /** | 496 /** |
| 511 * Indicates the chooser that no more items will be added. | 497 * Indicates the chooser that no more items will be added. |
| 512 */ | 498 */ |
| 513 public void setIdleState() { | 499 public void setIdleState() { |
| 514 mProgressBar.setVisibility(View.GONE); | 500 mProgressBar.setVisibility(View.GONE); |
| 515 setState(State.DISCOVERY_IDLE); | 501 setState(State.DISCOVERY_IDLE); |
| 516 } | 502 } |
| 517 | 503 |
| 518 /** | 504 /** |
| 519 * Sets whether the item is enabled. | 505 * Sets whether the item is enabled. |
| 520 * @param id The id of the item to affect. | 506 * @param key Unique indetifier for the item. |
| 521 * @param enabled Whether the item should be enabled or not. | 507 * @param enabled Whether the item should be enabled or not. |
| 522 */ | 508 */ |
| 523 public void setEnabled(String id, boolean enabled) { | 509 public void setEnabled(String key, boolean enabled) { |
| 524 mItemAdapter.setEnabled(id, enabled); | 510 mItemAdapter.setEnabled(key, enabled); |
| 525 } | 511 } |
| 526 | 512 |
| 527 /** | 513 /** |
| 528 * Clear all items from the dialog. | 514 * Clear all items from the dialog. |
| 529 */ | 515 */ |
| 530 public void clear() { | 516 public void clear() { |
| 531 mItemAdapter.clear(); | 517 mItemAdapter.clear(); |
| 532 setState(State.STARTING); | 518 setState(State.STARTING); |
| 533 } | 519 } |
| 534 | 520 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 } | 561 } |
| 576 | 562 |
| 577 /** | 563 /** |
| 578 * Returns the ItemAdapter associated with this class. For use with tests on ly. | 564 * Returns the ItemAdapter associated with this class. For use with tests on ly. |
| 579 */ | 565 */ |
| 580 @VisibleForTesting | 566 @VisibleForTesting |
| 581 public ItemAdapter getItemAdapterForTesting() { | 567 public ItemAdapter getItemAdapterForTesting() { |
| 582 return mItemAdapter; | 568 return mItemAdapter; |
| 583 } | 569 } |
| 584 } | 570 } |
| OLD | NEW |