1d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson/*
2d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * Copyright (C) 2012 The Android Open Source Project
3d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson *
4d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License");
5d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * you may not use this file except in compliance with the License.
6d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * You may obtain a copy of the License at
7d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson *
8d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson *      http://www.apache.org/licenses/LICENSE-2.0
9d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson *
10d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * Unless required by applicable law or agreed to in writing, software
11d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS,
12d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * See the License for the specific language governing permissions and
14d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson * limitations under the License.
15d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson */
16d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
17d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonpackage com.android.deskclock;
18d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
1978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.animation.Animator;
2078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.animation.AnimatorSet;
2178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.animation.ObjectAnimator;
2278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.animation.TimeInterpolator;
230b7c93a6b691b25ccbcd8d683774d3d0d351a8e9Robyn Coultasimport android.app.AlarmManager;
24d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.content.Context;
25d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.content.Intent;
26de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelsonimport android.content.SharedPreferences;
27d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.content.pm.PackageInfo;
28d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.content.pm.PackageManager.NameNotFoundException;
29d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelsonimport android.content.res.Resources;
3078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.graphics.Color;
3178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.graphics.Paint;
3278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.graphics.PorterDuff;
3378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.graphics.PorterDuffColorFilter;
3480eafdf26fc496ffa112b9eb1b44d7b80333c80arachelzhangimport android.graphics.Typeface;
35d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.net.Uri;
364fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultasimport android.os.Build;
3778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.os.Handler;
38287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzsteinimport android.os.SystemClock;
3978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.preference.PreferenceManager;
40690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.text.Spannable;
41690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.text.SpannableString;
42d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.text.TextUtils;
4378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.text.format.DateFormat;
4462b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kungimport android.text.format.DateUtils;
45eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultasimport android.text.format.Time;
46690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.text.style.AbsoluteSizeSpan;
47690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.text.style.StyleSpan;
48690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.text.style.TypefaceSpan;
49d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport android.view.MenuItem;
5078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.view.View;
5178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.view.animation.AccelerateInterpolator;
5278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.view.animation.DecelerateInterpolator;
53690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelsonimport android.widget.TextClock;
5478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport android.widget.TextView;
55d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
56de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelsonimport com.android.deskclock.stopwatch.Stopwatches;
5798b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultasimport com.android.deskclock.timer.Timers;
58d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelsonimport com.android.deskclock.worldclock.CityObj;
59de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson
6035300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelsonimport java.text.SimpleDateFormat;
6178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzsteinimport java.util.Calendar;
6235300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelsonimport java.util.Date;
63419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhangimport java.util.GregorianCalendar;
64d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonimport java.util.Locale;
6562b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kungimport java.util.TimeZone;
66d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
67d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
68d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelsonpublic class Utils {
69d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    private final static String PARAM_LANGUAGE_CODE = "hl";
70d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
71d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    /**
72d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     * Help URL query parameter key for the app version.
73d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     */
74d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    private final static String PARAM_VERSION = "version";
75d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
76d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    /**
77d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     * Cached version code to prevent repeated calls to the package manager.
78d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     */
79d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    private static String sCachedVersionCode = null;
80d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
81419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang    /**
82419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang     * Array of single-character day of week symbols {'S', 'M', 'T', 'W', 'T', 'F', 'S'}
83419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang     */
84419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang    private static String[] sShortWeekdays = null;
85419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang
8678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /** Types that may be used for clock displays. **/
8778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    public static final String CLOCK_TYPE_DIGITAL = "digital";
8878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    public static final String CLOCK_TYPE_ANALOG = "analog";
89d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
90d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    /** The background colors of the app, it changes thru out the day to mimic the sky. **/
91bfd25edaf38efb6df428ff261d127a99025d0622rachelzhang    public static final String[] BACKGROUND_SPECTRUM = { "#212121", "#27232e", "#2d253a",
92bfd25edaf38efb6df428ff261d127a99025d0622rachelzhang            "#332847", "#382a53", "#3e2c5f", "#442e6c", "#393a7a", "#2e4687", "#235395", "#185fa2",
93bfd25edaf38efb6df428ff261d127a99025d0622rachelzhang            "#0d6baf", "#0277bd", "#0d6cb1", "#1861a6", "#23569b", "#2d4a8f", "#383f84", "#433478",
94bfd25edaf38efb6df428ff261d127a99025d0622rachelzhang            "#3d3169", "#382e5b", "#322b4d", "#2c273e", "#272430" };
95d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang
967048625adb7c349deab4c00b2d85bcf65c164ae5Isaac Katzenelson    /**
97f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson     * Returns whether the SDK is KitKat or later
984fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas     */
99f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson    public static boolean isKitKatOrLater() {
100f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson        return Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2;
1014fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas    }
1024fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas
1037048625adb7c349deab4c00b2d85bcf65c164ae5Isaac Katzenelson
104d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    public static void prepareHelpMenuItem(Context context, MenuItem helpMenuItem) {
105d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        String helpUrlString = context.getResources().getString(R.string.desk_clock_help_url);
106d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        if (TextUtils.isEmpty(helpUrlString)) {
107d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            // The help url string is empty or null, so set the help menu item to be invisible.
108d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            helpMenuItem.setVisible(false);
109d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            return;
110d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        }
111d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // The help url string exists, so first add in some extra query parameters.  87
112d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        final Uri fullUri = uriWithAddedParameters(context, Uri.parse(helpUrlString));
113d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
114d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // Then, create an intent that will be fired when the user
115d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // selects this help menu item.
116d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        Intent intent = new Intent(Intent.ACTION_VIEW, fullUri);
117d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
118d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
119d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
120d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // Set the intent to the help menu item, show the help menu item in the overflow
121d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // menu, and make it visible.
122d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        helpMenuItem.setIntent(intent);
123d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        helpMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
124d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        helpMenuItem.setVisible(true);
125d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    }
126d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
127d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    /**
128d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     * Adds two query parameters into the Uri, namely the language code and the version code
1298322b2fa9d474fee9e7950fec68bd35e03fc9861Robyn Coultas     * of the application's package as gotten via the context.
130d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     * @return the uri with added query parameters
131d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson     */
132d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    private static Uri uriWithAddedParameters(Context context, Uri baseUri) {
133d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        Uri.Builder builder = baseUri.buildUpon();
134d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
135d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // Add in the preferred language
136d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        builder.appendQueryParameter(PARAM_LANGUAGE_CODE, Locale.getDefault().toString());
137d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
138d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // Add in the package version code
139d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        if (sCachedVersionCode == null) {
140d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            // There is no cached version code, so try to get it from the package manager.
141d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            try {
142d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                // cache the version code
143d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                PackageInfo info = context.getPackageManager().getPackageInfo(
144d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                        context.getPackageName(), 0);
145d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                sCachedVersionCode = Integer.toString(info.versionCode);
146d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
147d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                // append the version code to the uri
148d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
149d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            } catch (NameNotFoundException e) {
150d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                // Cannot find the package name, so don't add in the version parameter
151d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson                // This shouldn't happen.
152cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen                LogUtils.wtf("Invalid package name for context " + e);
153d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            }
154d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        } else {
155d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson            builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
156d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        }
157d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
158d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        // Build the full uri and return it
159d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson        return builder.build();
160d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson    }
161d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson
162287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein    public static long getTimeNow() {
163287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein        return SystemClock.elapsedRealtime();
164287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein    }
165287f2d82aaf91d881f5de50a133d21684a8d4821Sam Blitzstein
16600cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein    /**
16700cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein     * Calculate the amount by which the radius of a CircleTimerView should be offset by the any
16800cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein     * of the extra painted objects.
16900cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein     */
17000cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein    public static float calculateRadiusOffset(
1718322b2fa9d474fee9e7950fec68bd35e03fc9861Robyn Coultas            float strokeSize, float dotStrokeSize, float markerStrokeSize) {
1728322b2fa9d474fee9e7950fec68bd35e03fc9861Robyn Coultas        return Math.max(strokeSize, Math.max(dotStrokeSize, markerStrokeSize));
17300cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein    }
17400cb5981c984bc13aa2f6af510a9dd9a784f2af0Sam Blitzstein
175efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas    /**
176efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas     * Uses {@link Utils#calculateRadiusOffset(float, float, float)} after fetching the values
177efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas     * from the resources just as {@link CircleTimerView#init(android.content.Context)} does.
178efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas     */
179efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas    public static float calculateRadiusOffset(Resources resources) {
180efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas        if (resources != null) {
181efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas            float strokeSize = resources.getDimension(R.dimen.circletimer_circle_size);
1828322b2fa9d474fee9e7950fec68bd35e03fc9861Robyn Coultas            float dotStrokeSize = resources.getDimension(R.dimen.circletimer_dot_size);
183efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas            float markerStrokeSize = resources.getDimension(R.dimen.circletimer_marker_size);
1848322b2fa9d474fee9e7950fec68bd35e03fc9861Robyn Coultas            return calculateRadiusOffset(strokeSize, dotStrokeSize, markerStrokeSize);
185efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas        } else {
186efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas            return 0f;
187efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas        }
188efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas    }
189efc4ad3bce5f68e6a64c4aeac4f2359ab9bae5a8Robyn Coultas
19072332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    /**  The pressed color used throughout the app. If this method is changed, it will not have
19172332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein     *   any effect on the button press states, and those must be changed separately.
19272332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    **/
19372332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    public static int getPressedColorId() {
19469a4b4f2810100f19e997b4e539f1b0e56b0afb5rachelzhang        return R.color.hot_pink;
19572332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    }
19672332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein
19772332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    /**  The un-pressed color used throughout the app. If this method is changed, it will not have
19872332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein     *   any effect on the button press states, and those must be changed separately.
19972332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    **/
20072332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    public static int getGrayColorId() {
20172332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein        return R.color.clock_gray;
20272332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    }
203de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson
204de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson    /**
205de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson     * Clears the persistent data of stopwatch (start time, state, laps, etc...).
206de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson     */
207de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson    public static void clearSwSharedPref(SharedPreferences prefs) {
208de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        SharedPreferences.Editor editor = prefs.edit();
209de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        editor.remove (Stopwatches.PREF_START_TIME);
210de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        editor.remove (Stopwatches.PREF_ACCUM_TIME);
211de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        editor.remove (Stopwatches.PREF_STATE);
212de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        int lapNum = prefs.getInt(Stopwatches.PREF_LAP_NUM, Stopwatches.STOPWATCH_RESET);
213de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        for (int i = 0; i < lapNum; i++) {
214de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson            String key = Stopwatches.PREF_LAP_TIME + Integer.toString(i);
215de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson            editor.remove(key);
216de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        }
217de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        editor.remove(Stopwatches.PREF_LAP_NUM);
218de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson        editor.apply();
219de5f183f54b5d10bc8cbebb977c7c8ab391ad3f5Isaac Katzenelson    }
22098b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas
22198b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas    /**
22298b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas     * Broadcast a message to show the in-use timers in the notifications
22398b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas     */
22498b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas    public static void showInUseNotifications(Context context) {
22598b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas        Intent timerIntent = new Intent();
22698b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas        timerIntent.setAction(Timers.NOTIF_IN_USE_SHOW);
22798b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas        context.sendBroadcast(timerIntent);
22898b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas    }
22978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
230e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    /**
231e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas     * Broadcast a message to show the in-use timers in the notifications
232e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas     */
233e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    public static void showTimesUpNotifications(Context context) {
234e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        Intent timerIntent = new Intent();
235e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        timerIntent.setAction(Timers.NOTIF_TIMES_UP_SHOW);
236e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        context.sendBroadcast(timerIntent);
237e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
238e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
239e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    /**
240e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas     * Broadcast a message to cancel the in-use timers in the notifications
241e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas     */
242e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    public static void cancelTimesUpNotifications(Context context) {
243e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        Intent timerIntent = new Intent();
244e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        timerIntent.setAction(Timers.NOTIF_TIMES_UP_CANCEL);
245e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        context.sendBroadcast(timerIntent);
246e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
247e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
24878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /** Runnable for use with screensaver and dream, to move the clock every minute.
24978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     *  registerViews() must be called prior to posting.
25078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     */
25178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    public static class ScreensaverMoveSaverRunnable implements Runnable {
25278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        static final long MOVE_DELAY = 60000; // DeskClock.SCREEN_SAVER_MOVE_DELAY;
25378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        static final long SLIDE_TIME = 10000;
25478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        static final long FADE_TIME = 3000;
25578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
25678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        static final boolean SLIDE = false;
25778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
25878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        private View mContentView, mSaverView;
25978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        private final Handler mHandler;
26078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
26178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        private static TimeInterpolator mSlowStartWithBrakes;
26278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
26378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
26478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        public ScreensaverMoveSaverRunnable(Handler handler) {
26578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mHandler = handler;
26678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mSlowStartWithBrakes = new TimeInterpolator() {
26778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                @Override
26878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                public float getInterpolation(float x) {
26978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    return (float)(Math.cos((Math.pow(x,3) + 1) * Math.PI) / 2.0f) + 0.5f;
27078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                }
27178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            };
27278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
27378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
27478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        public void registerViews(View contentView, View saverView) {
27578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mContentView = contentView;
27678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mSaverView = saverView;
27778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
27878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
27978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        @Override
28078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        public void run() {
28178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            long delay = MOVE_DELAY;
28278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            if (mContentView == null || mSaverView == null) {
28378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                mHandler.removeCallbacks(this);
28478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                mHandler.postDelayed(this, delay);
28578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                return;
28678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            }
28778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
28878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            final float xrange = mContentView.getWidth() - mSaverView.getWidth();
28978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            final float yrange = mContentView.getHeight() - mSaverView.getHeight();
29078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
29178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            if (xrange == 0 && yrange == 0) {
29278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                delay = 500; // back in a split second
29378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            } else {
29478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                final int nextx = (int) (Math.random() * xrange);
29578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                final int nexty = (int) (Math.random() * yrange);
29678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
29778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                if (mSaverView.getAlpha() == 0f) {
29878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    // jump right there
29978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    mSaverView.setX(nextx);
30078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    mSaverView.setY(nexty);
30178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f)
30278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        .setDuration(FADE_TIME)
30378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        .start();
30478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                } else {
30578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    AnimatorSet s = new AnimatorSet();
30678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator xMove   = ObjectAnimator.ofFloat(mSaverView,
30778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                                         "x", mSaverView.getX(), nextx);
30878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator yMove   = ObjectAnimator.ofFloat(mSaverView,
30978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                                         "y", mSaverView.getY(), nexty);
31078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
31178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator xShrink = ObjectAnimator.ofFloat(mSaverView, "scaleX", 1f, 0.85f);
31278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator xGrow   = ObjectAnimator.ofFloat(mSaverView, "scaleX", 0.85f, 1f);
31378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
31478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator yShrink = ObjectAnimator.ofFloat(mSaverView, "scaleY", 1f, 0.85f);
31578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator yGrow   = ObjectAnimator.ofFloat(mSaverView, "scaleY", 0.85f, 1f);
31678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    AnimatorSet shrink = new AnimatorSet(); shrink.play(xShrink).with(yShrink);
31778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    AnimatorSet grow = new AnimatorSet(); grow.play(xGrow).with(yGrow);
31878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
31978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator fadeout = ObjectAnimator.ofFloat(mSaverView, "alpha", 1f, 0f);
32078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    Animator fadein = ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f);
32178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
32278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
32378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    if (SLIDE) {
32478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(xMove).with(yMove);
32578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.setDuration(SLIDE_TIME);
32678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
32778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(shrink.setDuration(SLIDE_TIME/2));
32878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(grow.setDuration(SLIDE_TIME/2)).after(shrink);
32978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.setInterpolator(mSlowStartWithBrakes);
33078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    } else {
33178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        AccelerateInterpolator accel = new AccelerateInterpolator();
33278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        DecelerateInterpolator decel = new DecelerateInterpolator();
33378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
33478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        shrink.setDuration(FADE_TIME).setInterpolator(accel);
33578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        fadeout.setDuration(FADE_TIME).setInterpolator(accel);
33678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        grow.setDuration(FADE_TIME).setInterpolator(decel);
33778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        fadein.setDuration(FADE_TIME).setInterpolator(decel);
33878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(shrink);
33978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(fadeout);
34078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(xMove.setDuration(0)).after(FADE_TIME);
34178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(yMove.setDuration(0)).after(FADE_TIME);
34278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(fadein).after(FADE_TIME);
34378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        s.play(grow).after(FADE_TIME);
34478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    }
34578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    s.start();
34678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                }
34778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
34878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                long now = System.currentTimeMillis();
34978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                long adjust = (now % 60000);
35078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                delay = delay
35178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        + (MOVE_DELAY - adjust) // minute aligned
35278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        - (SLIDE ? 0 : FADE_TIME) // start moving before the fade
35378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                        ;
35478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            }
35578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
35678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mHandler.removeCallbacks(this);
35778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            mHandler.postDelayed(this, delay);
35878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
35978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
36078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
36178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /** Setup to find out when the quarter-hour changes (e.g. Kathmandu is GMT+5:45) **/
3623bb9d29c12584480f3651ccbef86f2777c0b7818Robyn Coultas    public static long getAlarmOnQuarterHour() {
36378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        Calendar nextQuarter = Calendar.getInstance();
36478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        //  Set 1 second to ensure quarter-hour threshold passed.
36578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        nextQuarter.set(Calendar.SECOND, 1);
366851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson        nextQuarter.set(Calendar.MILLISECOND, 0);
36778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        int minute = nextQuarter.get(Calendar.MINUTE);
36878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        nextQuarter.add(Calendar.MINUTE, 15 - (minute % 15));
36978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        long alarmOnQuarterHour = nextQuarter.getTimeInMillis();
370851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson        long now = System.currentTimeMillis();
371851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson        long delta = alarmOnQuarterHour - now;
372851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson        if (0 >= delta || delta > 901000) {
373851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson            // Something went wrong in the calculation, schedule something that is
374851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson            // about 15 minutes. Next time , it will align with the 15 minutes border.
375851c662d9f02e76c9fd23426c9e6713521e01aacIsaac Katzenelson            alarmOnQuarterHour = now + 901000;
37678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
37778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        return alarmOnQuarterHour;
37878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
37978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
380eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    // Setup a thread that starts at midnight plus one second. The extra second is added to ensure
381eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    // the date has changed.
382eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    public static void setMidnightUpdater(Handler handler, Runnable runnable) {
383eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        String timezone = TimeZone.getDefault().getID();
384eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        if (handler == null || runnable == null || timezone == null) {
385eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas            return;
386eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        }
387eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        long now = System.currentTimeMillis();
388eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        Time time = new Time(timezone);
389eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        time.set(now);
390eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        long runInMillis = ((24 - time.hour) * 3600 - time.minute * 60 - time.second + 1) * 1000;
391eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        handler.removeCallbacks(runnable);
392eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        handler.postDelayed(runnable, runInMillis);
393eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    }
394eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas
395eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    // Stop the midnight update thread
3963bb9d29c12584480f3651ccbef86f2777c0b7818Robyn Coultas    public static void cancelMidnightUpdater(Handler handler, Runnable runnable) {
397eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        if (handler == null || runnable == null) {
398eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas            return;
399eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        }
400eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas        handler.removeCallbacks(runnable);
4019096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    }
4029096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas
4039096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    // Setup a thread that starts at the quarter-hour plus one second. The extra second is added to
4049096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    // ensure dates have changed.
4059096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    public static void setQuarterHourUpdater(Handler handler, Runnable runnable) {
4069096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        String timezone = TimeZone.getDefault().getID();
4079096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        if (handler == null || runnable == null || timezone == null) {
4089096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas            return;
4099096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        }
4109096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        long runInMillis = getAlarmOnQuarterHour() - System.currentTimeMillis();
4119096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        // Ensure the delay is at least one second.
4129096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        if (runInMillis < 1000) {
4139096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas            runInMillis = 1000;
4149096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        }
4159096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        handler.removeCallbacks(runnable);
4169096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        handler.postDelayed(runnable, runInMillis);
4179096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    }
4189096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas
4199096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    // Stop the quarter-hour update thread
4209096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas    public static void cancelQuarterHourUpdater(Handler handler, Runnable runnable) {
4219096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        if (handler == null || runnable == null) {
4229096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas            return;
4239096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        }
4249096dcec19f88883933e74b2d446eb94e6196089Robyn Coultas        handler.removeCallbacks(runnable);
425eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas    }
426eb3a1f0714e209a8335d84142778465aa6b44c5cRobyn Coultas
42778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /**
42878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     * For screensavers to set whether the digital or analog clock should be displayed.
42978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     * Returns the view to be displayed.
43078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     */
43178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    public static View setClockStyle(Context context, View digitalClock, View analogClock,
43278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            String clockStyleKey) {
43378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
43478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        String defaultClockStyle = context.getResources().getString(R.string.default_clock_style);
43578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        String style = sharedPref.getString(clockStyleKey, defaultClockStyle);
43678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        View returnView;
43778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        if (style.equals(CLOCK_TYPE_ANALOG)) {
43878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            digitalClock.setVisibility(View.GONE);
43978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            analogClock.setVisibility(View.VISIBLE);
44078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            returnView = analogClock;
44178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        } else {
44278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            digitalClock.setVisibility(View.VISIBLE);
44378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            analogClock.setVisibility(View.GONE);
44478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            returnView = digitalClock;
44578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
44678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
44778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        return returnView;
44878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
44978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
45078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /**
45178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     * For screensavers to dim the lights if necessary.
45278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein     */
45378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    public static void dimClockView(boolean dim, View clockView) {
45478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        Paint paint = new Paint();
45578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        paint.setColor(Color.WHITE);
45678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        paint.setColorFilter(new PorterDuffColorFilter(
457e8709b46a14defe610515a1a4c4fefa32ec9b044Isaac Katzenelson                        (dim ? 0x40FFFFFF : 0xC0FFFFFF),
45878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                PorterDuff.Mode.MULTIPLY));
45978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        clockView.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
46078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
46178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
462c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos    /**
463c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos     * @return The next alarm from {@link AlarmManager}
464c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos     */
465c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos    public static String getNextAlarm(Context context) {
466c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos        String timeString = null;
467a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro        final AlarmManager.AlarmClockInfo info = ((AlarmManager) context.getSystemService(
468a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro                Context.ALARM_SERVICE)).getNextAlarmClock();
469a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro        if (info != null) {
470a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro            final long triggerTime = info.getTriggerTime();
471a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro            final Calendar alarmTime = Calendar.getInstance();
472a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro            alarmTime.setTimeInMillis(triggerTime);
473a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro            timeString = AlarmUtils.getFormattedTime(context, alarmTime);
474a855a071a5cf2c1252389c0d650eba25f7b0be5fBudi Kusmiantoro        }
475c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos        return timeString;
476c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos    }
477c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos
47878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /** Clock views can call this to refresh their alarm to the next upcoming value. **/
479b41f177aef12a5aa5ec43057535f5deacf98a881Isaac Katzenelson    public static void refreshAlarm(Context context, View clock) {
480c0743272ad924bc97d335d695be3e6b32a83dd7dAdrian Roos        final String nextAlarm = getNextAlarm(context);
48178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        TextView nextAlarmView;
482b41f177aef12a5aa5ec43057535f5deacf98a881Isaac Katzenelson        nextAlarmView = (TextView) clock.findViewById(R.id.nextAlarm);
48378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        if (!TextUtils.isEmpty(nextAlarm) && nextAlarmView != null) {
48478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            nextAlarmView.setText(
48578b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    context.getString(R.string.control_set_alarm_with_existing, nextAlarm));
48678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            nextAlarmView.setContentDescription(context.getResources().getString(
48778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein                    R.string.next_alarm_description, nextAlarm));
48878b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            nextAlarmView.setVisibility(View.VISIBLE);
48978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        } else  {
49078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            nextAlarmView.setVisibility(View.GONE);
49178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
49278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
49378b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
49478b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    /** Clock views can call this to refresh their date. **/
495b41f177aef12a5aa5ec43057535f5deacf98a881Isaac Katzenelson    public static void updateDate(
496b41f177aef12a5aa5ec43057535f5deacf98a881Isaac Katzenelson            String dateFormat, String dateFormatForAccessibility, View clock) {
49778b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
49835300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson        Date now = new Date();
49978b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        TextView dateDisplay;
500b41f177aef12a5aa5ec43057535f5deacf98a881Isaac Katzenelson        dateDisplay = (TextView) clock.findViewById(R.id.date);
50178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        if (dateDisplay != null) {
50235300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            final Locale l = Locale.getDefault();
50335300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            String fmt = DateFormat.getBestDateTimePattern(l, dateFormat);
50435300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            SimpleDateFormat sdf = new SimpleDateFormat(fmt, l);
50535300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            dateDisplay.setText(sdf.format(now));
50678b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein            dateDisplay.setVisibility(View.VISIBLE);
50735300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            fmt = DateFormat.getBestDateTimePattern(l, dateFormatForAccessibility);
50835300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            sdf = new SimpleDateFormat(fmt, l);
50935300f84cef68e7f5666ec88591496aaaad242d1Isaac Katzenelson            dateDisplay.setContentDescription(sdf.format(now));
51078b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein        }
51178b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein    }
51278b8e1513e24c58ffea6ee4edbebdce85c248f6fSam Blitzstein
513690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson    /***
5143a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson     * Formats the time in the TextClock according to the Locale with a special
515690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson     * formatting treatment for the am/pm label.
516690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson     * @param clock - TextClock to format
5173a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson     * @param amPmFontSize - size of the am/pm label since it is usually smaller
5183a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson     *        than the clock time size.
519690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson     */
520690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson    public static void setTimeFormat(TextClock clock, int amPmFontSize) {
521690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson        if (clock != null) {
5223a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson            // Get the best format for 12 hours mode according to the locale
5238b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson            clock.setFormat12Hour(get12ModeFormat(amPmFontSize));
5243a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson            // Get the best format for 24 hours mode according to the locale
5258b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson            clock.setFormat24Hour(get24ModeFormat());
526690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson        }
527690f451a6aea35d944cb2eaddf488d3acf377184Isaac Katzenelson    }
5288b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson    /***
5298b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson     * @param amPmFontSize - size of am/pm label (label removed is size is 0).
5308b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson     * @return format string for 12 hours mode time
5318b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson     */
5328b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson    public static CharSequence get12ModeFormat(int amPmFontSize) {
53336ac292d66cf5b5a5776460cc9800be792e10adfIsaac Katzenelson        String skeleton = "hma";
5343a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
53536ac292d66cf5b5a5776460cc9800be792e10adfIsaac Katzenelson        // Remove the am/pm
53636ac292d66cf5b5a5776460cc9800be792e10adfIsaac Katzenelson        if (amPmFontSize <= 0) {
53736ac292d66cf5b5a5776460cc9800be792e10adfIsaac Katzenelson            pattern.replaceAll("a", "").trim();
53836ac292d66cf5b5a5776460cc9800be792e10adfIsaac Katzenelson        }
5393a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        // Replace spaces with "Hair Space"
5403a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        pattern = pattern.replaceAll(" ", "\u200A");
5413a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        // Build a spannable so that the am/pm will be formatted
5423a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        int amPmPos = pattern.indexOf('a');
5433a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        if (amPmPos == -1) {
5443a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson            return pattern;
5453a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        }
5463a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        Spannable sp = new SpannableString(pattern);
54780eafdf26fc496ffa112b9eb1b44d7b80333c80arachelzhang        sp.setSpan(new StyleSpan(Typeface.NORMAL), amPmPos, amPmPos + 1,
5483a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson                Spannable.SPAN_POINT_MARK);
5493a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        sp.setSpan(new AbsoluteSizeSpan(amPmFontSize), amPmPos, amPmPos + 1,
5503a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson                Spannable.SPAN_POINT_MARK);
55180eafdf26fc496ffa112b9eb1b44d7b80333c80arachelzhang        sp.setSpan(new TypefaceSpan("sans-serif"), amPmPos, amPmPos + 1,
5523a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson                Spannable.SPAN_POINT_MARK);
5533a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        return sp;
5543a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson    }
5553a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson
5568b8542c44a744b7afc5c9af34bbfec924e13a963Isaac Katzenelson    public static CharSequence get24ModeFormat() {
5573a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        String skeleton = "Hm";
5583a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson        return DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
5593a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson    }
5603a4ba0db218b830af3dd17fde2952125a2e50fdcIsaac Katzenelson
56162b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung    public static CityObj[] loadCitiesFromXml(Context c) {
562d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson        Resources r = c.getResources();
563d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson        // Read strings array of name,timezone, id
564d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson        // make sure the list are the same length
565d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        String[] cities = r.getStringArray(R.array.cities_names);
566d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        String[] timezones = r.getStringArray(R.array.cities_tz);
567d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        String[] ids = r.getStringArray(R.array.cities_id);
56825ca0e1b5e70386b30171d8aba8810593baffecbIsaac Katzenelson        int minLength = cities.length;
569d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson        if (cities.length != timezones.length || ids.length != cities.length) {
57025ca0e1b5e70386b30171d8aba8810593baffecbIsaac Katzenelson            minLength = Math.min(cities.length, Math.min(timezones.length, ids.length));
571cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen            LogUtils.e("City lists sizes are not the same, truncating");
572d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        }
57325ca0e1b5e70386b30171d8aba8810593baffecbIsaac Katzenelson        CityObj[] tempList = new CityObj[minLength];
574d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        for (int i = 0; i < cities.length; i++) {
575d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson            tempList[i] = new CityObj(cities[i], timezones[i], ids[i]);
576d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        }
577d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson        return tempList;
578d4bbc122b90c63c5906ad32c4652b72c9409fd44Isaac Katzenelson    }
579d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson
58062b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung    /**
58162b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung     * Returns string denoting the timezone hour offset (e.g. GMT-8:00)
58262b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung     */
58362b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung    public static String getGMTHourOffset(TimeZone timezone, boolean showMinutes) {
58462b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        StringBuilder sb = new StringBuilder();
58557cb1dbcead54ff08e8f07e727d0b1c842301440rachelzhang        sb.append("GMT  ");
58662b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        int gmtOffset = timezone.getRawOffset();
58762b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        if (gmtOffset < 0) {
58862b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            sb.append('-');
58962b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        } else {
59062b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            sb.append('+');
59162b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        }
59262b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        sb.append(Math.abs(gmtOffset) / DateUtils.HOUR_IN_MILLIS); // Hour
59362b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung
59462b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        if (showMinutes) {
59562b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            final int min = (Math.abs(gmtOffset) / (int) DateUtils.MINUTE_IN_MILLIS) % 60;
59662b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            sb.append(':');
59762b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            if (min < 10) {
59862b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung                sb.append('0');
59962b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            }
60062b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung            sb.append(min);
60162b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        }
60262b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung
60362b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung        return sb.toString();
60462b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung    }
60562b9f3d89a2be17f70d2fe45c1c94f732e0224a4James Kung
606d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson    public static String getCityName(CityObj city, CityObj dbCity) {
607d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson        return (city.mCityId == null || dbCity == null) ? city.mCityName : dbCity.mCityName;
608d851e8a4b134028bd12f509312d31664e4c826ddIsaac Katzenelson    }
609d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang
610d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    public static int getCurrentHourColor() {
611d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        final int hourOfDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
612d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        return Color.parseColor(BACKGROUND_SPECTRUM[hourOfDay]);
613d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    }
614419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang
6153f98d14fd4a98ffb90b7babc10e63218f9a43b2brachelzhang    public static int getNextHourColor() {
6163f98d14fd4a98ffb90b7babc10e63218f9a43b2brachelzhang        final int currHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
6173f98d14fd4a98ffb90b7babc10e63218f9a43b2brachelzhang        return Color.parseColor(BACKGROUND_SPECTRUM[currHour < 24 ? currHour + 1 : 1]);
6183f98d14fd4a98ffb90b7babc10e63218f9a43b2brachelzhang    }
6193f98d14fd4a98ffb90b7babc10e63218f9a43b2brachelzhang
620419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang    /**
621419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang     * To get an array of single-character day of week symbols {'S', 'M', 'T', 'W', 'T', 'F', 'S'}
622419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang     * @return the array of symbols
623419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang     */
624419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang    public static String[] getShortWeekdays() {
625419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang        if (sShortWeekdays == null) {
626419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            final String[] shortWeekdays = new String[7];
627419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            final SimpleDateFormat format = new SimpleDateFormat("EEEEE");
628419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            // Create a date (2014/07/20) that is a Sunday
629419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            long aSunday = new GregorianCalendar(2014, Calendar.JULY, 20).getTimeInMillis();
630419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            for (int day = 0; day < 7; day++) {
631419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang                shortWeekdays[day] = format.format(new Date(aSunday + day * DateUtils.DAY_IN_MILLIS));
632419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            }
633419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang            sShortWeekdays = shortWeekdays;
634419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang        }
635419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang        return sShortWeekdays;
636419659ca21953a0cd3bbc3e9f481b5c69ff519cbrachelzhang    }
637d2f8c51aba02f5e8cbbf82234ff453f305fba759Isaac Katzenelson}
638