Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5f5bbc4 authored by Fan Zhang's avatar Fan Zhang
Browse files

Keep world clock cities sorted by index and phonetically.

Bug: 22727472
Change-Id: I85e1888ed1430c1b987fcb0a1e92c4465cc57ec0
parent 2fe2b3e0
Loading
Loading
Loading
Loading
+24 −16
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright (C) 2012 The Android Open Source Project
    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.
@@ -21,11 +21,16 @@
    The section header is the "index" of all the cities in the section. By default, the section
    header is the first character of the city name.

    However, in some languages, cities are listed under an incorrect index.
    Format of providing a city name:
    <item>[index]<xliff:g id="separator">=</xliff:g>[city name]<xliff:g id="phonetic">:</xliff:g>[phonetic name]</item>

    Index and phonetic name are optional.

    In some languages, cities are listed under an incorrect index or sorted incorrectly within an
    index.

    Should a city be listed under an incorrect index, the correct index can be manually specified
    by adding an index to the translation string before the "=" placeholder:
        <item>[index]<xliff:g id="separator">=</xliff:g>[city name]</item>
    by adding an index to the translation string before the "=" placeholder.

        Ex. <item>A<xliff:g id="separator">=</xliff:g>Abidjan</item>
        Now Abidjan will be classified under the "A" index.
@@ -33,9 +38,12 @@
    Note that the separator "=" should NOT be localized. The index can be multi-character; it will
    consist of all specified characters before the "=" separator.

    This will NOT change the sort order of the cities list. It will solve issues where a city is
    mistakenly listed under its own index instead of being included in a section immediately
    before or after its listing.
    If a city is sorted incorrectly, provide a phonetic name for the city by adding
    <xliff:g id="phonetic">:</xliff:g>[PHONETIC_NAME]. The city now will be sorted based on phonetic
    name. The phonetic should use the alphabet that makes the most sense for the locale. For
    example, Japanese city can use Katakana to provide phonetic name.

    Providing index and/or phonetic name will change the sort order of the cities list.
    -->

    <string-array name="cities_names">
@@ -135,7 +143,7 @@
        <item>T<xliff:g id="separator">=</xliff:g>Toronto</item>
        <item>V<xliff:g id="separator">=</xliff:g>Vancouver</item>
        <item>W<xliff:g id="separator">=</xliff:g>Winnipeg</item>
        <item>S<xliff:g id="separator">=</xliff:g>South Pole</item>
        <item>S<xliff:g id="separator">=</xliff:g>South Pole<xliff:g id="phonetic">:</xliff:g></item>
        <item>L<xliff:g id="separator">=</xliff:g>Longyearbyen</item>
        <item>A<xliff:g id="separator">=</xliff:g>Almaty</item>
        <item>A<xliff:g id="separator">=</xliff:g>Amman</item>
@@ -153,7 +161,7 @@
        <item>G<xliff:g id="separator">=</xliff:g>Gaza</item>
        <item>H<xliff:g id="separator">=</xliff:g>Hebron</item>
        <item>H<xliff:g id="separator">=</xliff:g>Ho Chi Minh</item>
        <item>H<xliff:g id="separator">=</xliff:g>Hong Kong</item>
        <item>H<xliff:g id="separator">=</xliff:g>Hong Kong<xliff:g id="phonetic">:</xliff:g></item>
        <item>I<xliff:g id="separator">=</xliff:g>Istanbul</item>
        <item>J<xliff:g id="separator">=</xliff:g>Jakarta</item>
        <item>J<xliff:g id="separator">=</xliff:g>Jerusalem</item>
@@ -166,18 +174,18 @@
        <item>M<xliff:g id="separator">=</xliff:g>Manila</item>
        <item>M<xliff:g id="separator">=</xliff:g>Muscat</item>
        <item>P<xliff:g id="separator">=</xliff:g>Phnom Penh</item>
        <item>P<xliff:g id="separator">=</xliff:g>Pyongyang</item>
        <item>P<xliff:g id="separator">=</xliff:g>Pyongyang<xliff:g id="phonetic">:</xliff:g></item>
        <item>Q<xliff:g id="separator">=</xliff:g>Qatar</item>
        <item>R<xliff:g id="separator">=</xliff:g>Rangoon</item>
        <item>R<xliff:g id="separator">=</xliff:g>Riyadh</item>
        <item>S<xliff:g id="separator">=</xliff:g>Saigon</item>
        <item>S<xliff:g id="separator">=</xliff:g>Seoul</item>
        <item>S<xliff:g id="separator">=</xliff:g>Shanghai</item>
        <item>S<xliff:g id="separator">=</xliff:g>Shanghai<xliff:g id="phonetic">:</xliff:g></item>
        <item>S<xliff:g id="separator">=</xliff:g>Singapore</item>
        <item>T<xliff:g id="separator">=</xliff:g>Taipei</item>
        <item>T<xliff:g id="separator">=</xliff:g>Taipei<xliff:g id="phonetic">:</xliff:g></item>
        <item>T<xliff:g id="separator">=</xliff:g>Tehran</item>
        <item>T<xliff:g id="separator">=</xliff:g>Tel Aviv</item>
        <item>T<xliff:g id="separator">=</xliff:g>Tokyo</item>
        <item>T<xliff:g id="separator">=</xliff:g>Tokyo<xliff:g id="phonetic">:</xliff:g></item>
        <item>U<xliff:g id="separator">=</xliff:g>Ulaanbaatar</item>
        <item>B<xliff:g id="separator">=</xliff:g>Bermuda</item>
        <item>C<xliff:g id="separator">=</xliff:g>Canary</item>
@@ -294,10 +302,10 @@
        <item>R<xliff:g id="separator">=</xliff:g>Reno</item>
        <item>B<xliff:g id="separator">=</xliff:g>Black Rock City</item>
        <item>D<xliff:g id="separator">=</xliff:g>Doha</item>
        <item>B<xliff:g id="separator">=</xliff:g>Beijing</item>
        <item>B<xliff:g id="separator">=</xliff:g>Beijing<xliff:g id="phonetic">:</xliff:g></item>
        <item>M<xliff:g id="separator">=</xliff:g>Mumbai</item>
        <item>D<xliff:g id="separator">=</xliff:g>Delhi</item>
        <item>O<xliff:g id="separator">=</xliff:g>Osaka</item>
        <item>O<xliff:g id="separator">=</xliff:g>Osaka<xliff:g id="phonetic">:</xliff:g></item>
        <item>L<xliff:g id="separator">=</xliff:g>Lahore</item>
        <item>S<xliff:g id="separator">=</xliff:g>Sana\'a</item>
        <item>B<xliff:g id="separator">=</xliff:g>Barcelona</item>
@@ -316,7 +324,7 @@
        <item>C<xliff:g id="separator">=</xliff:g>Cambridge</item>
        <item>K<xliff:g id="separator">=</xliff:g>Kirkland</item>
        <item>M<xliff:g id="separator">=</xliff:g>Madison</item>
        <item>G<xliff:g id="separator">=</xliff:g>Guangzhou</item>
        <item>G<xliff:g id="separator">=</xliff:g>Guangzhou<xliff:g id="phonetic">:</xliff:g></item>
        <item>H<xliff:g id="separator">=</xliff:g>Hyderabad</item>
        <item>R<xliff:g id="separator">=</xliff:g>Reston</item>
        <item>B<xliff:g id="separator">=</xliff:g>Belo Horizonte</item>
+16 −8
Original line number Diff line number Diff line
@@ -691,7 +691,7 @@ public class Utils {

    public static CityObj[] loadCitiesFromXml(Context c) {
        Resources r = c.getResources();
        // Read strings array of name,timezone, id
        // Read strings array of [index, name, phonetic name, timezone, id]
        // make sure the list are the same length
        String[] cityNames = r.getStringArray(R.array.cities_names);
        String[] timezones = r.getStringArray(R.array.cities_tz);
@@ -706,33 +706,41 @@ public class Utils {
            // Default to using the first character of the city name as the index unless one is
            // specified. The indicator for a specified index is the addition of character(s)
            // before the "=" separator.
            final String parseString = cityNames[i];
            String parseString = cityNames[i];
            final int separatorIndex = parseString.indexOf("=");
            final String index;
            final String cityName;
            if (parseString.length() <= 1 && separatorIndex >= 0) {
                LogUtils.w("Cannot parse city name %s; skipping", parseString);
                continue;
            }
            // Parse Index.
            if (separatorIndex == 0) {
                // Default to using second character (the first character after the = separator)
                // as the index.
                index = parseString.substring(1, 2);
                cityName = parseString.substring(1);
                parseString = parseString.substring(1);
            } else if (separatorIndex == -1) {
                // Default to using the first character as the index
                index = parseString.substring(0, 1);
                cityName = parseString;
                LogUtils.e("Missing expected separator character =");
            } else {
                 index = parseString.substring(0, separatorIndex);
                 cityName = parseString.substring(separatorIndex + 1);
                 parseString = parseString.substring(separatorIndex + 1);
            }
            // Separate city name and phonetic name.
            final String[] names = parseString.split(":");
            if (names.length == 2) {
                cities[i] = new CityObj(names[0], names[1], timezones[i], ids[i], index);
            } else {
                cities[i] = new CityObj(names[0], null, timezones[i], ids[i], index);
            }
            cities[i] = new CityObj(cityName, timezones[i], ids[i], index);
        }
        return cities;
    }
    // Returns a map of cities where the key is lowercase

    /**
     * Returns a map of cities where the key is lowercase
     */
    public static Map<String, CityObj> loadCityMapFromXml(Context c) {
        CityObj[] cities = loadCitiesFromXml(c);

+1 −4
Original line number Diff line number Diff line
@@ -134,8 +134,6 @@ public class CitiesActivity extends BaseActivity implements OnCheckedChangeListe
        private final String mPattern12;
        private final String mPattern24;

        private int mSelectedEndPosition = 0;

        private Filter mFilter = new Filter() {

            @Override
@@ -155,7 +153,7 @@ public class CitiesActivity extends BaseActivity implements OnCheckedChangeListe
                    if (mSelectedCities.length > 0) {
                        sectionHeaders.add("+");
                        sectionPositions.add(0);
                        filteredList.add(new CityObj(mSelectedCitiesHeaderString,
                        filteredList.add(new CityObj(mSelectedCitiesHeaderString, null,
                                mSelectedCitiesHeaderString, null, null));
                    }
                    for (CityObj city : mSelectedCities) {
@@ -168,7 +166,6 @@ public class CitiesActivity extends BaseActivity implements OnCheckedChangeListe
                for (CityObj c : mSelectedCities) {
                    selectedCityIds.add(c.mCityId);
                }
                mSelectedEndPosition = filteredList.size();

                long currentTime = System.currentTimeMillis();
                String val = null;
+10 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.deskclock.worldclock;
import java.text.Collator;
import java.util.Comparator;

public class CityNameComparator implements Comparator<CityObj> {
public final class CityNameComparator implements Comparator<CityObj> {

    private Collator mCollator;

@@ -28,6 +28,14 @@ public class CityNameComparator implements Comparator<CityObj> {

    @Override
    public int compare(CityObj c1, CityObj c2) {
        return mCollator.compare(c1.mCityName, c2.mCityName);
        final int naturalIndexOrder = c1.mCityNumericIndex - c2.mCityNumericIndex;
        if (naturalIndexOrder != 0) {
            return naturalIndexOrder;
        }
        final int indexOrder = mCollator.compare(c1.mCityIndex, c2.mCityIndex);
        if (indexOrder != 0) {
            return indexOrder;
        }
        return mCollator.compare(c1.mCityPhoneticName, c2.mCityPhoneticName);
    }
}
+29 −2
Original line number Diff line number Diff line
@@ -17,48 +17,75 @@
package com.android.deskclock.worldclock;

import android.content.SharedPreferences;
import android.text.TextUtils;

public class CityObj {
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class CityObj {
    // Regex to match numeric values.
    private static final Pattern NATURAL_INDEX_REGEX = Pattern.compile("\\d+");
    // Data key to store in
    private static final String CITY_NAME = "city_name_";
    private static final String CITY_PHONETIC_NAME = "city_phonetic_name_";
    private static final String CITY_TIME_ZONE = "city_tz_";
    private static final String CITY_ID = "city_id_";
    private static final String CITY_INDEX = "city_index_";
    private static final String CITY_NUMERIC_INDEX = "city_numeric_index_";

    public String mCityName;
    public String mCityPhoneticName;
    public String mTimeZone;
    public String mCityId;
    public String mCityIndex;
    public int mCityNumericIndex;
    public boolean isHeader;

    public CityObj(String name, String timezone, String id, String index) {
    public CityObj(String name, String phoneticName, String timezone, String id, String index) {
        mCityName = name;
        mCityPhoneticName = TextUtils.isEmpty(phoneticName) ? name : phoneticName;
        mTimeZone = timezone;
        mCityId = id;
        mCityIndex = index;

        // Build a natural index by extracting numeric values from {@link #mCityIndex} and store as
        // {@link #mCityNumericIndex}, which is used as primary strength to sort a list of
        // {@link CityObj}.
        // This is necessary so we can sort index list like ["1 stroke, 2 strokes, 10 strokes"]
        // in a human friendly way.
        if (mCityIndex != null) {
            final Matcher matcher = NATURAL_INDEX_REGEX.matcher(mCityIndex);
            mCityNumericIndex = matcher.find() ? Integer.parseInt(matcher.group()) : 0;
        }
    }

    @Override
    public String toString() {
        return "CityObj{" +
                "name=" + mCityName +
                ", phonetic=" + mCityPhoneticName +
                ", timezone=" + mTimeZone +
                ", id=" + mCityId +
                ", index=" + mCityIndex +
                ", numericIndex=" + mCityNumericIndex +
                '}';
    }

    public CityObj(SharedPreferences prefs, int index) {
        mCityName = prefs.getString(CITY_NAME + index, null);
        mCityPhoneticName = prefs.getString(CITY_PHONETIC_NAME + index, mCityName);
        mTimeZone = prefs.getString(CITY_TIME_ZONE + index, null);
        mCityId = prefs.getString(CITY_ID + index, null);
        mCityIndex = prefs.getString(CITY_INDEX + index, null);
        mCityNumericIndex = prefs.getInt(CITY_NUMERIC_INDEX + index, 0);
    }

    public void saveCityToSharedPrefs(SharedPreferences.Editor editor, int index) {
        editor.putString(CITY_NAME + index, mCityName);
        editor.putString(CITY_PHONETIC_NAME + index, mCityPhoneticName);
        editor.putString(CITY_TIME_ZONE + index, mTimeZone);
        editor.putString(CITY_ID + index, mCityId);
        editor.putString(CITY_INDEX + index, mCityIndex);
        editor.putInt(CITY_NUMERIC_INDEX + index, mCityNumericIndex);
    }
}
Loading