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.Activity; 20 import android.content.Intent; 21 import android.icu.text.Collator; 22 import android.icu.text.LocaleDisplayNames; 23 import android.os.Bundle; 24 import android.support.annotation.VisibleForTesting; 25 import android.util.Log; 26 27 import com.android.internal.logging.nano.MetricsProto; 28 import com.android.settings.R; 29 import com.android.settings.core.SubSettingLauncher; 30 import com.android.settings.datetime.timezone.BaseTimeZoneAdapter.AdapterItem; 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.Comparator; 36 import java.util.List; 37 import java.util.Set; 38 import java.util.TreeSet; 39 40 /** 41 * Render a list of regions into a list view. 42 */ 43 public class RegionSearchPicker extends BaseTimeZonePicker { 44 private static final int REQUEST_CODE_ZONE_PICKER = 1; 45 private static final String TAG = "RegionSearchPicker"; 46 47 private BaseTimeZoneAdapter<RegionItem> mAdapter; 48 private TimeZoneData mTimeZoneData; 49 50 public RegionSearchPicker() { 51 super(R.string.date_time_select_region, R.string.date_time_search_region, true, true); 52 } 53 54 @Override 55 public int getMetricsCategory() { 56 return MetricsProto.MetricsEvent.SETTINGS_ZONE_PICKER_REGION; 57 } 58 59 @Override 60 protected BaseTimeZoneAdapter createAdapter(TimeZoneData timeZoneData) { 61 mTimeZoneData = timeZoneData; 62 mAdapter = new BaseTimeZoneAdapter<>(createAdapterItem(timeZoneData.getRegionIds()), 63 this::onListItemClick, getLocale(), false /* showItemSummary */, 64 null /* headerText */); 65 return mAdapter; 66 } 67 68 private void onListItemClick(RegionItem item) { 69 final String regionId = item.getId(); 70 final FilteredCountryTimeZones countryTimeZones = mTimeZoneData.lookupCountryTimeZones( 71 regionId); 72 final Activity activity = getActivity(); 73 if (countryTimeZones == null || countryTimeZones.getTimeZoneIds().isEmpty()) { 74 Log.e(TAG, "Region has no time zones: " + regionId); 75 activity.setResult(Activity.RESULT_CANCELED); 76 activity.finish(); 77 return; 78 } 79 80 List<String> timeZoneIds = countryTimeZones.getTimeZoneIds(); 81 // Choose the time zone associated the region if there is only one time zone in that region 82 if (timeZoneIds.size() == 1) { 83 final Intent resultData = new Intent() 84 .putExtra(EXTRA_RESULT_REGION_ID, regionId) 85 .putExtra(EXTRA_RESULT_TIME_ZONE_ID, timeZoneIds.get(0)); 86 getActivity().setResult(Activity.RESULT_OK, resultData); 87 getActivity().finish(); 88 } else { 89 // Launch the zone picker and let the user choose a time zone from the list of 90 // time zones associated with the region. 91 final Bundle args = new Bundle(); 92 args.putString(RegionZonePicker.EXTRA_REGION_ID, regionId); 93 new SubSettingLauncher(getContext()) 94 .setDestination(RegionZonePicker.class.getCanonicalName()) 95 .setArguments(args) 96 .setSourceMetricsCategory(getMetricsCategory()) 97 .setResultListener(this, REQUEST_CODE_ZONE_PICKER) 98 .launch(); 99 } 100 } 101 102 @Override 103 public void onActivityResult(int requestCode, int resultCode, Intent data) { 104 if (requestCode == REQUEST_CODE_ZONE_PICKER) { 105 if (resultCode == Activity.RESULT_OK) { 106 getActivity().setResult(Activity.RESULT_OK, data); 107 } 108 getActivity().finish(); 109 } 110 } 111 112 private List<RegionItem> createAdapterItem(Set<String> regionIds) { 113 final Collator collator = Collator.getInstance(getLocale()); 114 final TreeSet<RegionItem> items = new TreeSet<>(new RegionInfoComparator(collator)); 115 final LocaleDisplayNames localeDisplayNames = LocaleDisplayNames.getInstance(getLocale()); 116 long i = 0; 117 for (String regionId : regionIds) { 118 String name = localeDisplayNames.regionDisplayName(regionId); 119 items.add(new RegionItem(i++, regionId, name)); 120 } 121 return new ArrayList<>(items); 122 } 123 124 @VisibleForTesting 125 static class RegionItem implements AdapterItem { 126 127 private final String mId; 128 private final String mName; 129 private final long mItemId; 130 private final String[] mSearchKeys; 131 132 RegionItem(long itemId, String id, String name) { 133 mId = id; 134 mName = name; 135 mItemId = itemId; 136 // Allow to search with ISO_3166-1 alpha-2 code. It's handy for english users in some 137 // countries, e.g. US for United States. It's not best search keys for users, but 138 // ICU doesn't have the data for the alias names of a region. 139 mSearchKeys = new String[] {mId, mName}; 140 } 141 142 public String getId() { 143 return mId; 144 } 145 146 @Override 147 public CharSequence getTitle() { 148 return mName; 149 } 150 151 @Override 152 public CharSequence getSummary() { 153 return null; 154 } 155 156 @Override 157 public String getIconText() { 158 return null; 159 } 160 161 @Override 162 public String getCurrentTime() { 163 return null; 164 } 165 166 @Override 167 public long getItemId() { 168 return mItemId; 169 } 170 171 @Override 172 public String[] getSearchKeys() { 173 return mSearchKeys; 174 } 175 } 176 177 private static class RegionInfoComparator implements Comparator<RegionItem> { 178 private final Collator mCollator; 179 180 RegionInfoComparator(Collator collator) { 181 mCollator = collator; 182 } 183 184 @Override 185 public int compare(RegionItem r1, RegionItem r2) { 186 return mCollator.compare(r1.getTitle(), r2.getTitle()); 187 } 188 } 189 } 190