DeskClock.java revision feabb7a335fb8c7644783d2dca53b864009054d8
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.deskclock;
18
19import android.app.ActionBar;
20import android.app.ActionBar.Tab;
21import android.app.Activity;
22import android.app.Fragment;
23import android.app.FragmentTransaction;
24import android.content.ActivityNotFoundException;
25import android.content.Context;
26import android.content.Intent;
27import android.content.SharedPreferences;
28import android.graphics.drawable.TransitionDrawable;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Message;
32import android.preference.PreferenceManager;
33import android.support.v13.app.FragmentPagerAdapter;
34import android.support.v4.view.ViewPager;
35import android.util.Log;
36import android.view.Menu;
37import android.view.MenuItem;
38import android.view.MotionEvent;
39import android.view.View;
40import android.view.View.OnTouchListener;
41import android.view.animation.Animation;
42import android.view.animation.Animation.AnimationListener;
43import android.view.animation.AnimationUtils;
44import android.view.animation.TranslateAnimation;
45import android.widget.PopupMenu;
46import android.widget.TextView;
47
48import com.android.deskclock.stopwatch.StopwatchFragment;
49import com.android.deskclock.stopwatch.StopwatchService;
50import com.android.deskclock.stopwatch.Stopwatches;
51import com.android.deskclock.timer.TimerFragment;
52import com.android.deskclock.timer.TimerObj;
53import com.android.deskclock.timer.Timers;
54import com.android.deskclock.worldclock.CitiesActivity;
55
56import java.util.ArrayList;
57import java.util.TimeZone;
58
59/**
60 * DeskClock clock view for desk docks.
61 */
62public class DeskClock extends Activity implements LabelDialogFragment.TimerLabelDialogHandler {
63    private static final boolean DEBUG = false;
64
65    private static final String LOG_TAG = "DeskClock";
66
67    // Alarm action for midnight (so we can update the date display).
68    private static final String KEY_SELECTED_TAB = "selected_tab";
69    private static final String KEY_CLOCK_STATE = "clock_state";
70
71    public static final String SELECT_TAB_INTENT_EXTRA = "deskclock.select.tab";
72
73    private ActionBar mActionBar;
74    private Tab mTimerTab;
75    private Tab mClockTab;
76    private Tab mStopwatchTab;
77
78    private ViewPager mViewPager;
79    private TabsAdapter mTabsAdapter;
80
81    public static final int TIMER_TAB_INDEX = 0;
82    public static final int CLOCK_TAB_INDEX = 1;
83    public static final int STOPWATCH_TAB_INDEX = 2;
84
85    private int mSelectedTab;
86    private final boolean mDimmed = false;
87    private boolean mAddingTimer;
88    private int[] mClockButtonIds;
89    private int[] mTimerButtonId;
90    private int mFooterHeight;
91    private int mDimAnimationDuration;
92    private View mClockBackground;
93    private View mClockForeground;
94    private boolean mIsBlackBackground;
95
96    private int mClockState = CLOCK_NORMAL;
97    private static final int CLOCK_NORMAL = 0;
98    private static final int CLOCK_LIGHTS_OUT = 1;
99    private static final int CLOCK_DIMMED = 2;
100
101
102
103    // Delay before hiding the action bar and buttons
104    private static final long CLOCK_LIGHTSOUT_TIMEOUT = 10 * 1000; // 10 seconds
105    private static final long TIMER_SW_LIGHTSOUT_TIMEOUT = 3 * 1000; // 10 seconds
106    // Delay before dimming the screen
107    private static final long DIM_TIMEOUT = 10 * 1000; // 10 seconds
108
109    // Opacity of black layer between clock display and wallpaper.
110    private final float DIM_BEHIND_AMOUNT_NORMAL = 0.4f;
111    private final float DIM_BEHIND_AMOUNT_DIMMED = 0.8f; // higher contrast when display dimmed
112
113    private final int SCREEN_SAVER_TIMEOUT_MSG   = 0x2000;
114    private final int SCREEN_SAVER_MOVE_MSG      = 0x2001;
115    private final int DIM_TIMEOUT_MSG            = 0x2002;
116    private final int LIGHTSOUT_TIMEOUT_MSG      = 0x2003;
117    private final int BACK_TO_NORMAL_MSG         = 0x2004;
118
119
120
121    private final Handler mHandy = new Handler() {
122        @Override
123        public void handleMessage(Message m) {
124            switch(m.what) {
125                case LIGHTSOUT_TIMEOUT_MSG:
126                    if (mViewPager.getCurrentItem() == TIMER_TAB_INDEX && mAddingTimer) {
127                        break;
128                    }
129                    mClockState = CLOCK_LIGHTS_OUT;
130                    setClockState(true);
131                    break;
132                case DIM_TIMEOUT_MSG:
133                    mClockState = CLOCK_DIMMED;
134                    doDim(true);
135                    break;
136            }
137        }
138    };
139
140    @Override
141    public void onNewIntent(Intent newIntent) {
142        super.onNewIntent(newIntent);
143        if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent);
144
145        // update our intent so that we can consult it to determine whether or
146        // not the most recent launch was via a dock event
147        setIntent(newIntent);
148
149        // Timer receiver may ask to go to the timers fragment if a timer expired.
150        int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
151        if (tab != -1) {
152            if (mActionBar != null) {
153                mActionBar.setSelectedNavigationItem(tab);
154            }
155        }
156    }
157
158    private void initViews() {
159
160        if (mTabsAdapter == null) {
161            mViewPager = new ViewPager(this);
162            mViewPager.setId(R.id.desk_clock_pager);
163            mTabsAdapter = new TabsAdapter(this, mViewPager);
164            createTabs(mSelectedTab);
165        }
166        setContentView(mViewPager);
167        mActionBar.setSelectedNavigationItem(mSelectedTab);
168    }
169
170    private void createTabs(int selectedIndex) {
171        mActionBar = getActionBar();
172
173        mActionBar.setDisplayOptions(0);
174        if (mActionBar != null) {
175            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
176            mTimerTab = mActionBar.newTab();
177            mTimerTab.setIcon(R.drawable.timer_tab);
178            mTimerTab.setContentDescription(R.string.menu_timer);
179            mTabsAdapter.addTab(mTimerTab, TimerFragment.class,TIMER_TAB_INDEX);
180
181            mClockTab = mActionBar.newTab();
182            mClockTab.setIcon(R.drawable.clock_tab);
183            mClockTab.setContentDescription(R.string.menu_clock);
184            mTabsAdapter.addTab(mClockTab, ClockFragment.class,CLOCK_TAB_INDEX);
185            mStopwatchTab = mActionBar.newTab();
186            mStopwatchTab.setIcon(R.drawable.stopwatch_tab);
187            mStopwatchTab.setContentDescription(R.string.menu_stopwatch);
188            mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class,STOPWATCH_TAB_INDEX);
189            mActionBar.setSelectedNavigationItem(selectedIndex);
190        }
191    }
192
193    @Override
194    protected void onCreate(Bundle icicle) {
195        super.onCreate(icicle);
196
197        mSelectedTab = CLOCK_TAB_INDEX;
198        if (icicle != null) {
199            mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX);
200            mClockState = icicle.getInt(KEY_CLOCK_STATE, CLOCK_NORMAL);
201        }
202
203        // Timer receiver may ask the app to go to the timer fragment if a timer expired
204        Intent i = getIntent();
205        if (i != null) {
206            int tab = i.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
207            if (tab != -1) {
208                mSelectedTab = tab;
209            }
210        }
211        initViews();
212        setHomeTimeZone();
213
214        int[] buttonIds = {R.id.alarms_button, R.id.cities_button, R.id.menu_button};
215        mClockButtonIds = buttonIds;
216        int[] button = {R.id.timer_add_timer};
217        mTimerButtonId = button;
218        mFooterHeight = (int) getResources().getDimension(R.dimen.button_footer_height);
219        mDimAnimationDuration = getResources().getInteger(R.integer.dim_animation_duration);
220        mClockBackground = findViewById(R.id.clock_background);
221        mClockForeground = findViewById(R.id.clock_foreground);
222        mIsBlackBackground = false;
223    }
224
225    @Override
226    protected void onResume() {
227        super.onResume();
228        mAddingTimer = true;
229        setClockState(false);
230
231        Intent stopwatchIntent = new Intent(getApplicationContext(), StopwatchService.class);
232        stopwatchIntent.setAction(Stopwatches.KILL_NOTIF);
233        startService(stopwatchIntent);
234
235        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
236        SharedPreferences.Editor editor = prefs.edit();
237        editor.putBoolean(Timers.NOTIF_APP_OPEN, true);
238        editor.apply();
239        Intent timerIntent = new Intent();
240        timerIntent.setAction(Timers.NOTIF_IN_USE_CANCEL);
241        sendBroadcast(timerIntent);
242    }
243
244    @Override
245    public void onPause() {
246        removeLightsMessages();
247
248        Intent intent = new Intent(getApplicationContext(), StopwatchService.class);
249        intent.setAction(Stopwatches.SHOW_NOTIF);
250        startService(intent);
251
252        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
253        SharedPreferences.Editor editor = prefs.edit();
254        editor.putBoolean(Timers.NOTIF_APP_OPEN, false);
255        editor.apply();
256        Utils.showInUseNotifications(this);
257
258        super.onPause();
259    }
260
261    @Override
262    protected void onSaveInstanceState(Bundle outState) {
263        super.onSaveInstanceState(outState);
264        outState.putInt(KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex());
265        outState.putInt(KEY_CLOCK_STATE, mClockState);
266    }
267
268    public void clockButtonsOnClick(View v) {
269        if (!isClockStateNormal()) {
270            bringLightsUp(true);
271            return;
272        }
273        if (v == null)
274            return;
275        switch (v.getId()) {
276            case R.id.alarms_button:
277                startActivity(new Intent(this, AlarmClock.class));
278                break;
279            case R.id.cities_button:
280                startActivity(new Intent(this, CitiesActivity.class));
281                break;
282            case R.id.menu_button:
283                showMenu(v);
284                break;
285            default:
286                break;
287        }
288    }
289
290    private void showMenu(View v) {
291        PopupMenu popupMenu = new PopupMenu(this, v);
292        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener () {
293            @Override
294            public boolean onMenuItemClick(MenuItem item) {
295                switch (item.getItemId()) {
296                    case R.id.menu_item_settings:
297                        startActivity(new Intent(DeskClock.this, SettingsActivity.class));
298                        return true;
299                    case R.id.menu_item_help:
300                        Intent i = item.getIntent();
301                        if (i != null) {
302                            try {
303                                startActivity(i);
304                            } catch (ActivityNotFoundException e) {
305                                // No activity found to match the intent - ignore
306                            }
307                        }
308                        return true;
309                    default:
310                        break;
311                }
312                return true;
313            }
314        });
315        popupMenu.inflate(R.menu.desk_clock_menu);
316
317        Menu menu = popupMenu.getMenu();
318        MenuItem help = menu.findItem(R.id.menu_item_help);
319        if (help != null) {
320            Utils.prepareHelpMenuItem(this, help);
321        }
322        popupMenu.show();
323    }
324
325    /***
326     * Insert the local time zone as the Home Time Zone if one is not set
327     */
328    private void setHomeTimeZone() {
329        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
330        String homeTimeZone = prefs.getString(SettingsActivity.KEY_HOME_TZ, "");
331        if (!homeTimeZone.isEmpty()) {
332        return;
333        }
334        homeTimeZone = TimeZone.getDefault().getID();
335        SharedPreferences.Editor editor = prefs.edit();
336        editor.putString(SettingsActivity.KEY_HOME_TZ, homeTimeZone);
337        editor.apply();
338        Log.v(LOG_TAG, "Setting home time zone to " + homeTimeZone);
339    }
340
341    public boolean isClockStateNormal() {
342        return mClockState == CLOCK_NORMAL;
343    }
344
345    public boolean isClockStateDimmed() {
346        return mClockState == CLOCK_DIMMED;
347    }
348
349    public boolean isClockTab() {
350        return mViewPager.getCurrentItem() == CLOCK_TAB_INDEX;
351    }
352
353    public void clockOnViewClick(View view) {
354        // Toggle lights
355        switch(mClockState) {
356            case CLOCK_NORMAL:
357                mClockState = CLOCK_LIGHTS_OUT;
358                break;
359            case CLOCK_LIGHTS_OUT:
360            case CLOCK_DIMMED:
361                mClockState = CLOCK_NORMAL;
362                break;
363            default:
364                Log.v(LOG_TAG, "in a bad state. setting to normal.");
365                mClockState = CLOCK_NORMAL;
366                break;
367        }
368        setClockState(true);
369    }
370
371    private void setClockState(boolean fade) {
372        doDim(fade);
373        switch(mClockState) {
374            case CLOCK_NORMAL:
375                doLightsOut(false, fade);
376                break;
377            case CLOCK_LIGHTS_OUT:
378                doLightsOut(true, fade);
379                if (isClockTab()) {
380                    scheduleDim();
381                }
382                break;
383            case CLOCK_DIMMED:
384                doLightsOut(true, fade);
385                break;
386            default:
387                break;
388        }
389    }
390
391    private void doDim(boolean fade) {
392        if (mClockBackground == null) {
393            mClockBackground = findViewById(R.id.clock_background);
394            mClockForeground = findViewById(R.id.clock_foreground);
395            if (mClockBackground == null || mClockForeground == null) {
396                return;
397            }
398        }
399        if (mClockState == CLOCK_DIMMED) {
400            mClockForeground.startAnimation(
401                    AnimationUtils.loadAnimation(this, fade ? R.anim.dim : R.anim.dim_instant));
402            TransitionDrawable backgroundFade =
403                    (TransitionDrawable) mClockBackground.getBackground();
404            TransitionDrawable foregroundFade =
405                    (TransitionDrawable) mClockForeground.getBackground();
406            backgroundFade.startTransition(fade ? mDimAnimationDuration : 0);
407            foregroundFade.startTransition(fade ? mDimAnimationDuration : 0);
408            mIsBlackBackground = true;
409        } else {
410            if (mIsBlackBackground) {
411                mClockForeground.startAnimation(
412                        AnimationUtils.loadAnimation(this, R.anim.undim));
413                TransitionDrawable backgroundFade =
414                        (TransitionDrawable) mClockBackground.getBackground();
415                TransitionDrawable foregroundFade =
416                        (TransitionDrawable) mClockForeground.getBackground();
417                backgroundFade.reverseTransition(0);
418                foregroundFade.reverseTransition(0);
419                mIsBlackBackground = false;
420            }
421        }
422    }
423
424    public void doLightsOut(boolean lightsOut, boolean fade) {
425        if (lightsOut && mActionBar.isShowing()) {
426            mActionBar.hide();
427            mViewPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
428            hideAnimated(fade, R.id.clock_footer, mFooterHeight, mClockButtonIds);
429            if (mViewPager.getCurrentItem() != STOPWATCH_TAB_INDEX) {
430                hideAnimated(fade, R.id.timer_footer, mFooterHeight, mTimerButtonId);
431            }
432        } else if (!lightsOut && !mActionBar.isShowing()){
433            mActionBar.show();
434            mViewPager.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
435            unhideAnimated(fade, R.id.clock_footer, mFooterHeight, mClockButtonIds);
436            if (mViewPager.getCurrentItem() != STOPWATCH_TAB_INDEX) {
437                unhideAnimated(fade, R.id.timer_footer, mFooterHeight, mTimerButtonId);
438            }
439            // Make sure dim will not start before lights out
440            removeLightsMessages();
441            scheduleLightsOut();
442        }
443    }
444
445    private void hideAnimated(boolean fade, int viewId, int toYDelta, final int[] buttonIds) {
446        View view = findViewById(viewId);
447        if (view != null) {
448            Animation hideAnimation = new TranslateAnimation(0, 0, 0, toYDelta);
449            hideAnimation.setDuration(fade ? 350 : 0);
450            hideAnimation.setFillAfter(true);
451            hideAnimation.setInterpolator(AnimationUtils.loadInterpolator(this,
452                    android.R.interpolator.decelerate_cubic));
453            hideAnimation.setAnimationListener(new AnimationListener() {
454                @Override
455                public void onAnimationEnd(Animation animation) {
456                    if (buttonIds != null) {
457                        for (int buttonId : buttonIds) {
458                            View button = findViewById(buttonId);
459                            if (button != null) {
460                                button.setVisibility(View.GONE);
461                            }
462                        }
463                    }
464                }
465                @Override
466                public void onAnimationRepeat(Animation animation) {
467                }
468                @Override
469                public void onAnimationStart(Animation animation) {
470                }
471            });
472            view.startAnimation(hideAnimation);
473        }
474    }
475
476    private void unhideAnimated(boolean fade, int viewId, int fromYDelta, final int[] buttonIds) {
477        View view = findViewById(viewId);
478        if (view != null) {
479            Animation unhideAnimation = new TranslateAnimation(0, 0, fromYDelta, 0);
480            unhideAnimation.setDuration(fade ? 350 : 0);
481            unhideAnimation.setFillAfter(true);
482            unhideAnimation.setInterpolator(AnimationUtils.loadInterpolator(this,
483                    android.R.interpolator.decelerate_cubic));
484            if (buttonIds != null) {
485                for (int buttonId : buttonIds) {
486                    View button = findViewById(buttonId);
487                    if (button != null) {
488                        button.setVisibility(View.VISIBLE);
489                    }
490                }
491            }
492            view.startAnimation(unhideAnimation);
493        }
494    }
495
496    public void removeLightsMessages() {
497        mHandy.removeMessages(BACK_TO_NORMAL_MSG);
498        mHandy.removeMessages(LIGHTSOUT_TIMEOUT_MSG);
499        mHandy.removeMessages(DIM_TIMEOUT_MSG);
500    }
501
502    public void scheduleLightsOut() {
503        removeLightsMessages();
504        long timeout;
505        if (isClockTab()) {
506            timeout = CLOCK_LIGHTSOUT_TIMEOUT;
507        } else {
508            timeout = TIMER_SW_LIGHTSOUT_TIMEOUT;
509        }
510        mHandy.sendMessageDelayed(Message.obtain(mHandy, LIGHTSOUT_TIMEOUT_MSG), timeout);
511    }
512
513    public void bringLightsUp(boolean fade) {
514        removeLightsMessages();
515        if (mClockState != CLOCK_NORMAL) {
516            mClockState = CLOCK_NORMAL;
517            setClockState(fade);
518        } else {
519            scheduleLightsOut();
520        }
521    }
522
523    private void scheduleDim() {
524        removeLightsMessages();
525        mHandy.sendMessageDelayed(Message.obtain(mHandy, DIM_TIMEOUT_MSG), DIM_TIMEOUT);
526    }
527
528    public void setTimerAddingTimerState(boolean addingTimer) {
529        mAddingTimer = addingTimer;
530        if (addingTimer && mViewPager.getCurrentItem() == TIMER_TAB_INDEX) {
531            removeLightsMessages();
532        }
533    }
534
535    /***
536     * Adapter for wrapping together the ActionBar's tab with the ViewPager
537     */
538
539    private class TabsAdapter extends FragmentPagerAdapter
540            implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
541
542        private static final String KEY_TAB_POSITION = "tab_position";
543
544        final class TabInfo {
545            private final Class<?> clss;
546            private final Bundle args;
547
548            TabInfo(Class<?> _class, int position) {
549                clss = _class;
550                args = new Bundle();
551                args.putInt(KEY_TAB_POSITION, position);
552            }
553
554            public int getPosition() {
555                return args.getInt(KEY_TAB_POSITION, 0);
556            }
557        }
558
559        private final ArrayList<TabInfo> mTabs = new ArrayList <TabInfo>();
560        ActionBar mMainActionBar;
561        Context mContext;
562        ViewPager mPager;
563
564        public TabsAdapter(Activity activity, ViewPager pager) {
565            super(activity.getFragmentManager());
566            mContext = activity;
567            mMainActionBar = activity.getActionBar();
568            mPager = pager;
569            mPager.setAdapter(this);
570            mPager.setOnPageChangeListener(this);
571        }
572
573        @Override
574        public Fragment getItem(int position) {
575            TabInfo info = mTabs.get(position);
576            DeskClockFragment f = (DeskClockFragment) Fragment.instantiate(
577                    mContext, info.clss.getName(), info.args);
578            return f;
579        }
580
581        @Override
582        public int getCount() {
583            return mTabs.size();
584        }
585
586        public void addTab(ActionBar.Tab tab, Class<?> clss, int position) {
587            TabInfo info = new TabInfo(clss, position);
588            tab.setTag(info);
589            tab.setTabListener(this);
590            mTabs.add(info);
591            mMainActionBar.addTab(tab);
592            notifyDataSetChanged();
593        }
594
595        @Override
596        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
597            boolean fade = !isClockStateNormal();
598            bringLightsUp(fade);
599        }
600
601        @Override
602        public void onPageSelected(int position) {
603            mMainActionBar.setSelectedNavigationItem(position);
604            boolean fade = !isClockStateNormal();
605            bringLightsUp(fade);
606        }
607
608        @Override
609        public void onPageScrollStateChanged(int state) {
610            // Do nothing
611        }
612
613        @Override
614        public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
615            // Do nothing
616        }
617
618        @Override
619        public void onTabSelected(Tab tab, FragmentTransaction ft) {
620            TabInfo info = (TabInfo)tab.getTag();
621            mPager.setCurrentItem(info.getPosition());
622            boolean fade = !isClockStateNormal();
623            bringLightsUp(fade);
624        }
625
626        @Override
627        public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
628            // Do nothing
629
630        }
631    }
632
633    public static class OnTapListener implements OnTouchListener {
634        private DeskClock mActivity;
635        private float mLastTouchX;
636        private float mLastTouchY;
637        private long mLastTouchTime;
638        private TextView mMakePressedTextView;
639        private int mPressedColor, mGrayColor;
640        private final float MAX_MOVEMENT_ALLOWED = 20;
641        private final long MAX_TIME_ALLOWED = 500;
642
643        public OnTapListener(Activity activity) {
644            mActivity = (DeskClock) activity;
645        }
646
647        public OnTapListener(Activity activity, TextView makePressedView) {
648            mActivity = (DeskClock) activity;
649            mMakePressedTextView = makePressedView;
650            mPressedColor = activity.getResources().getColor(Utils.getPressedColorId());
651            mGrayColor = activity.getResources().getColor(Utils.getGrayColorId());
652        }
653
654        @Override
655        public boolean onTouch(View v, MotionEvent e) {
656            switch (e.getAction()) {
657                case (MotionEvent.ACTION_DOWN):
658                    mLastTouchTime = Utils.getTimeNow();
659                    if (mActivity.isClockStateDimmed()) {
660                        mActivity.clockOnViewClick(v);
661                        resetValues();
662                        break;
663                    }
664                    mLastTouchX = e.getX();
665                    mLastTouchY = e.getY();
666                    mActivity.removeLightsMessages();
667                    if (mMakePressedTextView != null) {
668                        mMakePressedTextView.setTextColor(mPressedColor);
669                    }
670                    break;
671                case (MotionEvent.ACTION_UP):
672                    float xDiff = Math.abs(e.getX()-mLastTouchX);
673                    float yDiff = Math.abs(e.getY()-mLastTouchY);
674                    long timeDiff = (Utils.getTimeNow() - mLastTouchTime);
675                    if (xDiff < MAX_MOVEMENT_ALLOWED && yDiff < MAX_MOVEMENT_ALLOWED
676                            && timeDiff < MAX_TIME_ALLOWED) {
677                        if (mMakePressedTextView != null) {
678                            v = mMakePressedTextView;
679                        }
680                        processClick(v);
681                        return true;
682                    } else {
683                        if (mActivity.isClockStateNormal()){
684                            mActivity.scheduleLightsOut();
685                        } else if (mActivity.isClockTab() && !mActivity.isClockStateDimmed()) {
686                            mActivity.scheduleDim();
687                        }
688                    }
689                    resetValues();
690                    break;
691                case (MotionEvent.ACTION_MOVE):
692                    xDiff = Math.abs(e.getX()-mLastTouchX);
693                    yDiff = Math.abs(e.getY()-mLastTouchY);
694                    if (xDiff >= MAX_MOVEMENT_ALLOWED || yDiff >= MAX_MOVEMENT_ALLOWED) {
695                        resetValues();
696                    }
697                    break;
698                default:
699                    resetValues();
700            }
701            return false;
702        }
703
704        private void resetValues() {
705            mLastTouchX = -1*MAX_MOVEMENT_ALLOWED + 1;
706            mLastTouchY = -1*MAX_MOVEMENT_ALLOWED + 1;
707            mLastTouchTime = -1*MAX_TIME_ALLOWED + 1;
708            if (mMakePressedTextView != null) {
709                mMakePressedTextView.setTextColor(mGrayColor);
710            }
711        }
712
713        protected void processClick(View v) {
714            mActivity.clockOnViewClick(v);
715        }
716    }
717
718    /** Called by the LabelDialogFormat class after the dialog is finished. **/
719    @Override
720    public void onDialogLabelSet(TimerObj timer, String label, String tag) {
721        if (isClockStateNormal()) {
722            scheduleLightsOut();
723        }
724        Fragment frag = getFragmentManager().findFragmentByTag(tag);
725        if (frag instanceof TimerFragment) {
726            ((TimerFragment) frag).setLabel(timer, label);
727        }
728    }
729}
730