diff --git a/res/layout/time_zone_list.xml b/res/layout/time_zone_list.xml deleted file mode 100644 index a3c47cd904a..00000000000 --- a/res/layout/time_zone_list.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - diff --git a/src/com/android/settings/datetime/timezone/DataLoader.java b/src/com/android/settings/datetime/timezone/DataLoader.java deleted file mode 100644 index 038558a426a..00000000000 --- a/src/com/android/settings/datetime/timezone/DataLoader.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import android.graphics.Paint; -import android.icu.text.Collator; -import android.icu.text.LocaleDisplayNames; -import android.icu.text.TimeZoneFormat; -import android.icu.text.TimeZoneNames; -import android.icu.text.TimeZoneNames.NameType; -import android.icu.util.Region; -import android.icu.util.Region.RegionType; -import android.icu.util.TimeZone; -import android.icu.util.TimeZone.SystemTimeZoneType; -import com.android.settingslib.datetime.ZoneGetter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Provides data for manual selection of time zones based associated to regions. This class makes no - * attempt to avoid IO and processing intensive actions. This means it should not be called from the - * UI thread. - */ -public class DataLoader { - - private static final int MIN_HOURS_OFFSET = -14; - private static final int MAX_HOURS_OFFSET = +12; - - private final Locale mLocale; - - private final Collator mCollator; - private final LocaleDisplayNames mLocaleDisplayNames; - private final TimeZoneFormat mTimeZoneFormat; - private final Paint mPaint; - private final AtomicLong nextItemId = new AtomicLong(1); - private final long mNow = System.currentTimeMillis(); - - public DataLoader(Locale locale) { - mLocale = locale; - mCollator = Collator.getInstance(locale); - mLocaleDisplayNames = LocaleDisplayNames.getInstance(locale); - mTimeZoneFormat = TimeZoneFormat.getInstance(locale); - mPaint = new Paint(); - } - - /** - * Returns a {@link RegionInfo} object for each region that has selectable time zones. The - * returned list will be sorted properly for display in the locale. - */ - public List loadRegionInfos() { - final Set regions = Region.getAvailable(RegionType.TERRITORY); - final TreeSet regionInfos = new TreeSet<>(new RegionInfoComparator()); - for (final Region region : regions) { - final String regionId = region.toString(); - final Set timeZoneIds = getTimeZoneIds(regionId); - if (timeZoneIds.isEmpty()) { - continue; - } - - final String name = mLocaleDisplayNames.regionDisplayName(regionId); - final String regionalIndicator = createRegionalIndicator(regionId); - - regionInfos.add(new RegionInfo(regionId, name, regionalIndicator, timeZoneIds)); - } - - return Collections.unmodifiableList(new ArrayList<>(regionInfos)); - } - - /** - * Returns a list of {@link TimeZoneInfo} objects. The returned list will be sorted properly for - * display in the locale.It may be smaller than the input collection, if equivalent IDs are - * passed in. - * - * @param timeZoneIds a list of Olson IDs. - */ - public List loadTimeZoneInfos(Collection timeZoneIds) { - final TreeSet timeZoneInfos = new TreeSet<>(new TimeZoneInfoComparator()); - outer: - for (final String timeZoneId : timeZoneIds) { - final TimeZone timeZone = TimeZone.getFrozenTimeZone(timeZoneId); - for (final TimeZoneInfo other : timeZoneInfos) { - if (other.getTimeZone().hasSameRules(timeZone)) { - continue outer; - } - } - timeZoneInfos.add(createTimeZoneInfo(timeZone)); - } - return Collections.unmodifiableList(new ArrayList<>(timeZoneInfos)); - } - - /** - * Returns a {@link TimeZoneInfo} for each fixed offset time zone, such as UTC or GMT+4. The - * returned list will be sorted in a reasonable way for display. - */ - public List loadFixedOffsets() { - final List timeZoneInfos = new ArrayList<>(); - timeZoneInfos.add(createTimeZoneInfo(TimeZone.getFrozenTimeZone("Etc/UTC"))); - for (int hoursOffset = MAX_HOURS_OFFSET; hoursOffset >= MIN_HOURS_OFFSET; --hoursOffset) { - if (hoursOffset == 0) { - // UTC is handled above, so don't add GMT +/-0 again. - continue; - } - final String id = String.format("Etc/GMT%+d", hoursOffset); - timeZoneInfos.add(createTimeZoneInfo(TimeZone.getFrozenTimeZone(id))); - } - return Collections.unmodifiableList(timeZoneInfos); - } - - /** - * Gets the set of ids for relevant TimeZones in the given region. - */ - private Set getTimeZoneIds(String regionId) { - return TimeZone.getAvailableIDs( - SystemTimeZoneType.CANONICAL_LOCATION, regionId, /* rawOffset */ null); - } - - private TimeZoneInfo createTimeZoneInfo(TimeZone timeZone) { - // Every timezone we handle must be an OlsonTimeZone. - final String id = timeZone.getID(); - final TimeZoneNames timeZoneNames = mTimeZoneFormat.getTimeZoneNames(); - final java.util.TimeZone javaTimeZone = android.icu.impl.TimeZoneAdapter.wrap(timeZone); - final CharSequence gmtOffset = ZoneGetter.getGmtOffsetText(mTimeZoneFormat, mLocale, - javaTimeZone, new Date(mNow)); - return new TimeZoneInfo.Builder(timeZone) - .setGenericName(timeZoneNames.getDisplayName(id, NameType.LONG_GENERIC, mNow)) - .setStandardName(timeZoneNames.getDisplayName(id, NameType.LONG_STANDARD, mNow)) - .setDaylightName(timeZoneNames.getDisplayName(id, NameType.LONG_DAYLIGHT, mNow)) - .setExemplarLocation(timeZoneNames.getExemplarLocationName(id)) - .setGmtOffset(gmtOffset) - .setItemId(nextItemId.getAndIncrement()) - .build(); - } - - /** - * Create a Unicode Region Indicator Symbol for a given region id (a.k.a flag emoji). If the - * system can't render a flag for this region or the input is not a region id, this returns - * {@code null}. - * - * @param id the two-character region id. - * @return a String representing the flag of the region or {@code null}. - */ - private String createRegionalIndicator(String id) { - if (id.length() != 2) { - return null; - } - final char c1 = id.charAt(0); - final char c2 = id.charAt(1); - if ('A' > c1 || c1 > 'Z' || 'A' > c2 || c2 > 'Z') { - return null; - } - // Regional Indicator A is U+1F1E6 which is 0xD83C 0xDDE6 in UTF-16. - final String regionalIndicator = new String( - new char[]{0xd83c, (char) (0xdde6 - 'A' + c1), 0xd83c, (char) (0xdde6 - 'A' + c2)}); - if (!mPaint.hasGlyph(regionalIndicator)) { - return null; - } - return regionalIndicator; - } - - private class TimeZoneInfoComparator implements Comparator { - - @Override - public int compare(TimeZoneInfo tzi1, TimeZoneInfo tzi2) { - int result = - Integer - .compare(tzi1.getTimeZone().getRawOffset(), tzi2.getTimeZone().getRawOffset()); - if (result == 0) { - result = mCollator.compare(tzi1.getExemplarLocation(), tzi2.getExemplarLocation()); - } - if (result == 0 && tzi1.getGenericName() != null && tzi2.getGenericName() != null) { - result = mCollator.compare(tzi1.getGenericName(), tzi2.getGenericName()); - } - return result; - } - } - - private class RegionInfoComparator implements Comparator { - - @Override - public int compare(RegionInfo r1, RegionInfo r2) { - return mCollator.compare(r1.getName(), r2.getName()); - } - } -} diff --git a/src/com/android/settings/datetime/timezone/RegionInfo.java b/src/com/android/settings/datetime/timezone/RegionInfo.java deleted file mode 100644 index 99fbaf09a05..00000000000 --- a/src/com/android/settings/datetime/timezone/RegionInfo.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * Data object describing a geographical region. - * - * Regions are roughly equivalent to countries, but not every region is a country (for example "U.S. - * overseas territories" is treated as a country). - */ -public class RegionInfo { - - private final String mId; - private final String mName; - private final String mRegionalIndicator; - private final Collection mTimeZoneIds; - - public RegionInfo(String id, String name, String regionalIndicator, - Collection timeZoneIds) { - mId = id; - mName = name; - mRegionalIndicator = regionalIndicator; - mTimeZoneIds = Collections.unmodifiableList(new ArrayList<>(timeZoneIds)); - } - - public String getId() { - return mId; - } - - public String getName() { - return mName; - } - - public Collection getTimeZoneIds() { - return mTimeZoneIds; - } - - @Override - public String toString() { - return mRegionalIndicator != null ? mRegionalIndicator + " " + mName : mName; - } -} diff --git a/src/com/android/settings/datetime/timezone/TimeZoneAdapter.java b/src/com/android/settings/datetime/timezone/TimeZoneAdapter.java deleted file mode 100644 index 62fc8c9baea..00000000000 --- a/src/com/android/settings/datetime/timezone/TimeZoneAdapter.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import android.content.Context; -import android.graphics.Typeface; -import android.icu.impl.OlsonTimeZone; -import android.icu.text.DateFormat; -import android.icu.text.DisplayContext; -import android.icu.text.SimpleDateFormat; -import android.icu.util.Calendar; -import android.icu.util.TimeZone; -import android.icu.util.TimeZoneTransition; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import com.android.settings.R; - -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -/** - * Adapter for showing {@link TimeZoneInfo} objects in a recycler view. - */ -class TimeZoneAdapter extends RecyclerView.Adapter { - - static final int VIEW_TYPE_NORMAL = 1; - static final int VIEW_TYPE_SELECTED = 2; - - private final DateFormat mTimeFormat; - private final DateFormat mDateFormat; - private final View.OnClickListener mOnClickListener; - private final Context mContext; - private final String mCurrentTimeZone; - - private List mTimeZoneInfos; - - TimeZoneAdapter(View.OnClickListener onClickListener, Context context) { - mOnClickListener = onClickListener; - mContext = context; - // Use android.text.format.DateFormat to observe 24-hour settings and find the best pattern - // using ICU with skeleton. - mTimeFormat = new SimpleDateFormat( - android.text.format.DateFormat.getTimeFormatString(context), - Locale.getDefault()); - mDateFormat = DateFormat.getDateInstance(SimpleDateFormat.MEDIUM); - mDateFormat.setContext(DisplayContext.CAPITALIZATION_NONE); - mCurrentTimeZone = TimeZone.getDefault().getID(); - setHasStableIds(true); - } - - @Override - public long getItemId(int position) { - return getItem(position).getItemId(); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - final View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.time_zone_list_item, parent, false); - view.setOnClickListener(mOnClickListener); - final ViewHolder viewHolder = new ViewHolder(view); - if (viewType == VIEW_TYPE_SELECTED) { - viewHolder.mNameView.setTypeface( - viewHolder.mNameView.getTypeface(), Typeface.BOLD); - } - return viewHolder; - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - final TimeZoneInfo item = getItem(position); - final ViewHolder tzHolder = (ViewHolder) holder; - tzHolder.mNameView.setText(formatName(item)); - tzHolder.mDetailsView.setText(formatDetails(item)); - tzHolder.mTimeView.setText(formatTime(item)); - String dstText = formatDstText(item); - tzHolder.mDstView.setText(dstText); - // Hide DST TextView when it has no content. - tzHolder.mDstView.setVisibility(dstText != null ? View.VISIBLE : View.GONE); - - } - - @Override - public int getItemCount() { - return getTimeZones().size(); - } - - @Override - public int getItemViewType(int position) { - final TimeZoneInfo tz = getItem(position); - if (tz.getId().equals(mCurrentTimeZone)) { - return VIEW_TYPE_SELECTED; - } else { - return VIEW_TYPE_NORMAL; - } - } - - public TimeZoneInfo getItem(int position) { - return getTimeZones().get(position); - } - - private CharSequence formatName(TimeZoneInfo item) { - CharSequence name = item.getExemplarLocation(); - if (name == null) { - name = item.getGenericName(); - } - if (name == null && item.getTimeZone().inDaylightTime(new Date())) { - name = item.getDaylightName(); - } - if (name == null) { - name = item.getStandardName(); - } - if (name == null) { - name = item.getGmtOffset(); - } - return name; - } - - private CharSequence formatDetails(TimeZoneInfo item) { - String name = item.getGenericName(); - if (name == null) { - if (item.getTimeZone().inDaylightTime(new Date())) { - name = item.getDaylightName(); - } else { - name = item.getStandardName(); - } - } - if (name == null) { - return item.getGmtOffset(); - } else { - return TextUtils.concat(item.getGmtOffset(), " ", name); - } - } - - private String formatDstText(TimeZoneInfo item) { - final TimeZone timeZone = item.getTimeZone(); - if (!timeZone.observesDaylightTime()) { - return null; - } - - final TimeZoneTransition nextDstTransition = findNextDstTransition(timeZone); - if (nextDstTransition == null) { - return null; - } - final boolean toDst = nextDstTransition.getTo().getDSTSavings() != 0; - String timeType = toDst ? item.getDaylightName() : item.getStandardName(); - if (timeType == null) { - // Fall back to generic "summer time" and "standard time" if the time zone has no - // specific names. - timeType = toDst ? - mContext.getString(R.string.zone_time_type_dst) : - mContext.getString(R.string.zone_time_type_standard); - - } - final Calendar transitionTime = Calendar.getInstance(timeZone); - transitionTime.setTimeInMillis(nextDstTransition.getTime()); - final String date = mDateFormat.format(transitionTime); - return mContext.getString(R.string.zone_change_to_from_dst, timeType, date); - } - - private TimeZoneTransition findNextDstTransition(TimeZone timeZone) { - if (!(timeZone instanceof OlsonTimeZone)) { - return null; - } - final OlsonTimeZone olsonTimeZone = (OlsonTimeZone) timeZone; - TimeZoneTransition transition = olsonTimeZone.getNextTransition( - System.currentTimeMillis(), /* inclusive */ false); - do { - if (transition.getTo().getDSTSavings() != transition.getFrom().getDSTSavings()) { - break; - } - transition = olsonTimeZone.getNextTransition( - transition.getTime(), /*inclusive */ false); - } while (transition != null); - return transition; - } - - private String formatTime(TimeZoneInfo item) { - return mTimeFormat.format(Calendar.getInstance(item.getTimeZone())); - } - - private List getTimeZones() { - if (mTimeZoneInfos == null) { - return Collections.emptyList(); - } - return mTimeZoneInfos; - } - - void setTimeZoneInfos(List timeZoneInfos) { - mTimeZoneInfos = timeZoneInfos; - notifyDataSetChanged(); - } -} diff --git a/src/com/android/settings/datetime/timezone/TimeZoneInfo.java b/src/com/android/settings/datetime/timezone/TimeZoneInfo.java index 03663903121..c036eacd4b3 100644 --- a/src/com/android/settings/datetime/timezone/TimeZoneInfo.java +++ b/src/com/android/settings/datetime/timezone/TimeZoneInfo.java @@ -37,8 +37,6 @@ public class TimeZoneInfo { private final String mDaylightName; private final String mExemplarLocation; private final CharSequence mGmtOffset; - // Arbitrary id that's unique within all TimeZoneInfo objects created by a given DataLoader instance. - private final long mItemId; public TimeZoneInfo(Builder builder) { mTimeZone = builder.mTimeZone; @@ -48,7 +46,6 @@ public class TimeZoneInfo { mDaylightName = builder.mDaylightName; mExemplarLocation = builder.mExemplarLocation; mGmtOffset = builder.mGmtOffset; - mItemId = builder.mItemId; } public String getId() { @@ -79,10 +76,6 @@ public class TimeZoneInfo { return mGmtOffset; } - public long getItemId() { - return mItemId; - } - public static class Builder { private final TimeZone mTimeZone; private String mGenericName; @@ -90,7 +83,6 @@ public class TimeZoneInfo { private String mDaylightName; private String mExemplarLocation; private CharSequence mGmtOffset; - private long mItemId = -1; public Builder(TimeZone timeZone) { if (timeZone == null) { @@ -124,18 +116,10 @@ public class TimeZoneInfo { return this; } - public Builder setItemId(long itemId) { - mItemId = itemId; - return this; - } - public TimeZoneInfo build() { if (TextUtils.isEmpty(mGmtOffset)) { throw new IllegalStateException("gmtOffset must not be empty!"); } - if (mItemId == -1) { - throw new IllegalStateException("ItemId not set!"); - } return new TimeZoneInfo(this); } } @@ -179,8 +163,6 @@ public class TimeZoneInfo { TimeZoneNames.NameType.LONG_DAYLIGHT, mNow.getTime())) .setExemplarLocation(timeZoneNames.getExemplarLocationName(id)) .setGmtOffset(gmtOffset) - // TODO: move Item id to TimeZoneInfoAdapter - .setItemId(0) .build(); } } diff --git a/src/com/android/settings/datetime/timezone/ViewHolder.java b/src/com/android/settings/datetime/timezone/ViewHolder.java deleted file mode 100644 index 3cb2c4e29d8..00000000000 --- a/src/com/android/settings/datetime/timezone/ViewHolder.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.widget.TextView; -import com.android.settings.R; - -/** - * View holder for a time zone list item. - */ -class ViewHolder extends RecyclerView.ViewHolder { - - final TextView mNameView; - final TextView mDstView; - final TextView mDetailsView; - final TextView mTimeView; - - public ViewHolder(View itemView) { - super(itemView); - mNameView = itemView.findViewById(R.id.tz_item_name); - mDstView = itemView.findViewById(R.id.tz_item_dst); - mDetailsView = itemView.findViewById(R.id.tz_item_details); - mTimeView = itemView.findViewById(R.id.tz_item_time); - } -} diff --git a/src/com/android/settings/datetime/timezone/ZonePicker.java b/src/com/android/settings/datetime/timezone/ZonePicker.java deleted file mode 100644 index d0d17202595..00000000000 --- a/src/com/android/settings/datetime/timezone/ZonePicker.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import android.app.Activity; -import android.app.AlarmManager; -import android.content.Context; -import android.icu.util.TimeZone; -import android.os.Bundle; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.Spinner; -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.core.InstrumentedFragment; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * The class displaying a region list and a list of time zones for the selected region. - * Choosing an item from the list will set the time zone. Pressing Back without choosing from the - * list will not result in a change in the time zone setting. - */ -public class ZonePicker extends InstrumentedFragment - implements AdapterView.OnItemSelectedListener, View.OnClickListener { - - private static final int MENU_BY_REGION = Menu.FIRST; - private static final int MENU_BY_OFFSET = Menu.FIRST + 1; - - private Locale mLocale; - private List mRegions; - private Map> mZoneInfos; - private List mFixedOffsetTimeZones; - private String mSelectedTimeZone; - private boolean mSelectByRegion; - private DataLoader mDataLoader; - private TimeZoneAdapter mTimeZoneAdapter; - - private RecyclerView mRecyclerView; - private LinearLayout mRegionSpinnerLayout; - private Spinner mRegionSpinner; - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.ZONE_PICKER; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.time_zone_list, container, false); - - mLocale = getContext().getResources().getConfiguration().locale; - mDataLoader = new DataLoader(mLocale); - // TOOD: move this off the UI thread. - mRegions = mDataLoader.loadRegionInfos(); - mZoneInfos = new HashMap<>(); - mSelectByRegion = true; - mSelectedTimeZone = TimeZone.getDefault().getID(); - - mTimeZoneAdapter = new TimeZoneAdapter(this, getContext()); - mRecyclerView = view.findViewById(R.id.tz_list); - mRecyclerView.setAdapter(mTimeZoneAdapter); - mRecyclerView.setLayoutManager( - new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, /* reverseLayout */ false)); - - final ArrayAdapter regionAdapter = new ArrayAdapter<>(getContext(), - R.layout.filter_spinner_item, mRegions); - regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - - mRegionSpinnerLayout = view.findViewById(R.id.tz_region_spinner_layout); - mRegionSpinner = view.findViewById(R.id.tz_region_spinner); - mRegionSpinner.setAdapter(regionAdapter); - mRegionSpinner.setOnItemSelectedListener(this); - setupForCurrentTimeZone(); - setHasOptionsMenu(true); - return view; - } - - private void setupForCurrentTimeZone() { - final String localeRegionId = mLocale.getCountry().toUpperCase(Locale.ROOT); - final String currentTimeZone = TimeZone.getDefault().getID(); - boolean fixedOffset = currentTimeZone.startsWith("Etc/GMT") || - currentTimeZone.equals("Etc/UTC"); - - for (int regionIndex = 0; regionIndex < mRegions.size(); regionIndex++) { - final RegionInfo region = mRegions.get(regionIndex); - if (localeRegionId.equals(region.getId())) { - mRegionSpinner.setSelection(regionIndex); - } - if (!fixedOffset) { - for (String timeZoneId: region.getTimeZoneIds()) { - if (TextUtils.equals(timeZoneId, mSelectedTimeZone)) { - mRegionSpinner.setSelection(regionIndex); - return; - } - } - } - } - - if (fixedOffset) { - setSelectByRegion(false); - } - } - - @Override - public void onClick(View view) { - // Ignore extra clicks - if (!isResumed()) { - return; - } - final int position = mRecyclerView.getChildAdapterPosition(view); - if (position == RecyclerView.NO_POSITION) { - return; - } - final TimeZoneInfo timeZoneInfo = mTimeZoneAdapter.getItem(position); - - // Update the system timezone value - final Activity activity = getActivity(); - final AlarmManager alarm = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(timeZoneInfo.getId()); - - activity.onBackPressed(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - menu.add(0, MENU_BY_REGION, 0, R.string.zone_menu_by_region); - menu.add(0, MENU_BY_OFFSET, 0, R.string.zone_menu_by_offset); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - if (mSelectByRegion) { - menu.findItem(MENU_BY_REGION).setVisible(false); - menu.findItem(MENU_BY_OFFSET).setVisible(true); - } else { - menu.findItem(MENU_BY_REGION).setVisible(true); - menu.findItem(MENU_BY_OFFSET).setVisible(false); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case MENU_BY_REGION: - setSelectByRegion(true); - return true; - - case MENU_BY_OFFSET: - setSelectByRegion(false); - return true; - - default: - return false; - } - } - - private void setSelectByRegion(boolean selectByRegion) { - mSelectByRegion = selectByRegion; - mRegionSpinnerLayout.setVisibility( - mSelectByRegion ? View.VISIBLE : View.GONE); - List tzInfos; - if (selectByRegion) { - int selectedRegion = mRegionSpinner.getSelectedItemPosition(); - if (selectedRegion == -1) { - // Arbitrarily pick the first item if no region was selected above. - selectedRegion = 0; - mRegionSpinner.setSelection(selectedRegion); - } - tzInfos = getTimeZoneInfos(mRegions.get(selectedRegion)); - } else { - if (mFixedOffsetTimeZones == null) { - mFixedOffsetTimeZones = mDataLoader.loadFixedOffsets(); - } - tzInfos = mFixedOffsetTimeZones; - } - mTimeZoneAdapter.setTimeZoneInfos(tzInfos); - } - - private List getTimeZoneInfos(RegionInfo regionInfo) { - List tzInfos = mZoneInfos.get(regionInfo.getId()); - if (tzInfos == null) { - // TODO: move this off the UI thread. - Collection tzIds = regionInfo.getTimeZoneIds(); - tzInfos = mDataLoader.loadTimeZoneInfos(tzIds); - mZoneInfos.put(regionInfo.getId(), tzInfos); - } - return tzInfos; - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - mTimeZoneAdapter.setTimeZoneInfos(getTimeZoneInfos(mRegions.get(position))); - } - - @Override - public void onNothingSelected(AdapterView parent) { - mTimeZoneAdapter.setTimeZoneInfos(null); - } - -} diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPickerTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPickerTest.java index ef80968cbd7..aa0ba77d176 100644 --- a/tests/robotests/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPickerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPickerTest.java @@ -89,7 +89,6 @@ public class BaseTimeZoneInfoPickerTest { .setDaylightName("Pacific Daylight Time") .setExemplarLocation("Los Angeles") .setGmtOffset("GMT-08:00") - .setItemId(0) .build(); TimeZoneInfo zone2 = new TimeZoneInfo.Builder( TimeZone.getFrozenTimeZone("America/New_York")) @@ -98,7 +97,6 @@ public class BaseTimeZoneInfoPickerTest { .setDaylightName("Eastern Daylight Time") .setExemplarLocation("New York") .setGmtOffset("GMT-05:00") - .setItemId(1) .build(); return Arrays.asList(zone1, zone2); diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/DataLoaderTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/DataLoaderTest.java deleted file mode 100644 index 6e211e6af0d..00000000000 --- a/tests/robotests/src/com/android/settings/datetime/timezone/DataLoaderTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; -import java.util.Locale; - -@RunWith(SettingsRobolectricTestRunner.class) -public class DataLoaderTest { - - @Test - public void testHasData() { - List regions = new DataLoader(Locale.US).loadRegionInfos(); - // Sanity check. Real size is closer to 200. - assertNotNull(regions); - assertTrue(regions.size() > 100); - assertEquals("Afghanistan", regions.get(0).getName()); - assertEquals("Zimbabwe", regions.get(regions.size() - 1).getName()); - } - - @Test - public void testRegionsWithTimeZone() { - List regions = new DataLoader(Locale.US).loadRegionInfos(); - checkRegionHasTimeZone(regions, "AT", "Europe/Vienna"); - checkRegionHasTimeZone(regions, "US", "America/Los_Angeles"); - checkRegionHasTimeZone(regions, "CN", "Asia/Shanghai"); - checkRegionHasTimeZone(regions, "AU", "Australia/Sydney"); - } - - @Test - public void testFixedOffsetTimeZones() { - List timeZones = new DataLoader(Locale.US).loadFixedOffsets(); - // Etc/GMT would be equivalent to Etc/UTC, except for how it is labelled. Users have - // explicitly asked for UTC to be supported, so make sure we label it as such. - checkHasTimeZone(timeZones, "Etc/UTC"); - checkHasTimeZone(timeZones, "Etc/GMT-1"); - checkHasTimeZone(timeZones, "Etc/GMT-14"); - checkHasTimeZone(timeZones, "Etc/GMT+1"); - checkHasTimeZone(timeZones, "Etc/GMT+12"); - } - - private void checkRegionHasTimeZone(List regions, String regionId, String tzId) { - RegionInfo ri = findRegion(regions, regionId); - assertTrue("Region " + regionId + " does not have time zone " + tzId, - ri.getTimeZoneIds().contains(tzId)); - } - - private void checkHasTimeZone(List timeZoneInfos, String tzId) { - for (TimeZoneInfo tz : timeZoneInfos) { - if (tz.getId().equals(tzId)) { - return; - } - } - fail("Fixed offset time zones do not contain " + tzId); - } - - private RegionInfo findRegion(List regions, String regionId) { - for (RegionInfo region : regions) { - if (region.getId().equals(regionId)) { - assertNotNull(region.getName()); - return region; - } - - } - fail("No region with id " + regionId + " found."); - return null; // can't reach. - } -} diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/FixedOffsetPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/FixedOffsetPreferenceControllerTest.java index f657560f9be..26fbe50e0cb 100644 --- a/tests/robotests/src/com/android/settings/datetime/timezone/FixedOffsetPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/timezone/FixedOffsetPreferenceControllerTest.java @@ -44,7 +44,6 @@ public class FixedOffsetPreferenceControllerTest { TimeZoneInfo fixedOffsetZone = new TimeZoneInfo.Builder( TimeZone.getFrozenTimeZone("Etc/GMT-8")) .setGmtOffset("GMT-08:00") - .setItemId(0) .build(); Preference preference = new Preference(mActivity); FixedOffsetPreferenceController controller = new FixedOffsetPreferenceController(mActivity); @@ -59,7 +58,6 @@ public class FixedOffsetPreferenceControllerTest { TimeZone.getFrozenTimeZone("Etc/UTC")) .setStandardName("Coordinated Universal Time") .setGmtOffset("GMT+00:00") - .setItemId(0) .build(); Preference preference = new Preference(mActivity); FixedOffsetPreferenceController controller = new FixedOffsetPreferenceController(mActivity); diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/RegionZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/RegionZonePreferenceControllerTest.java index b39641fc1a7..b7b42782873 100644 --- a/tests/robotests/src/com/android/settings/datetime/timezone/RegionZonePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/timezone/RegionZonePreferenceControllerTest.java @@ -48,7 +48,6 @@ public class RegionZonePreferenceControllerTest { .setDaylightName("Pacific Daylight Time") .setExemplarLocation("Los Angeles") .setGmtOffset("GMT-08:00") - .setItemId(0) .build(); Preference preference = new Preference(mActivity); RegionZonePreferenceController controller = new RegionZonePreferenceController(mActivity); diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/TimeZoneAdapterTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/TimeZoneAdapterTest.java deleted file mode 100644 index 030f1680995..00000000000 --- a/tests/robotests/src/com/android/settings/datetime/timezone/TimeZoneAdapterTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.datetime.timezone; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.icu.util.TimeZone; -import android.text.TextUtils; -import android.view.View; -import android.widget.FrameLayout; - -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; - -import java.util.Collections; -import java.util.Locale; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(shadows = TimeZoneAdapterTest.ShadowDataFormat.class) -public class TimeZoneAdapterTest { - - @Mock - private View.OnClickListener mOnClickListener; - - private TimeZoneAdapter mTimeZoneAdapter; - - private Context mContext; - private Locale mDefaultLocale; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mTimeZoneAdapter = new TimeZoneAdapter(mOnClickListener, mContext); - mDefaultLocale = Locale.getDefault(); - } - - @After - public void tearDown() { - Locale.setDefault(mDefaultLocale); - } - - @Test - public void getItemViewType_onDefaultTimeZone_returnsTypeSelected() { - final TimeZoneInfo tzi = dummyTimeZoneInfo(TimeZone.getDefault()); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - assertThat(mTimeZoneAdapter.getItemViewType(0)) - .isEqualTo(TimeZoneAdapter.VIEW_TYPE_SELECTED); - } - - @Test - public void getItemViewType_onNonDefaultTimeZone_returnsTypeNormal() { - final TimeZoneInfo tzi = dummyTimeZoneInfo(getNonDefaultTimeZone()); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - assertThat(mTimeZoneAdapter.getItemViewType(0)).isEqualTo(TimeZoneAdapter.VIEW_TYPE_NORMAL); - } - - @Test - public void bindViewHolder_onDstTimeZone_showsDstLabel() { - final TimeZoneInfo tzi = dummyTimeZoneInfo(TimeZone.getTimeZone("America/Los_Angeles")); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - - final FrameLayout parent = new FrameLayout(RuntimeEnvironment.application); - - final ViewHolder viewHolder = - (ViewHolder) mTimeZoneAdapter.createViewHolder(parent, TimeZoneAdapter.VIEW_TYPE_NORMAL); - mTimeZoneAdapter.bindViewHolder(viewHolder, 0); - assertThat(viewHolder.mDstView).isNotNull(); - assertThat(viewHolder.mDstView.getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void bindViewHolder_onNonDstTimeZone_hidesDstLabel() { - final TimeZoneInfo tzi = dummyTimeZoneInfo(TimeZone.getTimeZone("Etc/UTC")); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - - final FrameLayout parent = new FrameLayout(RuntimeEnvironment.application); - - final ViewHolder viewHolder = - (ViewHolder) mTimeZoneAdapter.createViewHolder(parent, TimeZoneAdapter.VIEW_TYPE_NORMAL); - mTimeZoneAdapter.bindViewHolder(viewHolder, 0); - assertThat(viewHolder.mDstView).isNotNull(); - assertThat(viewHolder.mDstView.getVisibility()).isEqualTo(View.GONE); - } - - @Test - public void bindViewHolder_on24Hour() { - Locale.setDefault(Locale.US); - ShadowDataFormat.mTimeFormatString = "HH:mm"; - mTimeZoneAdapter = new TimeZoneAdapter(mOnClickListener, mContext); - - final TimeZoneInfo tzi = dummyTimeZoneInfo(TimeZone.getTimeZone("Etc/UTC")); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - - final FrameLayout parent = new FrameLayout(RuntimeEnvironment.application); - - final ViewHolder viewHolder = - (ViewHolder) mTimeZoneAdapter.createViewHolder(parent, TimeZoneAdapter.VIEW_TYPE_NORMAL); - mTimeZoneAdapter.bindViewHolder(viewHolder, 0); - assertThat(viewHolder.mTimeView).isNotNull(); - assertThat(viewHolder.mTimeView.getText().toString()).hasLength(5); - } - - @Test - public void bindViewHolder_on12Hour() { - Locale.setDefault(Locale.US); - ShadowDataFormat.mTimeFormatString = "hh:mm a"; - mTimeZoneAdapter = new TimeZoneAdapter(mOnClickListener, mContext); - - final TimeZoneInfo tzi = dummyTimeZoneInfo(TimeZone.getTimeZone("Etc/UTC")); - mTimeZoneAdapter.setTimeZoneInfos(Collections.singletonList(tzi)); - - final FrameLayout parent = new FrameLayout(RuntimeEnvironment.application); - - final ViewHolder viewHolder = - (ViewHolder) mTimeZoneAdapter.createViewHolder(parent, TimeZoneAdapter.VIEW_TYPE_NORMAL); - mTimeZoneAdapter.bindViewHolder(viewHolder, 0); - assertThat(viewHolder.mTimeView).isNotNull(); - assertThat(viewHolder.mTimeView.getText().toString()).hasLength(8); - } - - // Pick an arbitrary time zone that's not the current default. - private static TimeZone getNonDefaultTimeZone() { - final String[] availableIDs = TimeZone.getAvailableIDs(); - int index = 0; - if (TextUtils.equals(availableIDs[index], TimeZone.getDefault().getID())) { - index++; - } - return TimeZone.getTimeZone(availableIDs[index]); - } - - private TimeZoneInfo dummyTimeZoneInfo(TimeZone timeZone) { - return new TimeZoneInfo.Builder(timeZone).setGmtOffset("GMT+0").setItemId(1).build(); - } - - @Implements(android.text.format.DateFormat.class) - public static class ShadowDataFormat { - - private static String mTimeFormatString = ""; - - @Implementation - public static String getTimeFormatString(Context context) { - return mTimeFormatString; - } - } -}