• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.globaltime;
18 
19 import java.io.DataInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.util.Arrays;
23 import java.util.Comparator;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.TimeZone;
28 
29 /**
30  * A class representing a city, with an associated position, time zone name,
31  * and raw offset from UTC.
32  */
33 public  class City implements Comparable<City> {
34 
35     private static Map<String,City> cities = new HashMap<String,City>();
36     private static City[] citiesByRawOffset;
37 
38     private String name;
39     private String timeZoneID;
40     private TimeZone timeZone = null;
41     private int rawOffset;
42     private float latitude, longitude;
43     private float x, y, z;
44 
45     /**
46      * Loads the city database.  The cities must be stored in order by raw
47      * offset from UTC.
48      */
loadCities(InputStream is)49     public static void loadCities(InputStream is) throws IOException {
50         DataInputStream dis = new DataInputStream(is);
51         int numCities = dis.readInt();
52         citiesByRawOffset = new City[numCities];
53 
54         byte[] buf = new byte[24];
55         for (int i = 0; i < numCities; i++) {
56             String name = dis.readUTF();
57             String tzid = dis.readUTF();
58             dis.read(buf);
59 
60 //          The code below is a faster version of:
61 //          int rawOffset = dis.readInt();
62 //          float latitude = dis.readFloat();
63 //          float longitude = dis.readFloat();
64 //          float cx = dis.readFloat();
65 //          float cy = dis.readFloat();
66 //          float cz = dis.readFloat();
67 
68             int rawOffset =
69                        (buf[ 0] << 24) |       ((buf[ 1] & 0xff) << 16) |
70                       ((buf[ 2] & 0xff) << 8) | (buf[ 3] & 0xff);
71             int ilat = (buf[ 4] << 24) |       ((buf[ 5] & 0xff) << 16) |
72                       ((buf[ 6] & 0xff) << 8) | (buf[ 7] & 0xff);
73             int ilon = (buf[ 8] << 24) |       ((buf[ 9] & 0xff) << 16) |
74                       ((buf[10] & 0xff) << 8) | (buf[11] & 0xff);
75             int icx =  (buf[12] << 24) |       ((buf[13] & 0xff) << 16) |
76                       ((buf[14] & 0xff) << 8) | (buf[15] & 0xff);
77             int icy =  (buf[16] << 24) |       ((buf[17] & 0xff) << 16) |
78                       ((buf[18] & 0xff) << 8) | (buf[19] & 0xff);
79             int icz =  (buf[20] << 24) |       ((buf[21] & 0xff) << 16) |
80                       ((buf[22] & 0xff) << 8) | (buf[23] & 0xff);
81             float latitude = Float.intBitsToFloat(ilat);
82             float longitude = Float.intBitsToFloat(ilon);
83             float cx = Float.intBitsToFloat(icx);
84             float cy = Float.intBitsToFloat(icy);
85             float cz = Float.intBitsToFloat(icz);
86 
87             City city = new City(name, tzid, rawOffset,
88                                  latitude, longitude, cx, cy, cz);
89 
90             cities.put(name, city);
91             citiesByRawOffset[i] = city;
92         }
93     }
94 
95     /**
96      * Returns the cities, ordered by name.
97      */
getCitiesByName()98     public static City[] getCitiesByName() {
99         City[] ocities = new City[cities.size()];
100         Iterator<City> iter = cities.values().iterator();
101         int idx = 0;
102         while (iter.hasNext()) {
103             ocities[idx++] = iter.next();
104         }
105         Arrays.sort(ocities);
106         return ocities;
107     }
108 
109     /**
110      * Returns the cities, ordered by offset, accounting for summer/daylight
111      * savings time.  This requires reading the entire time zone database
112      * behind the scenes.
113      */
getCitiesByOffset()114     public static City[] getCitiesByOffset() {
115         City[] ocities = new City[cities.size()];
116         Iterator<City> iter = cities.values().iterator();
117         int idx = 0;
118         while (iter.hasNext()) {
119             ocities[idx++] = iter.next();
120         }
121         Arrays.sort(ocities, new Comparator() {
122                 public int compare(Object o1, Object o2) {
123                     long now = System.currentTimeMillis();
124                     City c1 = (City)o1;
125                     City c2 = (City)o2;
126                     TimeZone tz1 = c1.getTimeZone();
127                     TimeZone tz2 = c2.getTimeZone();
128                     int off1 = tz1.getOffset(now);
129                     int off2 = tz2.getOffset(now);
130                     if (off1 == off2) {
131                         float dlat = c2.getLatitude() - c1.getLatitude();
132                         if (dlat < 0.0f) return -1;
133                         if (dlat > 0.0f) return 1;
134                         return 0;
135                     }
136                     return off1 - off2;
137                 }
138             });
139         return ocities;
140     }
141 
142 
143     /**
144      * Returns the cities, ordered by offset, accounting for summer/daylight
145      * savings time.  This does not require reading the time zone database
146      * since the cities are pre-sorted.
147      */
getCitiesByRawOffset()148     public static City[] getCitiesByRawOffset() {
149         return citiesByRawOffset;
150     }
151 
152     /**
153      * Returns an Iterator over all cities, in raw offset order.
154      */
iterator()155     public static Iterator<City> iterator() {
156         return cities.values().iterator();
157     }
158 
159     /**
160      * Returns the total number of cities.
161      */
numCities()162     public static int numCities() {
163         return cities.size();
164     }
165 
166     /**
167      * Constructs a city with the given name, time zone name, raw offset,
168      * latitude, longitude, and 3D (X, Y, Z) coordinate.
169      */
City(String name, String timeZoneID, int rawOffset, float latitude, float longitude, float x, float y, float z)170     public City(String name, String timeZoneID,
171                 int rawOffset,
172                 float latitude, float longitude,
173                 float x, float y, float z) {
174         this.name = name;
175         this.timeZoneID = timeZoneID;
176         this.rawOffset = rawOffset;
177         this.latitude = latitude;
178         this.longitude = longitude;
179         this.x = x;
180         this.y = y;
181         this.z = z;
182     }
183 
getName()184     public String getName() {
185         return name;
186     }
187 
getTimeZone()188     public TimeZone getTimeZone() {
189         if (timeZone == null) {
190             timeZone = TimeZone.getTimeZone(timeZoneID);
191         }
192         return timeZone;
193     }
194 
getLongitude()195     public float getLongitude() {
196         return longitude;
197     }
198 
getLatitude()199     public float getLatitude() {
200         return latitude;
201     }
202 
getX()203     public float getX() {
204         return x;
205     }
206 
getY()207     public float getY() {
208         return y;
209     }
210 
getZ()211     public float getZ() {
212         return z;
213     }
214 
getRawOffset()215     public float getRawOffset() {
216         return rawOffset / 3600000.0f;
217     }
218 
getRawOffsetMillis()219     public int getRawOffsetMillis() {
220         return rawOffset;
221     }
222 
223     /**
224      * Returns this city's offset from UTC, taking summer/daylight savigns
225      * time into account.
226      */
getOffset()227     public float getOffset() {
228         long now = System.currentTimeMillis();
229         if (timeZone == null) {
230             timeZone = TimeZone.getTimeZone(timeZoneID);
231         }
232         return timeZone.getOffset(now) / 3600000.0f;
233     }
234 
235     /**
236      * Compares this city to another by name.
237      */
compareTo(City o)238     public int compareTo(City o) {
239         return name.compareTo(o.name);
240     }
241 }
242