• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.datetime.timezone;
18 
19 import android.content.Intent;
20 import android.icu.text.Collator;
21 import android.icu.text.LocaleDisplayNames;
22 import android.icu.util.TimeZone;
23 import android.os.Bundle;
24 import android.support.annotation.Nullable;
25 import android.support.annotation.VisibleForTesting;
26 import android.util.Log;
27 
28 import com.android.internal.logging.nano.MetricsProto;
29 import com.android.settings.R;
30 import com.android.settings.datetime.timezone.model.FilteredCountryTimeZones;
31 import com.android.settings.datetime.timezone.model.TimeZoneData;
32 
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.Date;
38 import java.util.List;
39 import java.util.TreeSet;
40 
41 /**
42  * Given a region, render a list of time zone {@class TimeZoneInfo} into a list view.
43  */
44 public class RegionZonePicker extends BaseTimeZoneInfoPicker {
45 
46     public static final String EXTRA_REGION_ID =
47             "com.android.settings.datetime.timezone.region_id";
48 
49     private @Nullable String mRegionName;
50 
RegionZonePicker()51     public RegionZonePicker() {
52         super(R.string.date_time_set_timezone_title, R.string.search_settings, true, false);
53     }
54 
55     @Override
getMetricsCategory()56     public int getMetricsCategory() {
57         return MetricsProto.MetricsEvent.SETTINGS_ZONE_PICKER_TIME_ZONE;
58     }
59 
60     @Override
onCreate(Bundle savedInstanceState)61     public void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63 
64         final LocaleDisplayNames localeDisplayNames = LocaleDisplayNames.getInstance(getLocale());
65         final String regionId =
66                 getArguments() == null ? null : getArguments().getString(EXTRA_REGION_ID);
67         mRegionName = regionId == null ? null : localeDisplayNames.regionDisplayName(regionId);
68     }
69 
70     @Override
getHeaderText()71     protected @Nullable CharSequence getHeaderText() {
72         return mRegionName;
73     }
74 
75     /**
76      * Add the extra region id into the result.
77      */
78     @Override
prepareResultData(TimeZoneInfo selectedTimeZoneInfo)79     protected Intent prepareResultData(TimeZoneInfo selectedTimeZoneInfo) {
80         final Intent intent = super.prepareResultData(selectedTimeZoneInfo);
81         intent.putExtra(EXTRA_RESULT_REGION_ID, getArguments().getString(EXTRA_REGION_ID));
82         return intent;
83     }
84 
85     @Override
getAllTimeZoneInfos(TimeZoneData timeZoneData)86     public List<TimeZoneInfo> getAllTimeZoneInfos(TimeZoneData timeZoneData) {
87         if (getArguments() == null) {
88             Log.e(TAG, "getArguments() == null");
89             getActivity().finish();
90             return Collections.emptyList();
91         }
92         String regionId = getArguments().getString(EXTRA_REGION_ID);
93 
94         FilteredCountryTimeZones filteredCountryTimeZones = timeZoneData.lookupCountryTimeZones(
95                 regionId);
96         if (filteredCountryTimeZones == null) {
97             Log.e(TAG, "region id is not valid: " + regionId);
98             getActivity().finish();
99             return Collections.emptyList();
100         }
101 
102         // It could be a timely operations if there are many time zones. A region in time zone data
103         // contains a maximum of 29 time zones currently. It may change in the future, but it's
104         // unlikely to be changed drastically.
105         return getRegionTimeZoneInfo(filteredCountryTimeZones.getTimeZoneIds());
106     }
107 
108     /**
109      * Returns a list of {@link TimeZoneInfo} objects. The returned list will be sorted properly for
110      * display in the locale.It may be smaller than the input collection, if equivalent IDs are
111      * passed in.
112      *
113      * @param timeZoneIds a list of Olson IDs.
114      */
getRegionTimeZoneInfo(Collection<String> timeZoneIds)115     public List<TimeZoneInfo> getRegionTimeZoneInfo(Collection<String> timeZoneIds) {
116         final TimeZoneInfo.Formatter formatter = new TimeZoneInfo.Formatter(getLocale(),
117                 new Date());
118         final TreeSet<TimeZoneInfo> timeZoneInfos =
119                 new TreeSet<>(new TimeZoneInfoComparator(Collator.getInstance(getLocale()),
120                         new Date()));
121 
122         for (final String timeZoneId : timeZoneIds) {
123             final TimeZone timeZone = TimeZone.getFrozenTimeZone(timeZoneId);
124             // Skip time zone ICU isn't aware.
125             if (timeZone.getID().equals(TimeZone.UNKNOWN_ZONE_ID)) {
126                 continue;
127             }
128             timeZoneInfos.add(formatter.format(timeZone));
129         }
130         return Collections.unmodifiableList(new ArrayList<>(timeZoneInfos));
131     }
132 
133     @VisibleForTesting
134     static class TimeZoneInfoComparator implements Comparator<TimeZoneInfo> {
135         private Collator mCollator;
136         private final Date mNow;
137 
138         @VisibleForTesting
TimeZoneInfoComparator(Collator collator, Date now)139         TimeZoneInfoComparator(Collator collator, Date now) {
140             mCollator = collator;
141             mNow = now;
142         }
143 
144         @Override
compare(TimeZoneInfo tzi1, TimeZoneInfo tzi2)145         public int compare(TimeZoneInfo tzi1, TimeZoneInfo tzi2) {
146             int result = Integer.compare(tzi1.getTimeZone().getOffset(mNow.getTime()),
147                     tzi2.getTimeZone().getOffset(mNow.getTime()));
148             if (result == 0) {
149                 result = Integer.compare(tzi1.getTimeZone().getRawOffset(),
150                     tzi2.getTimeZone().getRawOffset());
151             }
152             if (result == 0) {
153                 result = mCollator.compare(tzi1.getExemplarLocation(), tzi2.getExemplarLocation());
154             }
155             if (result == 0 && tzi1.getGenericName() != null && tzi2.getGenericName() != null) {
156                 result = mCollator.compare(tzi1.getGenericName(), tzi2.getGenericName());
157             }
158             return result;
159         }
160     }
161 }
162