blob: 544bc298de99214a4c7533d3eefcfa07d788dd0f [file] [log] [blame]
/*
* Copyright (C) 2015 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.deskclock.data;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This class encapsulates the transfer of data between {@link City} domain objects and their
* permanent storage in {@link Resources} and {@link SharedPreferences}.
*/
final class CityDAO {
// Regex to match natural index values when parsing city names.
private static final Pattern INDEX_REGEX = Pattern.compile("\\d+");
// Key to a preference that stores the number of selected cities.
private static final String NUMBER_OF_CITIES = "number_of_cities";
// Prefix for a key to a preference that stores the id of a selected city.
private static final String CITY_ID = "city_id_";
// Lazily instantiated and cached for the life of the application.
private static SharedPreferences sPrefs;
private CityDAO() {}
/**
* @param cityMap maps city ids to city instances
* @return the list of city ids selected for display by the user
*/
public static List<City> getSelectedCities(Context context, Map<String, City> cityMap) {
final SharedPreferences prefs = getSharedPreferences(context);
final int size = prefs.getInt(NUMBER_OF_CITIES, 0);
final List<City> selectedCities = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final String id = prefs.getString(CITY_ID + i, null);
final City city = cityMap.get(id);
if (city != null) {
selectedCities.add(city);
}
}
return selectedCities;
}
/**
* @param cities the collection of cities selected for display by the user
*/
public static void setSelectedCities(Context context, Collection<City> cities) {
final SharedPreferences prefs = getSharedPreferences(context);
final SharedPreferences.Editor editor = prefs.edit();
editor.putInt(NUMBER_OF_CITIES, cities.size());
int count = 0;
for (City city : cities) {
editor.putString(CITY_ID + count, city.getId());
count++;
}
editor.apply();
}
/**
* @return the domain of cities from which the user may choose a world clock
*/
public static Map<String, City> getCities(Context context) {
final Resources resources = context.getResources();
final String[] ids = resources.getStringArray(R.array.cities_id);
final String[] names = resources.getStringArray(R.array.cities_names);
final String[] timezones = resources.getStringArray(R.array.cities_tz);
if (ids.length != names.length) {
final String locale = Locale.getDefault().toString();
final String format = "id count (%d) != name count (%d) for locale %s";
final String message = String.format(format, ids.length, names.length, locale);
throw new IllegalStateException(message);
}
if (ids.length != timezones.length) {
final String locale = Locale.getDefault().toString();
final String format = "id count (%d) != timezone count (%d) for locale %s";
final String message = String.format(format, ids.length, timezones.length, locale);
throw new IllegalStateException(message);
}
final Map<String, City> cities = new ArrayMap<>(ids.length);
for (int i = 0; i < ids.length; i++) {
final String id = ids[i];
if ("C0".equals(id)) {
continue;
}
cities.put(id, createCity(id, names[i], timezones[i]));
}
return Collections.unmodifiableMap(cities);
}
/**
* @param id unique identifier for city
* @param formattedName "[index string]=[name]" or "[index string]=[name]:[phonetic name]",
* If [index string] is empty, we use the first character of name as index,
* If phonetic name is empty, we use the name itself as phonetic.
* @param timeZoneId identifies the timezone in which the city is located
*/
@VisibleForTesting
static City createCity(String id, String formattedName, String timeZoneId) {
final String[] parts = formattedName.split("[=:]");
final String name = parts[1];
// Extract index string from input, use the first character of city name as index string
// if it's not explicitly provided.
final String indexString = TextUtils.isEmpty(parts[0])
? String.valueOf(name.charAt(0)) : parts[0];
final String phoneticName = parts.length == 3 ? parts[2] : name;
final Matcher matcher = INDEX_REGEX.matcher(indexString);
final int index = matcher.find() ? Integer.parseInt(matcher.group()) : -1;
return new City(id, index, indexString, name, phoneticName, timeZoneId);
}
private static SharedPreferences getSharedPreferences(Context context) {
if (sPrefs == null) {
sPrefs = Utils.getDefaultSharedPreferences(context.getApplicationContext());
}
return sPrefs;
}
}