• 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.app.settings.SettingsEnums;
20 import android.content.Intent;
21 import android.icu.text.Collator;
22 import android.icu.text.LocaleDisplayNames;
23 import android.icu.util.TimeZone;
24 import android.os.Bundle;
25 import android.util.Log;
26 
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 
30 import com.android.settings.R;
31 import com.android.settings.datetime.timezone.model.FilteredCountryTimeZones;
32 import com.android.settings.datetime.timezone.model.TimeZoneData;
33 
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.Date;
39 import java.util.List;
40 import java.util.TreeSet;
41 
42 /**
43  * Given a region, render a list of time zone {@class TimeZoneInfo} into a list view.
44  */
45 public class RegionZonePicker extends BaseTimeZoneInfoPicker {
46 
47     public static final String EXTRA_REGION_ID =
48             "com.android.settings.datetime.timezone.region_id";
49 
50     private @Nullable String mRegionName;
51 
RegionZonePicker()52     public RegionZonePicker() {
53         super(R.string.date_time_set_timezone_title, R.string.search_settings, true, false);
54     }
55 
56     @Override
getMetricsCategory()57     public int getMetricsCategory() {
58         return SettingsEnums.SETTINGS_ZONE_PICKER_TIME_ZONE;
59     }
60 
61     @Override
onCreate(Bundle savedInstanceState)62     public void onCreate(Bundle savedInstanceState) {
63         super.onCreate(savedInstanceState);
64 
65         final LocaleDisplayNames localeDisplayNames = LocaleDisplayNames.getInstance(getLocale());
66         final String regionId =
67                 getArguments() == null ? null : getArguments().getString(EXTRA_REGION_ID);
68         mRegionName = regionId == null ? null : localeDisplayNames.regionDisplayName(regionId);
69     }
70 
71     @Override
getHeaderText()72     protected @Nullable CharSequence getHeaderText() {
73         return mRegionName;
74     }
75 
76     /**
77      * Add the extra region id into the result.
78      */
79     @Override
prepareResultData(TimeZoneInfo selectedTimeZoneInfo)80     protected Intent prepareResultData(TimeZoneInfo selectedTimeZoneInfo) {
81         final Intent intent = super.prepareResultData(selectedTimeZoneInfo);
82         intent.putExtra(EXTRA_RESULT_REGION_ID, getArguments().getString(EXTRA_REGION_ID));
83         return intent;
84     }
85 
86     @Override
getAllTimeZoneInfos(TimeZoneData timeZoneData)87     public List<TimeZoneInfo> getAllTimeZoneInfos(TimeZoneData timeZoneData) {
88         if (getArguments() == null) {
89             Log.e(TAG, "getArguments() == null");
90             getActivity().finish();
91             return Collections.emptyList();
92         }
93         String regionId = getArguments().getString(EXTRA_REGION_ID);
94 
95         FilteredCountryTimeZones filteredCountryTimeZones = timeZoneData.lookupCountryTimeZones(
96                 regionId);
97         if (filteredCountryTimeZones == null) {
98             Log.e(TAG, "region id is not valid: " + regionId);
99             getActivity().finish();
100             return Collections.emptyList();
101         }
102 
103         // It could be a timely operations if there are many time zones. A region in time zone data
104         // contains a maximum of 29 time zones currently. It may change in the future, but it's
105         // unlikely to be changed drastically.
106         return getRegionTimeZoneInfo(filteredCountryTimeZones.getTimeZoneIds());
107     }
108 
109     /**
110      * Returns a list of {@link TimeZoneInfo} objects. The returned list will be sorted properly for
111      * display in the locale.It may be smaller than the input collection, if equivalent IDs are
112      * passed in.
113      *
114      * @param timeZoneIds a list of Olson IDs.
115      */
getRegionTimeZoneInfo(Collection<String> timeZoneIds)116     public List<TimeZoneInfo> getRegionTimeZoneInfo(Collection<String> timeZoneIds) {
117         final TimeZoneInfo.Formatter formatter = new TimeZoneInfo.Formatter(getLocale(),
118                 new Date());
119         final TreeSet<TimeZoneInfo> timeZoneInfos =
120                 new TreeSet<>(new TimeZoneInfoComparator(Collator.getInstance(getLocale()),
121                         new Date()));
122 
123         for (final String timeZoneId : timeZoneIds) {
124             final TimeZone timeZone = TimeZone.getFrozenTimeZone(timeZoneId);
125             // Skip time zone ICU isn't aware.
126             if (timeZone.getID().equals(TimeZone.UNKNOWN_ZONE_ID)) {
127                 continue;
128             }
129             timeZoneInfos.add(formatter.format(timeZone));
130         }
131         return Collections.unmodifiableList(new ArrayList<>(timeZoneInfos));
132     }
133 
134     @VisibleForTesting
135     static class TimeZoneInfoComparator implements Comparator<TimeZoneInfo> {
136         private Collator mCollator;
137         private final Date mNow;
138 
139         @VisibleForTesting
TimeZoneInfoComparator(Collator collator, Date now)140         TimeZoneInfoComparator(Collator collator, Date now) {
141             mCollator = collator;
142             mNow = now;
143         }
144 
145         @Override
compare(TimeZoneInfo tzi1, TimeZoneInfo tzi2)146         public int compare(TimeZoneInfo tzi1, TimeZoneInfo tzi2) {
147             int result = Integer.compare(tzi1.getTimeZone().getOffset(mNow.getTime()),
148                     tzi2.getTimeZone().getOffset(mNow.getTime()));
149             if (result == 0) {
150                 result = Integer.compare(tzi1.getTimeZone().getRawOffset(),
151                     tzi2.getTimeZone().getRawOffset());
152             }
153             if (result == 0) {
154                 result = mCollator.compare(tzi1.getExemplarLocation(), tzi2.getExemplarLocation());
155             }
156             if (result == 0 && tzi1.getGenericName() != null && tzi2.getGenericName() != null) {
157                 result = mCollator.compare(tzi1.getGenericName(), tzi2.getGenericName());
158             }
159             return result;
160         }
161     }
162 }
163