TimeZonePickerUtils.java revision adbe2ac08b1456d2ed2e4adc2afa9c078a3e028e
1/* 2 * Copyright (C) 2013 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 17package com.android.timezonepicker; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.os.Build; 22import android.text.Spannable; 23import android.text.Spannable.Factory; 24import android.text.format.DateUtils; 25import android.text.format.Time; 26import android.text.style.ForegroundColorSpan; 27import android.util.Log; 28 29import java.util.Locale; 30import java.util.TimeZone; 31 32public class TimeZonePickerUtils { 33 private static final String TAG = "TimeZonePickerUtils"; 34 35 public static final int GMT_TEXT_COLOR = 0xFFAAAAAA; 36 public static final int DST_SYMBOL_COLOR = 0xFFBFBFBF; 37 private static final Factory mSpannableFactory = Spannable.Factory.getInstance(); 38 39 private Locale mDefaultLocale; 40 private String[] mOverrideIds; 41 private String[] mOverrideLabels; 42 43 /** 44 * This needs to be an instantiated class so that it doesn't need to continuously re-load the 45 * list of timezone IDs that need to be overridden. 46 * @param context 47 */ 48 public TimeZonePickerUtils(Context context) { 49 // Instead of saving a reference to the context (because we might need to look up the 50 // labels every time getGmtDisplayName is called), we'll cache the lists of override IDs 51 // and labels now. 52 cacheOverrides(context); 53 } 54 55 /** 56 * Given a timezone id (e.g. America/Los_Angeles), returns the corresponding timezone 57 * display name (e.g. Pacific Time GMT-7). 58 * 59 * @param context Context in case the override labels need to be re-cached. 60 * @param id The timezone id 61 * @param millis The time (daylight savings or not) 62 * @return The display name of the timezone. 63 */ 64 public CharSequence getGmtDisplayName(Context context, String id, long millis) { 65 TimeZone timezone = TimeZone.getTimeZone(id); 66 if (timezone == null) { 67 return null; 68 } 69 70 final Locale defaultLocale = Locale.getDefault(); 71 if (!defaultLocale.equals(mDefaultLocale)) { 72 // If the IDs and labels haven't been set yet, or if the locale has been changed 73 // recently, we'll need to re-cache them. 74 mDefaultLocale = defaultLocale; 75 cacheOverrides(context); 76 } 77 return buildGmtDisplayName(timezone, millis); 78 } 79 80 private CharSequence buildGmtDisplayName(TimeZone tz, long timeMillis) { 81 Time time = new Time(tz.getID()); 82 time.set(timeMillis); 83 84 StringBuilder sb = new StringBuilder(); 85 86 String displayName = getDisplayName(tz, time.isDst != 0); 87 sb.append(displayName); 88 89 sb.append(" "); 90 final int gmtOffset = tz.getOffset(timeMillis); 91 int gmtStart = sb.length(); 92 appendGmtOffset(sb, gmtOffset); 93 int gmtEnd = sb.length(); 94 95 int symbolStart = 0; 96 int symbolEnd = 0; 97 if (tz.useDaylightTime()) { 98 sb.append(" "); 99 symbolStart = sb.length(); 100 sb.append(getDstSymbol()); // Sun symbol 101 symbolEnd = sb.length(); 102 } 103 104 // Set the gray colors. 105 Spannable spannableText = mSpannableFactory.newSpannable(sb); 106 spannableText.setSpan(new ForegroundColorSpan(GMT_TEXT_COLOR), 107 gmtStart, gmtEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 108 if (tz.useDaylightTime()) { 109 spannableText.setSpan(new ForegroundColorSpan(DST_SYMBOL_COLOR), 110 symbolStart, symbolEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 111 } 112 113 CharSequence gmtDisplayName = spannableText; 114 return gmtDisplayName; 115 } 116 117 public static void appendGmtOffset(StringBuilder sb, final int gmtOffset) { 118 sb.append("GMT"); 119 120 if (gmtOffset < 0) { 121 sb.append('-'); 122 } else { 123 sb.append('+'); 124 } 125 126 final int p = Math.abs(gmtOffset); 127 sb.append(p / DateUtils.HOUR_IN_MILLIS); // Hour 128 129 final int min = (p / (int) DateUtils.MINUTE_IN_MILLIS) % 60; 130 if (min != 0) { // Show minutes if non-zero 131 sb.append(':'); 132 if (min < 10) { 133 sb.append('0'); 134 } 135 sb.append(min); 136 } 137 } 138 139 public static char getDstSymbol() { 140 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 141 return '\u2600'; // The Sun emoji icon. 142 } else { 143 return '*'; 144 } 145 } 146 147 /** 148 * Gets the display name for the specified Timezone ID. If the ID matches the list of IDs that 149 * need to be have their default display names overriden, use the pre-set display name from 150 * R.arrays. 151 * @param id The timezone ID. 152 * @param daylightTime True for daylight time, false for standard time 153 * @return The display name of the timezone. This will just use the default display name, 154 * except that certain timezones have poor defaults, and should use the pre-set override labels 155 * from R.arrays. 156 */ 157 private String getDisplayName(TimeZone tz, boolean daylightTime) { 158 if (mOverrideIds == null || mOverrideLabels == null) { 159 // Just in case they somehow didn't get loaded correctly. 160 return tz.getDisplayName(daylightTime, TimeZone.LONG, Locale.getDefault()); 161 } 162 163 for (int i = 0; i < mOverrideIds.length; i++) { 164 if (tz.getID().equals(mOverrideIds[i])) { 165 if (mOverrideLabels.length > i) { 166 return mOverrideLabels[i]; 167 } 168 Log.e(TAG, "timezone_rename_ids len=" + mOverrideIds.length + 169 " timezone_rename_labels len=" + mOverrideLabels.length); 170 break; 171 } 172 } 173 174 // If the ID doesn't need to have the display name overridden, or if the labels were 175 // malformed, just use the default. 176 return tz.getDisplayName(daylightTime, TimeZone.LONG, Locale.getDefault()); 177 } 178 179 private void cacheOverrides(Context context) { 180 Resources res = context.getResources(); 181 mOverrideIds = res.getStringArray(R.array.timezone_rename_ids); 182 mOverrideLabels = res.getStringArray(R.array.timezone_rename_labels); 183 } 184} 185