Add a header view to show the country in RegionZonePicker

Extra fixes in this CL
- Minor string update in time zone picker.
  Use date_time_search_region string in search bar,
  and date_time_set_timezone_title string for lower case "zone".
- Fixed b/76893139. Remove the unnecessary top padding in RecyclerView.
  Create a new layout file time_zone_items_list.xml without the padding.
- Add missing return statement when region ISO code
  is invalid in RegionZonePicker#getAllTimeZoneInfos

Bug: 76209571
Bug: 76893139
Test: m RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.datetime.timezone
Test: Verified that the strings are updated in the UI
Change-Id: I1fb3e2abf80da3cb53cfbc3363bbe46e40a6ac22
This commit is contained in:
Victor Chang
2018-03-27 17:34:53 +01:00
parent 201c629fcc
commit 65f09f3091
11 changed files with 161 additions and 32 deletions

View File

@@ -18,6 +18,7 @@ package com.android.settings.datetime.timezone;
import android.icu.text.BreakIterator;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.support.v7.widget.RecyclerView;
@@ -40,48 +41,98 @@ import java.util.Locale;
* {@class AdapterItem} must be provided when an instance is created.
*/
public class BaseTimeZoneAdapter<T extends BaseTimeZoneAdapter.AdapterItem>
extends RecyclerView.Adapter<BaseTimeZoneAdapter.ItemViewHolder> {
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@VisibleForTesting
static final int TYPE_HEADER = 0;
@VisibleForTesting
static final int TYPE_ITEM = 1;
private final List<T> mOriginalItems;
private final OnListItemClickListener<T> mOnListItemClickListener;
private final Locale mLocale;
private final boolean mShowItemSummary;
private final boolean mShowHeader;
private final CharSequence mHeaderText;
private List<T> mItems;
private ArrayFilter mFilter;
public BaseTimeZoneAdapter(List<T> items, OnListItemClickListener<T>
onListItemClickListener, Locale locale, boolean showItemSummary) {
/**
* @param headerText the text shown in the header, or null to show no header.
*/
public BaseTimeZoneAdapter(List<T> items, OnListItemClickListener<T> onListItemClickListener,
Locale locale, boolean showItemSummary, @Nullable CharSequence headerText) {
mOriginalItems = items;
mItems = items;
mOnListItemClickListener = onListItemClickListener;
mLocale = locale;
mShowItemSummary = showItemSummary;
mShowHeader = headerText != null;
mHeaderText = headerText;
setHasStableIds(true);
}
@NonNull
@Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.time_zone_search_item, parent, false);
return new ItemViewHolder(view, mOnListItemClickListener);
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch(viewType) {
case TYPE_HEADER: {
final View view = inflater.inflate(R.layout.preference_category_material_settings,
parent, false);
return new HeaderViewHolder(view);
}
case TYPE_ITEM: {
final View view = inflater.inflate(R.layout.time_zone_search_item, parent, false);
return new ItemViewHolder(view, mOnListItemClickListener);
}
default:
throw new IllegalArgumentException("Unexpected viewType: " + viewType);
}
}
@Override
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
holder.setAdapterItem(mItems.get(position));
holder.mSummaryFrame.setVisibility(mShowItemSummary ? View.VISIBLE : View.GONE);
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof HeaderViewHolder) {
((HeaderViewHolder) holder).setText(mHeaderText);
} else if (holder instanceof ItemViewHolder) {
ItemViewHolder<T> itemViewHolder = (ItemViewHolder<T>) holder;
itemViewHolder.setAdapterItem(getDataItem(position));
itemViewHolder.mSummaryFrame.setVisibility(mShowItemSummary ? View.VISIBLE : View.GONE);
}
}
@Override
public long getItemId(int position) {
return getItem(position).getItemId();
// Data item can't have negative id
return isPositionHeader(position) ? -1 : getDataItem(position).getItemId();
}
@Override
public int getItemCount() {
return mItems.size();
return mItems.size() + getHeaderCount();
}
@Override
public int getItemViewType(int position) {
return isPositionHeader(position) ? TYPE_HEADER : TYPE_ITEM;
}
/*
* Avoid being overridden by making the method final, since constructor shouldn't invoke
* overridable method.
*/
@Override
public final void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
}
private int getHeaderCount() {
return mShowHeader ? 1 : 0;
}
private boolean isPositionHeader(int position) {
return mShowHeader && position == 0;
}
public @NonNull ArrayFilter getFilter() {
@@ -91,8 +142,12 @@ public class BaseTimeZoneAdapter<T extends BaseTimeZoneAdapter.AdapterItem>
return mFilter;
}
public T getItem(int position) {
return mItems.get(position);
/**
* @throws IndexOutOfBoundsException if the view type at the position is a header
*/
@VisibleForTesting
public T getDataItem(int position) {
return mItems.get(position - getHeaderCount());
}
public interface AdapterItem {
@@ -100,10 +155,28 @@ public class BaseTimeZoneAdapter<T extends BaseTimeZoneAdapter.AdapterItem>
CharSequence getSummary();
String getIconText();
String getCurrentTime();
/**
* @return unique non-negative number
*/
long getItemId();
String[] getSearchKeys();
}
private static class HeaderViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
public HeaderViewHolder(View itemView) {
super(itemView);
mTextView = itemView.findViewById(android.R.id.title);
}
public void setText(CharSequence text) {
mTextView.setText(text);
}
}
@VisibleForTesting
public static class ItemViewHolder<T extends BaseTimeZoneAdapter.AdapterItem>
extends RecyclerView.ViewHolder implements View.OnClickListener {