summaryrefslogtreecommitdiff
path: root/src/com/android/timezonepicker/TimeZonePickerUtils.java
blob: e0f50cec5a90f6305f5c1702eca42ba6bc16d9ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * 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.android.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 java.util.Locale;
import java.util.TimeZone;

public class TimeZonePickerUtils {
    private static final String TAG = "TimeZonePickerUtils";

    public static final int GMT_TEXT_COLOR = 0xFF888888;
    public static final int DST_SYMBOL_COLOR = 0xFFBFBFBF;
    private static final Factory mSpannableFactory = Spannable.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.
     * @param context
     */
    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);
    }

    /**
     * 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);
        }

        CharSequence gmtDisplayName = spannableText;
        return gmtDisplayName;
    }

    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 '*';
        }
    }

    /**
     * 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());
    }

    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);
    }
}