1f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler/*
2f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * Copyright (C) 2009 The Android Open Source Project
3f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler *
4f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
5f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * you may not use this file except in compliance with the License.
6f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * You may obtain a copy of the License at
7f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler *
8f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
9f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler *
10f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * Unless required by applicable law or agreed to in writing, software
11f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
12f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * See the License for the specific language governing permissions and
14f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler * limitations under the License.
15f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler */
16f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
17f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerpackage com.android.deskclock;
18f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
19d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhangimport android.animation.ArgbEvaluator;
20d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhangimport android.animation.ObjectAnimator;
2163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.ActionBar;
2263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.ActionBar.Tab;
23f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerimport android.app.Activity;
2463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.Fragment;
250548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelsonimport android.app.FragmentManager;
2663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.FragmentTransaction;
27fc177987092f72f84f0833f80600d4bbf20d0b87Isaac Katzenelsonimport android.content.ActivityNotFoundException;
28f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerimport android.content.Context;
29f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerimport android.content.Intent;
30551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelsonimport android.content.SharedPreferences;
313bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzsteinimport android.content.res.Configuration;
325520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhangimport android.graphics.Outline;
33f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerimport android.os.Bundle;
34d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhangimport android.os.Handler;
35551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelsonimport android.preference.PreferenceManager;
36a80f15ded8c0be8bf2268bc4cf7b0ce125b07d1bIsaac Katzenelsonimport android.support.v13.app.FragmentPagerAdapter;
3763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.support.v4.view.ViewPager;
38a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelsonimport android.text.TextUtils;
39d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhangimport android.text.format.DateUtils;
4072a353a7d443f17a0e16412ae85ad359d97e9394Daniel Sandlerimport android.util.Log;
416fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelsonimport android.view.Menu;
42f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandlerimport android.view.MenuItem;
43357497c341662c56945e22e458852f52a977efdfSam Blitzsteinimport android.view.MotionEvent;
442763ab4cb6ee8d186eb8894ad006f699bfca3413Daniel Sandlerimport android.view.View;
455520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhangimport android.view.View.OnClickListener;
46357497c341662c56945e22e458852f52a977efdfSam Blitzsteinimport android.view.View.OnTouchListener;
475520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhangimport android.view.ViewOutlineProvider;
485520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhangimport android.widget.ImageButton;
490f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzsteinimport android.widget.TextView;
5063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson
51eddf7797cab8ca51a45dd66908654267fcf6fe18Paul Sliwowskiimport com.android.deskclock.alarms.AlarmStateManager;
528c1fcf3490a0d92448c460193c8824dbcd6790fdPaul Sliwowskiimport com.android.deskclock.provider.Alarm;
53113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzsteinimport com.android.deskclock.stopwatch.StopwatchFragment;
54113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzsteinimport com.android.deskclock.stopwatch.StopwatchService;
55113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzsteinimport com.android.deskclock.stopwatch.Stopwatches;
5663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport com.android.deskclock.timer.TimerFragment;
570f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzsteinimport com.android.deskclock.timer.TimerObj;
581ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelsonimport com.android.deskclock.timer.Timers;
59f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
6063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport java.util.ArrayList;
610548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelsonimport java.util.HashSet;
62a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelsonimport java.util.Locale;
63551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelsonimport java.util.TimeZone;
64f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
65f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler/**
667dd2d1f5fb1de58c8aef5bc102d21627924295cfDaniel Sandler * DeskClock clock view for desk docks.
67f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler */
683bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzsteinpublic class DeskClock extends Activity implements LabelDialogFragment.TimerLabelDialogHandler,
69d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        LabelDialogFragment.AlarmLabelDialogHandler {
70e6cf24dbbea56d8b88a8d48bed9d3a6f26c2ddf0Daniel Sandler    private static final boolean DEBUG = false;
7172a353a7d443f17a0e16412ae85ad359d97e9394Daniel Sandler    private static final String LOG_TAG = "DeskClock";
729463551d754302e158b80357d9c5c88517fe6e58Daniel Sandler    // Alarm action for midnight (so we can update the date display).
7363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private static final String KEY_SELECTED_TAB = "selected_tab";
746c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    private static final String KEY_LAST_HOUR_COLOR = "last_hour_color";
75d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    // Check whether to change background every minute
76d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    private static final long BACKGROUND_COLOR_CHECK_DELAY_MILLIS = DateUtils.MINUTE_IN_MILLIS;
776c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    private static final int BACKGROUND_COLOR_INITIAL_ANIMATION_DURATION_MILLIS = 3000;
785520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    // The depth of fab, use it to create shadow
795520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    private static final float FAB_DEPTH = 20f;
806c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    private static final int UNKNOWN_COLOR_ID = 0;
8151eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson
82d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    private boolean mIsFirstLaunch = true;
8363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private ActionBar mActionBar;
843bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    private Tab mAlarmTab;
8563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private Tab mClockTab;
863bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    private Tab mTimerTab;
8763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private Tab mStopwatchTab;
883bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    private Menu mMenu;
8951eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson    private ViewPager mViewPager;
9051eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson    private TabsAdapter mTabsAdapter;
91d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    private Handler mHander;
92d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    private ImageButton mFab;
93d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    private ImageButton mLeftButton;
94d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    private ImageButton mRightButton;
95d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    private int mSelectedTab;
966c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    private int mLastHourColor = UNKNOWN_COLOR_ID;
97d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    private final Runnable mBackgroundColorChanger = new Runnable() {
98d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        @Override
99d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        public void run() {
1006c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            setBackgroundColor();
101d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mHander.postDelayed(this, BACKGROUND_COLOR_CHECK_DELAY_MILLIS);
102d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        }
103d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    };
104d5b02dee04b7011a2b6cb1086752c583dcc604e1Erik
1053bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int ALARM_TAB_INDEX = 0;
10651eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson    public static final int CLOCK_TAB_INDEX = 1;
1073bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int TIMER_TAB_INDEX = 2;
1083bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int STOPWATCH_TAB_INDEX = 3;
109a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelson    // Tabs indices are switched for right-to-left since there is no
110a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelson    // native support for RTL in the ViewPager.
1113bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int RTL_ALARM_TAB_INDEX = 3;
1123bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int RTL_CLOCK_TAB_INDEX = 2;
1133bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public static final int RTL_TIMER_TAB_INDEX = 1;
114a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelson    public static final int RTL_STOPWATCH_TAB_INDEX = 0;
115d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    public static final String SELECT_TAB_INTENT_EXTRA = "deskclock.select.tab";
1167dd2d1f5fb1de58c8aef5bc102d21627924295cfDaniel Sandler
117d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    // TODO(rachelzhang): adding a broadcast receiver to adjust color when the timezone/time
118d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    // changes in the background.
119d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang
120d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    @Override
121d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    protected void onStart() {
122d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        super.onStart();
123d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        if (mHander == null) {
124d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mHander = new Handler();
125d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        }
126d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        mHander.postDelayed(mBackgroundColorChanger, BACKGROUND_COLOR_CHECK_DELAY_MILLIS);
127d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    }
128d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang
129d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    @Override
130d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    protected void onStop() {
131d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        super.onStop();
132d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        mHander.removeCallbacks(mBackgroundColorChanger);
133d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    }
1340a267d0f1c1e18e0f208b60a81bf2f73457a2c56Daniel Sandler
13563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    @Override
13663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    public void onNewIntent(Intent newIntent) {
13763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        super.onNewIntent(newIntent);
13863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent);
1397fc983026decebf7940b9512116bdbff015fadf0Dmitri Plotnikov
14063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        // update our intent so that we can consult it to determine whether or
14163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        // not the most recent launch was via a dock event
14263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        setIntent(newIntent);
14391522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
14451eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        // Timer receiver may ask to go to the timers fragment if a timer expired.
14551eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
14651eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        if (tab != -1) {
14751eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson            if (mActionBar != null) {
14851eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson                mActionBar.setSelectedNavigationItem(tab);
14951eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson            }
15051eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        }
15151eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson    }
15291522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
1535520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    private static final ViewOutlineProvider OVAL_OUTLINE_PROVIDER = new ViewOutlineProvider() {
1545520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        @Override
1555520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        public void getOutline(View view, Outline outline) {
1565520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            outline.setOval(0, 0, view.getWidth(), view.getHeight());
1575520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        }
1585520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    };
1595520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang
16063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private void initViews() {
1615520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        setContentView(R.layout.desk_clock);
1625520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        mFab = (ImageButton) findViewById(R.id.fab);
1635520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        mFab.setOutlineProvider(OVAL_OUTLINE_PROVIDER);
1645520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        mFab.setTranslationZ(FAB_DEPTH);
165d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        mLeftButton = (ImageButton) findViewById(R.id.left_button);
166d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        mRightButton = (ImageButton) findViewById(R.id.right_button);
16763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        if (mTabsAdapter == null) {
1685520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            mViewPager = (ViewPager) findViewById(R.id.desk_clock_pager);
1693bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            // Keep all four tabs to minimize jank.
1703bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mViewPager.setOffscreenPageLimit(3);
17163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mTabsAdapter = new TabsAdapter(this, mViewPager);
17263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            createTabs(mSelectedTab);
17391522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler        }
1745520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang
1755520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        mFab.setOnClickListener(new OnClickListener() {
1765520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            @Override
1775520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            public void onClick(View view) {
178d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                getSelectedFragment().onFabClick(view);
179d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            }
180d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        });
181d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        mLeftButton.setOnClickListener(new OnClickListener() {
182d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            @Override
183d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            public void onClick(View view) {
184d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                getSelectedFragment().onLeftButtonClick(view);
185d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            }
186d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        });
187d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        mRightButton.setOnClickListener(new OnClickListener() {
188d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            @Override
189d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            public void onClick(View view) {
190d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                getSelectedFragment().onRightButtonClick(view);
1915520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            }
1925520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        });
1935520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang
19463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        mActionBar.setSelectedNavigationItem(mSelectedTab);
19591522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler    }
19691522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
197d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    private DeskClockFragment getSelectedFragment() {
198d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        return (DeskClockFragment) mTabsAdapter.getItem(getRtlPosition(mSelectedTab));
199d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang    }
200d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang
20163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    private void createTabs(int selectedIndex) {
20263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        mActionBar = getActionBar();
20363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson
20463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        if (mActionBar != null) {
2053bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mActionBar.setDisplayOptions(0);
20663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
2073bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
2083bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mAlarmTab = mActionBar.newTab();
2093bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mAlarmTab.setIcon(R.drawable.alarm_tab);
2103bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mAlarmTab.setContentDescription(R.string.menu_alarm);
2113bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTabsAdapter.addTab(mAlarmTab, AlarmClockFragment.class, ALARM_TAB_INDEX);
212a80f15ded8c0be8bf2268bc4cf7b0ce125b07d1bIsaac Katzenelson
21363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mClockTab = mActionBar.newTab();
21463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mClockTab.setIcon(R.drawable.clock_tab);
21548a8e478723413bbc343a6429da821aa32f72844Yorke Lee            mClockTab.setContentDescription(R.string.menu_clock);
2163bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTabsAdapter.addTab(mClockTab, ClockFragment.class, CLOCK_TAB_INDEX);
2173bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
2183bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTimerTab = mActionBar.newTab();
2193bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTimerTab.setIcon(R.drawable.timer_tab);
2203bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTimerTab.setContentDescription(R.string.menu_timer);
2213bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            mTabsAdapter.addTab(mTimerTab, TimerFragment.class, TIMER_TAB_INDEX);
2223bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
22363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mStopwatchTab = mActionBar.newTab();
22463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mStopwatchTab.setIcon(R.drawable.stopwatch_tab);
22548a8e478723413bbc343a6429da821aa32f72844Yorke Lee            mStopwatchTab.setContentDescription(R.string.menu_stopwatch);
226d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class, STOPWATCH_TAB_INDEX);
2273bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
22863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mActionBar.setSelectedNavigationItem(selectedIndex);
2290548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            mTabsAdapter.notifySelectedPage(selectedIndex);
2302c5f0979c70f8e16916766540ed4c96cdd127aacDmitri Plotnikov        }
23180ff42c1abf87a4e81cb422446412973b46a75bdDaniel Sandler    }
23280ff42c1abf87a4e81cb422446412973b46a75bdDaniel Sandler
23363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    @Override
23463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    protected void onCreate(Bundle icicle) {
23563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        super.onCreate(icicle);
236c57490dff5bfbf601d4b708fdae029df99f807b2Daniel Sandler
237d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        mIsFirstLaunch = (icicle == null);
238117f6da3ed857877c24573cddd2bc2260b73e370Budi Kusmiantoro        getWindow().setBackgroundDrawable(null);
239117f6da3ed857877c24573cddd2bc2260b73e370Budi Kusmiantoro
24040bf69f36896140231b260827d96e9f4aaa6aa3fBudi Kusmiantoro        mIsFirstLaunch = true;
24163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        mSelectedTab = CLOCK_TAB_INDEX;
24263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        if (icicle != null) {
24363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX);
2446c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            mLastHourColor = icicle.getInt(KEY_LAST_HOUR_COLOR, UNKNOWN_COLOR_ID);
2456c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            if (mLastHourColor != UNKNOWN_COLOR_ID) {
2466c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro                getWindow().getDecorView().setBackgroundColor(mLastHourColor);
2476c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            }
24863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
24951eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson
25051eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        // Timer receiver may ask the app to go to the timer fragment if a timer expired
25151eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        Intent i = getIntent();
25251eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        if (i != null) {
25351eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson            int tab = i.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
25451eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson            if (tab != -1) {
25551eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson                mSelectedTab = tab;
25651eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson            }
25751eb2d54650a3600ce68e942f8a7fe37aa731f9eIsaac Katzenelson        }
25891522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler        initViews();
259551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        setHomeTimeZone();
260eddf7797cab8ca51a45dd66908654267fcf6fe18Paul Sliwowski
261eddf7797cab8ca51a45dd66908654267fcf6fe18Paul Sliwowski        // We need to update the system next alarm time on app startup because the
262eddf7797cab8ca51a45dd66908654267fcf6fe18Paul Sliwowski        // user might have clear our data.
263eddf7797cab8ca51a45dd66908654267fcf6fe18Paul Sliwowski        AlarmStateManager.updateNextAlarm(this);
26411c38e64f05bbcfa4503edb1680f255946ff6350Florian Salbrechter        ExtensionsFactory.init(getAssets());
26591522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler    }
26691522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
26763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    @Override
26863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    protected void onResume() {
26963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        super.onResume();
270357497c341662c56945e22e458852f52a977efdfSam Blitzstein
2716c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        setBackgroundColor();
2721728d0db16048b188d37a5299c090480e946a33aBudi Kusmiantoro
2733bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // We only want to show notifications for stopwatch/timer when the app is closed so
2743bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // that we don't have to worry about keeping the notifications in perfect sync with
2753bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // the app.
2761ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        Intent stopwatchIntent = new Intent(getApplicationContext(), StopwatchService.class);
2771ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        stopwatchIntent.setAction(Stopwatches.KILL_NOTIF);
2781ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        startService(stopwatchIntent);
2791ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson
2801ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
2811ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        SharedPreferences.Editor editor = prefs.edit();
2821ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        editor.putBoolean(Timers.NOTIF_APP_OPEN, true);
2831ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        editor.apply();
2841ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        Intent timerIntent = new Intent();
2851ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        timerIntent.setAction(Timers.NOTIF_IN_USE_CANCEL);
2861ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        sendBroadcast(timerIntent);
28763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    }
28891522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
28963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    @Override
29063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    public void onPause() {
291113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzstein        Intent intent = new Intent(getApplicationContext(), StopwatchService.class);
292113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzstein        intent.setAction(Stopwatches.SHOW_NOTIF);
293113e1daddd8cb0e890084aa4b6ea3194d8ad4826Sam Blitzstein        startService(intent);
2941ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson
2951ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
2961ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        SharedPreferences.Editor editor = prefs.edit();
2971ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        editor.putBoolean(Timers.NOTIF_APP_OPEN, false);
2981ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson        editor.apply();
299feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas        Utils.showInUseNotifications(this);
3001ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson
30163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        super.onPause();
30291522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler    }
30391522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler
30491522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler    @Override
30563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson    protected void onSaveInstanceState(Bundle outState) {
30663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        super.onSaveInstanceState(outState);
30763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        outState.putInt(KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex());
3086c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        outState.putInt(KEY_LAST_HOUR_COLOR, mLastHourColor);
30991522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler    }
3102763ab4cb6ee8d186eb8894ad006f699bfca3413Daniel Sandler
3113bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    @Override
3123bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public boolean onCreateOptionsMenu(Menu menu) {
3133bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // We only want to show it as a menu in landscape, and only for clock/alarm fragment.
3143bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        mMenu = menu;
3156da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
3166da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            if (mActionBar.getSelectedNavigationIndex() == ALARM_TAB_INDEX ||
3176da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                    mActionBar.getSelectedNavigationIndex() == CLOCK_TAB_INDEX) {
3186da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                // Clear the menu so that it doesn't get duplicate items in case onCreateOptionsMenu
3196da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                // was called multiple times.
3206da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                menu.clear();
3216da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                getMenuInflater().inflate(R.menu.desk_clock_menu, menu);
3226da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            }
3236da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            // Always return true for landscape, regardless of whether we've inflated the menu, so
3246da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            // that when we switch tabs this method will get called and we can inflate the menu.
3253bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            return true;
3263bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        }
3276da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein        return false;
3283bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    }
3293bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
3303bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    @Override
3313bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public boolean onPrepareOptionsMenu(Menu menu) {
3323bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        updateMenu(menu);
3333bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        return true;
3343bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    }
3356fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelson
3363bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    private void updateMenu(Menu menu) {
3373bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // Hide "help" if we don't have a URI for it.
3386fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelson        MenuItem help = menu.findItem(R.id.menu_item_help);
3396fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelson        if (help != null) {
3406fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelson            Utils.prepareHelpMenuItem(this, help);
3416fc34de781d8fece646b16dc289bbf4c0b01fde4Isaac Katzenelson        }
3423bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
3433bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        // Hide "lights out" for timer.
3443bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        MenuItem nightMode = menu.findItem(R.id.menu_item_night_mode);
3453bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        if (mActionBar.getSelectedNavigationIndex() == ALARM_TAB_INDEX) {
3463bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            nightMode.setVisible(false);
3473bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        } else if (mActionBar.getSelectedNavigationIndex() == CLOCK_TAB_INDEX) {
3483bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            nightMode.setVisible(true);
3493bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        }
3503bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    }
3513bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
3523bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    @Override
3533bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public boolean onOptionsItemSelected(MenuItem item) {
3543bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        if (processMenuClick(item)) {
3553bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            return true;
3563bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        }
3573bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
3583bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        return super.onOptionsItemSelected(item);
3593bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    }
3603bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
3613bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    private boolean processMenuClick(MenuItem item) {
3623bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        switch (item.getItemId()) {
3633bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            case R.id.menu_item_settings:
3643bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                startActivity(new Intent(DeskClock.this, SettingsActivity.class));
3653bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                return true;
3663bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            case R.id.menu_item_help:
3673bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                Intent i = item.getIntent();
3683bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                if (i != null) {
3693bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                    try {
3703bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                        startActivity(i);
3713bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                    } catch (ActivityNotFoundException e) {
3723bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                        // No activity found to match the intent - ignore
3733bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                    }
3743bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                }
3753bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                return true;
3763bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            case R.id.menu_item_night_mode:
3773bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                startActivity(new Intent(DeskClock.this, ScreensaverActivity.class));
3783bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            default:
3793bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                break;
3803bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        }
3813bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        return true;
382ef18177f9bbbeab8ef266c3f080175bc813dc34cDaniel Sandler    }
383ef18177f9bbbeab8ef266c3f080175bc813dc34cDaniel Sandler
384d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    /**
385551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson     * Insert the local time zone as the Home Time Zone if one is not set
386551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson     */
387551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson    private void setHomeTimeZone() {
388551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
389551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        String homeTimeZone = prefs.getString(SettingsActivity.KEY_HOME_TZ, "");
390551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        if (!homeTimeZone.isEmpty()) {
3913bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            return;
392551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        }
393551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        homeTimeZone = TimeZone.getDefault().getID();
394551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        SharedPreferences.Editor editor = prefs.edit();
395551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        editor.putString(SettingsActivity.KEY_HOME_TZ, homeTimeZone);
396551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        editor.apply();
397551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson        Log.v(LOG_TAG, "Setting home time zone to " + homeTimeZone);
398551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson    }
399551a5c3b016d5f9273fb940c3849bc3560c2694aItzhak Katzenelson
4000548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson    public void registerPageChangedListener(DeskClockFragment frag) {
4010548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        if (mTabsAdapter != null) {
4020548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            mTabsAdapter.registerPageChangedListener(frag);
4030548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
4040548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson    }
4050548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
4060548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson    public void unregisterPageChangedListener(DeskClockFragment frag) {
4070548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        if (mTabsAdapter != null) {
4080548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            mTabsAdapter.unregisterPageChangedListener(frag);
4090548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
4100f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein    }
4110f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein
4126c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    private void setBackgroundColor() {
4136c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        final int duration;
4146c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        if (mLastHourColor == UNKNOWN_COLOR_ID) {
4156c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            mLastHourColor = getResources().getColor(R.color.default_background);
4166c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            duration = BACKGROUND_COLOR_INITIAL_ANIMATION_DURATION_MILLIS;
4176c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        } else {
4186c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            duration = getResources().getInteger(android.R.integer.config_longAnimTime);
4196c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        }
4206c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        final int currHourColor = Utils.getCurrentHourColor();
4216c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        if (mLastHourColor != currHourColor) {
4226c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            final ObjectAnimator animator = ObjectAnimator.ofInt(getWindow().getDecorView(),
4236c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro                    "backgroundColor", mLastHourColor, currHourColor);
4246c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            animator.setDuration(duration);
4256c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            animator.setEvaluator(new ArgbEvaluator());
4266c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            animator.start();
4276c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro            mLastHourColor = currHourColor;
4286c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro        }
4296c79f55cc2280fa6fe1774a828554589fa07241eBudi Kusmiantoro    }
4300548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
431d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    /**
43263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson     * Adapter for wrapping together the ActionBar's tab with the ViewPager
43363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson     */
434a80f15ded8c0be8bf2268bc4cf7b0ce125b07d1bIsaac Katzenelson    private class TabsAdapter extends FragmentPagerAdapter
43563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
4360a267d0f1c1e18e0f208b60a81bf2f73457a2c56Daniel Sandler
43763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        private static final String KEY_TAB_POSITION = "tab_position";
4380a267d0f1c1e18e0f208b60a81bf2f73457a2c56Daniel Sandler
43963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        final class TabInfo {
44063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            private final Class<?> clss;
44163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            private final Bundle args;
4420a267d0f1c1e18e0f208b60a81bf2f73457a2c56Daniel Sandler
44363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            TabInfo(Class<?> _class, int position) {
44463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson                clss = _class;
44563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson                args = new Bundle();
44663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson                args.putInt(KEY_TAB_POSITION, position);
44763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            }
448ef18177f9bbbeab8ef266c3f080175bc813dc34cDaniel Sandler
44963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            public int getPosition() {
45063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson                return args.getInt(KEY_TAB_POSITION, 0);
45163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            }
45263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
453e6cf24dbbea56d8b88a8d48bed9d3a6f26c2ddf0Daniel Sandler
454d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
45563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        ActionBar mMainActionBar;
45663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        Context mContext;
45763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        ViewPager mPager;
4580548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        // Used for doing callbacks to fragments.
4590548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        HashSet<String> mFragmentTags = new HashSet<String>();
46063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson
46163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public TabsAdapter(Activity activity, ViewPager pager) {
46263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            super(activity.getFragmentManager());
46363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mContext = activity;
46463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mMainActionBar = activity.getActionBar();
46563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mPager = pager;
46663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mPager.setAdapter(this);
46763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mPager.setOnPageChangeListener(this);
46863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
469f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
47063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
47163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public Fragment getItem(int position) {
4725520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            // Because this public method is called outside many times,
4735520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            // check if it exits first before creating a new one.
4745520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            final String name = makeFragmentName(R.id.desk_clock_pager, position);
4755520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            Fragment fragment = getFragmentManager().findFragmentByTag(name);
4765520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            if (fragment == null) {
4775520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang                TabInfo info = mTabs.get(getRtlPosition(position));
4785520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang                fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
479d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                if (fragment instanceof TimerFragment) {
4805e469aa155baea98f09d5d5e657aa2315a76679drachelzhang                    ((TimerFragment) fragment).setFabAppearance();
4815e469aa155baea98f09d5d5e657aa2315a76679drachelzhang                    ((TimerFragment) fragment).setLeftRightButtonAppearance();
482d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                }
4835520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            }
4845520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            return fragment;
4855520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        }
4865520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang
4875520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        /**
4885520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang         * Copied from:
4895520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang         * android/frameworks/support/v13/java/android/support/v13/app/FragmentPagerAdapter.java#94
4905520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang         * Create unique name for the fragment so fragment manager knows it exist.
4915520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang         */
4925520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        private String makeFragmentName(int viewId, int index) {
4935520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            return "android:switcher:" + viewId + ":" + index;
49463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
495f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
49663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
49763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public int getCount() {
49863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            return mTabs.size();
49963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
500b95b7a63c403a17c3725e1ccfbd65b4283fd6a0fDaniel Sandler
50163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void addTab(ActionBar.Tab tab, Class<?> clss, int position) {
50263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            TabInfo info = new TabInfo(clss, position);
50363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            tab.setTag(info);
50463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            tab.setTabListener(this);
50563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mTabs.add(info);
50663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            mMainActionBar.addTab(tab);
50763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            notifyDataSetChanged();
50863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
509b95b7a63c403a17c3725e1ccfbd65b4283fd6a0fDaniel Sandler
51063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
51163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
5127bcc2d8ce2951a8f5451e93a5192b7ae04564de0Sam Blitzstein            // Do nothing
51363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
514f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler
51563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
51663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onPageSelected(int position) {
5176da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            // Set the page before doing the menu so that onCreateOptionsMenu knows what page it is.
5186da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            mMainActionBar.setSelectedNavigationItem(getRtlPosition(position));
5196da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein            notifyPageChanged(position);
5206da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein
5213bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            // Only show the overflow menu for alarm and world clock.
5223bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            if (mMenu != null) {
5233bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                // Make sure the menu's been initialized.
5243bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                if (position == ALARM_TAB_INDEX || position == CLOCK_TAB_INDEX) {
5253bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                    mMenu.setGroupVisible(R.id.menu_items, true);
5266da4068d34ede187e9237c54ab70681755995e48Sam Blitzstein                    onCreateOptionsMenu(mMenu);
5273bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                } else {
5283bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                    mMenu.setGroupVisible(R.id.menu_items, false);
5293bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein                }
5303bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            }
53163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
532d13733225cb1a3e16413b35336e94e400bf5d399Daniel Sandler
53363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
53463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onPageScrollStateChanged(int state) {
53563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            // Do nothing
53691522cd49090f40e2e5b96c9b2e310b1adf1218aDaniel Sandler        }
537d13733225cb1a3e16413b35336e94e400bf5d399Daniel Sandler
53863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
53963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
54063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            // Do nothing
5417dd2d1f5fb1de58c8aef5bc102d21627924295cfDaniel Sandler        }
5427dd2d1f5fb1de58c8aef5bc102d21627924295cfDaniel Sandler
54363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
54463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onTabSelected(Tab tab, FragmentTransaction ft) {
5455e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            final TabInfo info = (TabInfo) tab.getTag();
5465e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            final int position = info.getPosition();
5475e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            final int rtlSafePosition = getRtlPosition(position);
5485520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            mSelectedTab = position;
5495e469aa155baea98f09d5d5e657aa2315a76679drachelzhang
5505e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            if (mIsFirstLaunch && isClockTab(rtlSafePosition)) {
551d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                mLeftButton.setVisibility(View.INVISIBLE);
552d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                mRightButton.setVisibility(View.INVISIBLE);
5535520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang                mFab.setVisibility(View.VISIBLE);
5545520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang                mFab.setImageResource(R.drawable.ic_globe);
55540bf69f36896140231b260827d96e9f4aaa6aa3fBudi Kusmiantoro                mFab.setContentDescription(getString(R.string.button_cities));
5565520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang                mIsFirstLaunch = false;
5575520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            } else {
5585e469aa155baea98f09d5d5e657aa2315a76679drachelzhang                DeskClockFragment f = (DeskClockFragment) getItem(rtlSafePosition);
5595e469aa155baea98f09d5d5e657aa2315a76679drachelzhang                f.setFabAppearance();
5605e469aa155baea98f09d5d5e657aa2315a76679drachelzhang                f.setLeftRightButtonAppearance();
5615520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang            }
5625e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            mPager.setCurrentItem(rtlSafePosition);
56363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
5647dd2d1f5fb1de58c8aef5bc102d21627924295cfDaniel Sandler
56563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        @Override
56663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
56763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson            // Do nothing
56863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson        }
5690548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
5705e469aa155baea98f09d5d5e657aa2315a76679drachelzhang        private boolean isClockTab(int rtlSafePosition) {
5715e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            final int clockTabIndex = isRtl() ? RTL_CLOCK_TAB_INDEX : CLOCK_TAB_INDEX;
5725e469aa155baea98f09d5d5e657aa2315a76679drachelzhang            return rtlSafePosition == clockTabIndex;
5735e469aa155baea98f09d5d5e657aa2315a76679drachelzhang        }
5745e469aa155baea98f09d5d5e657aa2315a76679drachelzhang
5750548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        public void notifySelectedPage(int page) {
5760548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            notifyPageChanged(page);
5770548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
5780548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
5790548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        private void notifyPageChanged(int newPage) {
5800548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            for (String tag : mFragmentTags) {
5810548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                final FragmentManager fm = getFragmentManager();
5820548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                DeskClockFragment f = (DeskClockFragment) fm.findFragmentByTag(tag);
5830548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                if (f != null) {
5840548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                    f.onPageChanged(newPage);
5850548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                }
5860548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            }
5870548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
5880548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
5890548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        public void registerPageChangedListener(DeskClockFragment frag) {
5900548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            String tag = frag.getTag();
5910548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            if (mFragmentTags.contains(tag)) {
5920548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                Log.wtf(LOG_TAG, "Trying to add an existing fragment " + tag);
5930548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            } else {
5940548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson                mFragmentTags.add(frag.getTag());
5950548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            }
5960548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            // Since registering a listener by the fragment is done sometimes after the page
5970548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            // was already changed, make sure the fragment gets the current page
5980548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            frag.onPageChanged(mMainActionBar.getSelectedNavigationIndex());
5990548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
6000548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson
6010548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        public void unregisterPageChangedListener(DeskClockFragment frag) {
6020548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson            mFragmentTags.remove(frag.getTag());
6030548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        }
604a662a90ae0659d8ddadde019b8bb3e2ffe2becc1Isaac Katzenelson
6057e77977037b89c775faa0a480c8ce70eb820dc20RoboErik    }
606357497c341662c56945e22e458852f52a977efdfSam Blitzstein
6077bcc2d8ce2951a8f5451e93a5192b7ae04564de0Sam Blitzstein    public static abstract class OnTapListener implements OnTouchListener {
608357497c341662c56945e22e458852f52a977efdfSam Blitzstein        private float mLastTouchX;
609357497c341662c56945e22e458852f52a977efdfSam Blitzstein        private float mLastTouchY;
610357497c341662c56945e22e458852f52a977efdfSam Blitzstein        private long mLastTouchTime;
6110548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        private final TextView mMakePressedTextView;
6120548712a944f298d0d785373056c83ad460fe5d0Isaac Katzenelson        private final int mPressedColor, mGrayColor;
6130f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        private final float MAX_MOVEMENT_ALLOWED = 20;
6140f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        private final long MAX_TIME_ALLOWED = 500;
615357497c341662c56945e22e458852f52a977efdfSam Blitzstein
6160f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        public OnTapListener(Activity activity, TextView makePressedView) {
6170f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            mMakePressedTextView = makePressedView;
6180f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            mPressedColor = activity.getResources().getColor(Utils.getPressedColorId());
6190f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            mGrayColor = activity.getResources().getColor(Utils.getGrayColorId());
6200f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        }
6210f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein
622357497c341662c56945e22e458852f52a977efdfSam Blitzstein        @Override
623357497c341662c56945e22e458852f52a977efdfSam Blitzstein        public boolean onTouch(View v, MotionEvent e) {
624357497c341662c56945e22e458852f52a977efdfSam Blitzstein            switch (e.getAction()) {
625357497c341662c56945e22e458852f52a977efdfSam Blitzstein                case (MotionEvent.ACTION_DOWN):
6260f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    mLastTouchTime = Utils.getTimeNow();
627357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    mLastTouchX = e.getX();
628357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    mLastTouchY = e.getY();
6290f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    if (mMakePressedTextView != null) {
6300f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                        mMakePressedTextView.setTextColor(mPressedColor);
6310f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    }
632357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    break;
633357497c341662c56945e22e458852f52a977efdfSam Blitzstein                case (MotionEvent.ACTION_UP):
634d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang                    float xDiff = Math.abs(e.getX() - mLastTouchX);
635d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang                    float yDiff = Math.abs(e.getY() - mLastTouchY);
636357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    long timeDiff = (Utils.getTimeNow() - mLastTouchTime);
637357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    if (xDiff < MAX_MOVEMENT_ALLOWED && yDiff < MAX_MOVEMENT_ALLOWED
638357497c341662c56945e22e458852f52a977efdfSam Blitzstein                            && timeDiff < MAX_TIME_ALLOWED) {
6390f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                        if (mMakePressedTextView != null) {
6400f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                            v = mMakePressedTextView;
6410f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                        }
6420f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                        processClick(v);
6437bcc2d8ce2951a8f5451e93a5192b7ae04564de0Sam Blitzstein                        resetValues();
644357497c341662c56945e22e458852f52a977efdfSam Blitzstein                        return true;
645357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    }
6460f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    resetValues();
647357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    break;
648357497c341662c56945e22e458852f52a977efdfSam Blitzstein                case (MotionEvent.ACTION_MOVE):
649d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang                    xDiff = Math.abs(e.getX() - mLastTouchX);
650d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang                    yDiff = Math.abs(e.getY() - mLastTouchY);
6510f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    if (xDiff >= MAX_MOVEMENT_ALLOWED || yDiff >= MAX_MOVEMENT_ALLOWED) {
6520f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                        resetValues();
6530f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                    }
654357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    break;
655357497c341662c56945e22e458852f52a977efdfSam Blitzstein                default:
656357497c341662c56945e22e458852f52a977efdfSam Blitzstein                    resetValues();
657357497c341662c56945e22e458852f52a977efdfSam Blitzstein            }
658357497c341662c56945e22e458852f52a977efdfSam Blitzstein            return false;
659357497c341662c56945e22e458852f52a977efdfSam Blitzstein        }
660357497c341662c56945e22e458852f52a977efdfSam Blitzstein
661357497c341662c56945e22e458852f52a977efdfSam Blitzstein        private void resetValues() {
662d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mLastTouchX = -1 * MAX_MOVEMENT_ALLOWED + 1;
663d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mLastTouchY = -1 * MAX_MOVEMENT_ALLOWED + 1;
664d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang            mLastTouchTime = -1 * MAX_TIME_ALLOWED + 1;
6650f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            if (mMakePressedTextView != null) {
6660f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein                mMakePressedTextView.setTextColor(mGrayColor);
6670f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            }
6680f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        }
6690f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein
6707bcc2d8ce2951a8f5451e93a5192b7ae04564de0Sam Blitzstein        protected abstract void processClick(View v);
671357497c341662c56945e22e458852f52a977efdfSam Blitzstein    }
672357497c341662c56945e22e458852f52a977efdfSam Blitzstein
673d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    /**
674d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang     * Called by the LabelDialogFormat class after the dialog is finished. *
675d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang     */
6760f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein    @Override
6770f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein    public void onDialogLabelSet(TimerObj timer, String label, String tag) {
6780f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        Fragment frag = getFragmentManager().findFragmentByTag(tag);
6790f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        if (frag instanceof TimerFragment) {
6800f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein            ((TimerFragment) frag).setLabel(timer, label);
6810f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein        }
6820f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein    }
6833bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein
684d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang    /**
685d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang     * Called by the LabelDialogFormat class after the dialog is finished. *
686d48339f270ba72bb8416fd194b4a0d1aeb3bd958rachelzhang     */
6873bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    @Override
6883bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    public void onDialogLabelSet(Alarm alarm, String label, String tag) {
6893bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        Fragment frag = getFragmentManager().findFragmentByTag(tag);
6903bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        if (frag instanceof AlarmClockFragment) {
6913bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein            ((AlarmClockFragment) frag).setLabel(alarm, label);
6923bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein        }
6933bc02950da8c14ec04199043f41a9ffc13290c8dSam Blitzstein    }
6945520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang
6955520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    public int getSelectedTab() {
6965520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang        return mSelectedTab;
6975520461495a8c4fb468aa94d7b18a3fc25d54739rachelzhang    }
69807acb5af9273863f2782c3a73632549604846c08rachelzhang
69907acb5af9273863f2782c3a73632549604846c08rachelzhang    private boolean isRtl() {
70007acb5af9273863f2782c3a73632549604846c08rachelzhang        return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) ==
70107acb5af9273863f2782c3a73632549604846c08rachelzhang                View.LAYOUT_DIRECTION_RTL;
70207acb5af9273863f2782c3a73632549604846c08rachelzhang    }
70307acb5af9273863f2782c3a73632549604846c08rachelzhang
70407acb5af9273863f2782c3a73632549604846c08rachelzhang    private int getRtlPosition(int position) {
70507acb5af9273863f2782c3a73632549604846c08rachelzhang        if (isRtl()) {
70607acb5af9273863f2782c3a73632549604846c08rachelzhang            switch (position) {
70707acb5af9273863f2782c3a73632549604846c08rachelzhang                case TIMER_TAB_INDEX:
70807acb5af9273863f2782c3a73632549604846c08rachelzhang                    return RTL_TIMER_TAB_INDEX;
70907acb5af9273863f2782c3a73632549604846c08rachelzhang                case CLOCK_TAB_INDEX:
71007acb5af9273863f2782c3a73632549604846c08rachelzhang                    return RTL_CLOCK_TAB_INDEX;
71107acb5af9273863f2782c3a73632549604846c08rachelzhang                case STOPWATCH_TAB_INDEX:
71207acb5af9273863f2782c3a73632549604846c08rachelzhang                    return RTL_STOPWATCH_TAB_INDEX;
71307acb5af9273863f2782c3a73632549604846c08rachelzhang                case ALARM_TAB_INDEX:
71407acb5af9273863f2782c3a73632549604846c08rachelzhang                    return RTL_ALARM_TAB_INDEX;
71507acb5af9273863f2782c3a73632549604846c08rachelzhang                default:
71607acb5af9273863f2782c3a73632549604846c08rachelzhang                    break;
71707acb5af9273863f2782c3a73632549604846c08rachelzhang            }
71807acb5af9273863f2782c3a73632549604846c08rachelzhang        }
71907acb5af9273863f2782c3a73632549604846c08rachelzhang        return position;
72007acb5af9273863f2782c3a73632549604846c08rachelzhang    }
7215e469aa155baea98f09d5d5e657aa2315a76679drachelzhang
7225e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    public ImageButton getFab() {
7235e469aa155baea98f09d5d5e657aa2315a76679drachelzhang        return mFab;
7245e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    }
7255e469aa155baea98f09d5d5e657aa2315a76679drachelzhang
7265e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    public ImageButton getLeftButton() {
7275e469aa155baea98f09d5d5e657aa2315a76679drachelzhang        return mLeftButton;
7285e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    }
7295e469aa155baea98f09d5d5e657aa2315a76679drachelzhang
7305e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    public ImageButton getRightButton() {
7315e469aa155baea98f09d5d5e657aa2315a76679drachelzhang        return mRightButton;
7325e469aa155baea98f09d5d5e657aa2315a76679drachelzhang    }
733f8317ad7146b1cdfeded7acb23ae8f770b2d3f97Daniel Sandler}
734