Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2015 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.deskclock.data;
     18 
     19 import java.text.Collator;
     20 import java.util.Comparator;
     21 import java.util.TimeZone;
     22 
     23 /**
     24  * A read-only domain object representing a city of the world and associated time information. It
     25  * also contains static comparators that can be instantiated to order cities in common sort orders.
     26  */
     27 public final class City {
     28 
     29     /** A unique identifier for the city. */
     30     private final String mId;
     31 
     32     /** An optional numeric index used to order cities for display; -1 if no such index exists. */
     33     private final int mIndex;
     34 
     35     /** An index string used to order cities for display. */
     36     private final String mIndexString;
     37 
     38     /** The display name of the city. */
     39     private final String mName;
     40 
     41     /** The phonetic name of the city used to order cities for display. */
     42     private final String mPhoneticName;
     43 
     44     /** The {@link TimeZone#getID() id} of the timezone in which the city is located. */
     45     private final String mTimeZoneId;
     46 
     47     /** The TimeZone corresponding to the {@link #mTimeZoneId}. */
     48     private final TimeZone mTimeZone;
     49 
     50     /** A cached upper case form of the {@link #mName} used in case-insensitive name comparisons. */
     51     private String mNameUpperCase;
     52 
     53     City(String id, int index, String indexString, String name, String phoneticName,
     54             String timeZoneId) {
     55         mId = id;
     56         mIndex = index;
     57         mIndexString = indexString;
     58         mName = name;
     59         mPhoneticName = phoneticName;
     60         mTimeZoneId = timeZoneId;
     61         mTimeZone = TimeZone.getTimeZone(mTimeZoneId);
     62     }
     63 
     64     public String getId() { return mId; }
     65     public int getIndex() { return mIndex; }
     66     public String getName() { return mName; }
     67     public TimeZone getTimeZone() { return mTimeZone; }
     68     public String getTimeZoneId() { return mTimeZoneId; }
     69     public String getIndexString() { return mIndexString; }
     70     public String getPhoneticName() { return mPhoneticName; }
     71 
     72     public String getNameUpperCase() {
     73         if (mNameUpperCase == null) {
     74             mNameUpperCase = mName.toUpperCase();
     75         }
     76         return mNameUpperCase;
     77     }
     78 
     79     @Override
     80     public String toString() {
     81         return String.format("City {id=%s, index=%d, indexString=%s, name=%s, phonetic=%s, tz=%s}",
     82                 mId, mIndex, mIndexString, mName, mPhoneticName, mTimeZoneId);
     83     }
     84 
     85     /**
     86      * Orders by:
     87      *
     88      * <ol>
     89      *     <li>UTC offset of {@link #getTimeZone() timezone}</li>
     90      *     <li>{@link #getIndex() numeric index}</li>
     91      *     <li>{@link #getIndexString()} alphabetic index}</li>
     92      *     <li>{@link #getPhoneticName() phonetic name}</li>
     93      * </ol>
     94      */
     95     public static final class UtcOffsetComparator implements Comparator<City> {
     96 
     97         private final Comparator<City> mDelegate1 = new UtcOffsetIndexComparator();;
     98 
     99         private final Comparator<City> mDelegate2 = new NameComparator();
    100 
    101         public int compare(City c1, City c2) {
    102             int result = mDelegate1.compare(c1, c2);
    103 
    104             if (result == 0) {
    105                 result = mDelegate2.compare(c1, c2);
    106             }
    107 
    108             return result;
    109         }
    110     }
    111 
    112     /**
    113      * Orders by:
    114      *
    115      * <ol>
    116      *     <li>UTC offset of {@link #getTimeZone() timezone}</li>
    117      * </ol>
    118      */
    119     public static final class UtcOffsetIndexComparator implements Comparator<City> {
    120 
    121         // Snapshot the current time when the Comparator is created to obtain consistent offsets.
    122         private final long now = System.currentTimeMillis();
    123 
    124         public int compare(City c1, City c2) {
    125             final int utcOffset1 = c1.getTimeZone().getOffset(now);
    126             final int utcOffset2 = c2.getTimeZone().getOffset(now);
    127             return Integer.compare(utcOffset1, utcOffset2);
    128         }
    129     }
    130 
    131     /**
    132      * This comparator sorts using the city fields that influence natural name sort order:
    133      *
    134      * <ol>
    135      *     <li>{@link #getIndex() numeric index}</li>
    136      *     <li>{@link #getIndexString()} alphabetic index}</li>
    137      *     <li>{@link #getPhoneticName() phonetic name}</li>
    138      * </ol>
    139      */
    140     public static final class NameComparator implements Comparator<City> {
    141 
    142         private final Comparator<City> mDelegate = new NameIndexComparator();
    143 
    144         // Locale-sensitive comparator for phonetic names.
    145         private final Collator mNameCollator = Collator.getInstance();
    146 
    147         @Override
    148         public int compare(City c1, City c2) {
    149             int result = mDelegate.compare(c1, c2);
    150 
    151             if (result == 0) {
    152                 result = mNameCollator.compare(c1.getPhoneticName(), c2.getPhoneticName());
    153             }
    154 
    155             return result;
    156         }
    157     }
    158 
    159     /**
    160      * Orders by:
    161      *
    162      * <ol>
    163      *     <li>{@link #getIndex() numeric index}</li>
    164      *     <li>{@link #getIndexString()} alphabetic index}</li>
    165      * </ol>
    166      */
    167     public static final class NameIndexComparator implements Comparator<City> {
    168 
    169         // Locale-sensitive comparator for index strings.
    170         private final Collator mNameCollator = Collator.getInstance();
    171 
    172         @Override
    173         public int compare(City c1, City c2) {
    174             int result = Integer.compare(c1.getIndex(), c2.getIndex());
    175 
    176             if (result == 0) {
    177                 result = mNameCollator.compare(c1.getIndexString(), c2.getIndexString());
    178             }
    179 
    180             return result;
    181         }
    182     }
    183 }