/* * Copyright (C) 2013 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.appsimobile.appsii.timezonepicker; import android.content.Context; import android.content.res.Resources; import android.os.Build; import android.text.Spannable; import android.text.Spannable.Factory; import android.text.format.DateUtils; import android.text.format.Time; import android.text.style.ForegroundColorSpan; import android.util.Log; import com.appsimobile.appsii.R; import java.util.Locale; import java.util.TimeZone; public class TimeZonePickerUtils { public static final int GMT_TEXT_COLOR = 0xFF888888; public static final int DST_SYMBOL_COLOR = 0xFFBFBFBF; private static final String TAG = "TimeZonePickerUtils"; private static final Factory mSpannableFactory = Factory.getInstance(); private Locale mDefaultLocale; private String[] mOverrideIds; private String[] mOverrideLabels; /** * This needs to be an instantiated class so that it doesn't need to continuously re-load the * list of timezone IDs that need to be overridden. */ public TimeZonePickerUtils(Context context) { // Instead of saving a reference to the context (because we might need to look up the // labels every time getGmtDisplayName is called), we'll cache the lists of override IDs // and labels now. cacheOverrides(context); } private void cacheOverrides(Context context) { Resources res = context.getResources(); mOverrideIds = res.getStringArray(R.array.timezone_rename_ids); mOverrideLabels = res.getStringArray(R.array.timezone_rename_labels); } /** * Given a timezone id (e.g. America/Los_Angeles), returns the corresponding timezone * display name (e.g. Pacific Time GMT-7). * * @param context Context in case the override labels need to be re-cached. * @param id The timezone id * @param millis The time (daylight savings or not) * @param grayGmt Whether the "GMT+x" part of the returned string should be colored gray. * * @return The display name of the timezone. */ public CharSequence getGmtDisplayName(Context context, String id, long millis, boolean grayGmt) { TimeZone timezone = TimeZone.getTimeZone(id); if (timezone == null) { return null; } final Locale defaultLocale = Locale.getDefault(); if (!defaultLocale.equals(mDefaultLocale)) { // If the IDs and labels haven't been set yet, or if the locale has been changed // recently, we'll need to re-cache them. mDefaultLocale = defaultLocale; cacheOverrides(context); } return buildGmtDisplayName(timezone, millis, grayGmt); } private CharSequence buildGmtDisplayName(TimeZone tz, long timeMillis, boolean grayGmt) { Time time = new Time(tz.getID()); time.set(timeMillis); StringBuilder sb = new StringBuilder(); String displayName = getDisplayName(tz, time.isDst != 0); sb.append(displayName); sb.append(" "); final int gmtOffset = tz.getOffset(timeMillis); int gmtStart = sb.length(); appendGmtOffset(sb, gmtOffset); int gmtEnd = sb.length(); int symbolStart = 0; int symbolEnd = 0; if (tz.useDaylightTime()) { sb.append(" "); symbolStart = sb.length(); sb.append(getDstSymbol()); // Sun symbol symbolEnd = sb.length(); } // Set the gray colors. Spannable spannableText = mSpannableFactory.newSpannable(sb); if (grayGmt) { spannableText.setSpan(new ForegroundColorSpan(GMT_TEXT_COLOR), gmtStart, gmtEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } if (tz.useDaylightTime()) { spannableText.setSpan(new ForegroundColorSpan(DST_SYMBOL_COLOR), symbolStart, symbolEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } return spannableText; } /** * Gets the display name for the specified Timezone ID. If the ID matches the list of IDs that * need to be have their default display names overriden, use the pre-set display name from * R.arrays. * * @param id The timezone ID. * @param daylightTime True for daylight time, false for standard time * * @return The display name of the timezone. This will just use the default display name, * except that certain timezones have poor defaults, and should use the pre-set override labels * from R.arrays. */ private String getDisplayName(TimeZone tz, boolean daylightTime) { if (mOverrideIds == null || mOverrideLabels == null) { // Just in case they somehow didn't get loaded correctly. return tz.getDisplayName(daylightTime, TimeZone.LONG, Locale.getDefault()); } for (int i = 0; i < mOverrideIds.length; i++) { if (tz.getID().equals(mOverrideIds[i])) { if (mOverrideLabels.length > i) { return mOverrideLabels[i]; } Log.e(TAG, "timezone_rename_ids len=" + mOverrideIds.length + " timezone_rename_labels len=" + mOverrideLabels.length); break; } } // If the ID doesn't need to have the display name overridden, or if the labels were // malformed, just use the default. return tz.getDisplayName(daylightTime, TimeZone.LONG, Locale.getDefault()); } public static void appendGmtOffset(StringBuilder sb, final int gmtOffset) { sb.append("GMT"); if (gmtOffset < 0) { sb.append('-'); } else { sb.append('+'); } final int p = Math.abs(gmtOffset); sb.append(p / DateUtils.HOUR_IN_MILLIS); // Hour final int min = (p / (int) DateUtils.MINUTE_IN_MILLIS) % 60; if (min != 0) { // Show minutes if non-zero sb.append(':'); if (min < 10) { sb.append('0'); } sb.append(min); } } public static char getDstSymbol() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { return '\u2600'; // The Sun emoji icon. } else { return '*'; } } }