Home | History | Annotate | Download | only in deskclock
      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 
     17 package com.android.deskclock;
     18 
     19 import android.app.ActionBar;
     20 import android.app.ActionBar.Tab;
     21 import android.app.Activity;
     22 import android.app.Fragment;
     23 import android.app.FragmentTransaction;
     24 import android.content.ActivityNotFoundException;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.SharedPreferences;
     28 import android.graphics.drawable.TransitionDrawable;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.os.Message;
     32 import android.preference.PreferenceManager;
     33 import android.support.v13.app.FragmentPagerAdapter;
     34 import android.support.v4.view.ViewPager;
     35 import android.util.Log;
     36 import android.view.Menu;
     37 import android.view.MenuItem;
     38 import android.view.MotionEvent;
     39 import android.view.View;
     40 import android.view.View.OnTouchListener;
     41 import android.view.animation.Animation;
     42 import android.view.animation.Animation.AnimationListener;
     43 import android.view.animation.AnimationUtils;
     44 import android.view.animation.TranslateAnimation;
     45 import android.widget.PopupMenu;
     46 import android.widget.TextView;
     47 
     48 import com.android.deskclock.stopwatch.StopwatchFragment;
     49 import com.android.deskclock.stopwatch.StopwatchService;
     50 import com.android.deskclock.stopwatch.Stopwatches;
     51 import com.android.deskclock.timer.TimerFragment;
     52 import com.android.deskclock.timer.TimerObj;
     53 import com.android.deskclock.timer.Timers;
     54 import com.android.deskclock.worldclock.CitiesActivity;
     55 
     56 import java.util.ArrayList;
     57 import java.util.TimeZone;
     58 
     59 /**
     60  * DeskClock clock view for desk docks.
     61  */
     62 public 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 
     87     @Override
     88     public void onNewIntent(Intent newIntent) {
     89         super.onNewIntent(newIntent);
     90         if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent);
     91 
     92         // update our intent so that we can consult it to determine whether or
     93         // not the most recent launch was via a dock event
     94         setIntent(newIntent);
     95 
     96         // Timer receiver may ask to go to the timers fragment if a timer expired.
     97         int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
     98         if (tab != -1) {
     99             if (mActionBar != null) {
    100                 mActionBar.setSelectedNavigationItem(tab);
    101             }
    102         }
    103     }
    104 
    105     private void initViews() {
    106 
    107         if (mTabsAdapter == null) {
    108             mViewPager = new ViewPager(this);
    109             mViewPager.setId(R.id.desk_clock_pager);
    110             mTabsAdapter = new TabsAdapter(this, mViewPager);
    111             createTabs(mSelectedTab);
    112         }
    113         setContentView(mViewPager);
    114         mActionBar.setSelectedNavigationItem(mSelectedTab);
    115     }
    116 
    117     private void createTabs(int selectedIndex) {
    118         mActionBar = getActionBar();
    119 
    120         mActionBar.setDisplayOptions(0);
    121         if (mActionBar != null) {
    122             mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    123             mTimerTab = mActionBar.newTab();
    124             mTimerTab.setIcon(R.drawable.timer_tab);
    125             mTimerTab.setContentDescription(R.string.menu_timer);
    126             mTabsAdapter.addTab(mTimerTab, TimerFragment.class,TIMER_TAB_INDEX);
    127 
    128             mClockTab = mActionBar.newTab();
    129             mClockTab.setIcon(R.drawable.clock_tab);
    130             mClockTab.setContentDescription(R.string.menu_clock);
    131             mTabsAdapter.addTab(mClockTab, ClockFragment.class,CLOCK_TAB_INDEX);
    132             mStopwatchTab = mActionBar.newTab();
    133             mStopwatchTab.setIcon(R.drawable.stopwatch_tab);
    134             mStopwatchTab.setContentDescription(R.string.menu_stopwatch);
    135             mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class,STOPWATCH_TAB_INDEX);
    136             mActionBar.setSelectedNavigationItem(selectedIndex);
    137         }
    138     }
    139 
    140     @Override
    141     protected void onCreate(Bundle icicle) {
    142         super.onCreate(icicle);
    143 
    144         mSelectedTab = CLOCK_TAB_INDEX;
    145         if (icicle != null) {
    146             mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX);
    147         }
    148 
    149         // Timer receiver may ask the app to go to the timer fragment if a timer expired
    150         Intent i = getIntent();
    151         if (i != null) {
    152             int tab = i.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
    153             if (tab != -1) {
    154                 mSelectedTab = tab;
    155             }
    156         }
    157         initViews();
    158         setHomeTimeZone();
    159     }
    160 
    161     @Override
    162     protected void onResume() {
    163         super.onResume();
    164 
    165         Intent stopwatchIntent = new Intent(getApplicationContext(), StopwatchService.class);
    166         stopwatchIntent.setAction(Stopwatches.KILL_NOTIF);
    167         startService(stopwatchIntent);
    168 
    169         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    170         SharedPreferences.Editor editor = prefs.edit();
    171         editor.putBoolean(Timers.NOTIF_APP_OPEN, true);
    172         editor.apply();
    173         Intent timerIntent = new Intent();
    174         timerIntent.setAction(Timers.NOTIF_IN_USE_CANCEL);
    175         sendBroadcast(timerIntent);
    176     }
    177 
    178     @Override
    179     public void onPause() {
    180 
    181         Intent intent = new Intent(getApplicationContext(), StopwatchService.class);
    182         intent.setAction(Stopwatches.SHOW_NOTIF);
    183         startService(intent);
    184 
    185         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    186         SharedPreferences.Editor editor = prefs.edit();
    187         editor.putBoolean(Timers.NOTIF_APP_OPEN, false);
    188         editor.apply();
    189         Utils.showInUseNotifications(this);
    190 
    191         super.onPause();
    192     }
    193 
    194     @Override
    195     protected void onSaveInstanceState(Bundle outState) {
    196         super.onSaveInstanceState(outState);
    197         outState.putInt(KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex());
    198     }
    199 
    200     public void clockButtonsOnClick(View v) {
    201         if (v == null)
    202             return;
    203         switch (v.getId()) {
    204             case R.id.alarms_button:
    205                 startActivity(new Intent(this, AlarmClock.class));
    206                 break;
    207             case R.id.cities_button:
    208                 startActivity(new Intent(this, CitiesActivity.class));
    209                 break;
    210             case R.id.menu_button:
    211                 showMenu(v);
    212                 break;
    213             default:
    214                 break;
    215         }
    216     }
    217 
    218     private void showMenu(View v) {
    219         PopupMenu popupMenu = new PopupMenu(this, v);
    220         popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener () {
    221             @Override
    222             public boolean onMenuItemClick(MenuItem item) {
    223                 switch (item.getItemId()) {
    224                     case R.id.menu_item_settings:
    225                         startActivity(new Intent(DeskClock.this, SettingsActivity.class));
    226                         return true;
    227                     case R.id.menu_item_help:
    228                         Intent i = item.getIntent();
    229                         if (i != null) {
    230                             try {
    231                                 startActivity(i);
    232                             } catch (ActivityNotFoundException e) {
    233                                 // No activity found to match the intent - ignore
    234                             }
    235                         }
    236                         return true;
    237                     case R.id.menu_item_night_mode:
    238                         startActivity(new Intent(DeskClock.this, ScreensaverActivity.class));
    239                     default:
    240                         break;
    241                 }
    242                 return true;
    243             }
    244         });
    245         popupMenu.inflate(R.menu.desk_clock_menu);
    246 
    247         Menu menu = popupMenu.getMenu();
    248         MenuItem help = menu.findItem(R.id.menu_item_help);
    249         if (help != null) {
    250             Utils.prepareHelpMenuItem(this, help);
    251         }
    252         popupMenu.show();
    253     }
    254 
    255     /***
    256      * Insert the local time zone as the Home Time Zone if one is not set
    257      */
    258     private void setHomeTimeZone() {
    259         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    260         String homeTimeZone = prefs.getString(SettingsActivity.KEY_HOME_TZ, "");
    261         if (!homeTimeZone.isEmpty()) {
    262         return;
    263         }
    264         homeTimeZone = TimeZone.getDefault().getID();
    265         SharedPreferences.Editor editor = prefs.edit();
    266         editor.putString(SettingsActivity.KEY_HOME_TZ, homeTimeZone);
    267         editor.apply();
    268         Log.v(LOG_TAG, "Setting home time zone to " + homeTimeZone);
    269     }
    270 
    271     public boolean isClockTab() {
    272         return mViewPager.getCurrentItem() == CLOCK_TAB_INDEX;
    273     }
    274 
    275     /***
    276      * Adapter for wrapping together the ActionBar's tab with the ViewPager
    277      */
    278 
    279     private class TabsAdapter extends FragmentPagerAdapter
    280             implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
    281 
    282         private static final String KEY_TAB_POSITION = "tab_position";
    283 
    284         final class TabInfo {
    285             private final Class<?> clss;
    286             private final Bundle args;
    287 
    288             TabInfo(Class<?> _class, int position) {
    289                 clss = _class;
    290                 args = new Bundle();
    291                 args.putInt(KEY_TAB_POSITION, position);
    292             }
    293 
    294             public int getPosition() {
    295                 return args.getInt(KEY_TAB_POSITION, 0);
    296             }
    297         }
    298 
    299         private final ArrayList<TabInfo> mTabs = new ArrayList <TabInfo>();
    300         ActionBar mMainActionBar;
    301         Context mContext;
    302         ViewPager mPager;
    303 
    304         public TabsAdapter(Activity activity, ViewPager pager) {
    305             super(activity.getFragmentManager());
    306             mContext = activity;
    307             mMainActionBar = activity.getActionBar();
    308             mPager = pager;
    309             mPager.setAdapter(this);
    310             mPager.setOnPageChangeListener(this);
    311         }
    312 
    313         @Override
    314         public Fragment getItem(int position) {
    315             TabInfo info = mTabs.get(position);
    316             DeskClockFragment f = (DeskClockFragment) Fragment.instantiate(
    317                     mContext, info.clss.getName(), info.args);
    318             return f;
    319         }
    320 
    321         @Override
    322         public int getCount() {
    323             return mTabs.size();
    324         }
    325 
    326         public void addTab(ActionBar.Tab tab, Class<?> clss, int position) {
    327             TabInfo info = new TabInfo(clss, position);
    328             tab.setTag(info);
    329             tab.setTabListener(this);
    330             mTabs.add(info);
    331             mMainActionBar.addTab(tab);
    332             notifyDataSetChanged();
    333         }
    334 
    335         @Override
    336         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    337             // Do nothing
    338         }
    339 
    340         @Override
    341         public void onPageSelected(int position) {
    342             mMainActionBar.setSelectedNavigationItem(position);
    343         }
    344 
    345         @Override
    346         public void onPageScrollStateChanged(int state) {
    347             // Do nothing
    348         }
    349 
    350         @Override
    351         public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
    352             // Do nothing
    353         }
    354 
    355         @Override
    356         public void onTabSelected(Tab tab, FragmentTransaction ft) {
    357             TabInfo info = (TabInfo)tab.getTag();
    358             mPager.setCurrentItem(info.getPosition());
    359         }
    360 
    361         @Override
    362         public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
    363             // Do nothing
    364 
    365         }
    366     }
    367 
    368     public static abstract class OnTapListener implements OnTouchListener {
    369         private float mLastTouchX;
    370         private float mLastTouchY;
    371         private long mLastTouchTime;
    372         private TextView mMakePressedTextView;
    373         private int mPressedColor, mGrayColor;
    374         private final float MAX_MOVEMENT_ALLOWED = 20;
    375         private final long MAX_TIME_ALLOWED = 500;
    376 
    377         public OnTapListener(Activity activity, TextView makePressedView) {
    378             mMakePressedTextView = makePressedView;
    379             mPressedColor = activity.getResources().getColor(Utils.getPressedColorId());
    380             mGrayColor = activity.getResources().getColor(Utils.getGrayColorId());
    381         }
    382 
    383         @Override
    384         public boolean onTouch(View v, MotionEvent e) {
    385             switch (e.getAction()) {
    386                 case (MotionEvent.ACTION_DOWN):
    387                     mLastTouchTime = Utils.getTimeNow();
    388                     mLastTouchX = e.getX();
    389                     mLastTouchY = e.getY();
    390                     if (mMakePressedTextView != null) {
    391                         mMakePressedTextView.setTextColor(mPressedColor);
    392                     }
    393                     break;
    394                 case (MotionEvent.ACTION_UP):
    395                     float xDiff = Math.abs(e.getX()-mLastTouchX);
    396                     float yDiff = Math.abs(e.getY()-mLastTouchY);
    397                     long timeDiff = (Utils.getTimeNow() - mLastTouchTime);
    398                     if (xDiff < MAX_MOVEMENT_ALLOWED && yDiff < MAX_MOVEMENT_ALLOWED
    399                             && timeDiff < MAX_TIME_ALLOWED) {
    400                         if (mMakePressedTextView != null) {
    401                             v = mMakePressedTextView;
    402                         }
    403                         processClick(v);
    404                         resetValues();
    405                         return true;
    406                     }
    407                     resetValues();
    408                     break;
    409                 case (MotionEvent.ACTION_MOVE):
    410                     xDiff = Math.abs(e.getX()-mLastTouchX);
    411                     yDiff = Math.abs(e.getY()-mLastTouchY);
    412                     if (xDiff >= MAX_MOVEMENT_ALLOWED || yDiff >= MAX_MOVEMENT_ALLOWED) {
    413                         resetValues();
    414                     }
    415                     break;
    416                 default:
    417                     resetValues();
    418             }
    419             return false;
    420         }
    421 
    422         private void resetValues() {
    423             mLastTouchX = -1*MAX_MOVEMENT_ALLOWED + 1;
    424             mLastTouchY = -1*MAX_MOVEMENT_ALLOWED + 1;
    425             mLastTouchTime = -1*MAX_TIME_ALLOWED + 1;
    426             if (mMakePressedTextView != null) {
    427                 mMakePressedTextView.setTextColor(mGrayColor);
    428             }
    429         }
    430 
    431         protected abstract void processClick(View v);
    432     }
    433 
    434     /** Called by the LabelDialogFormat class after the dialog is finished. **/
    435     @Override
    436     public void onDialogLabelSet(TimerObj timer, String label, String tag) {
    437         Fragment frag = getFragmentManager().findFragmentByTag(tag);
    438         if (frag instanceof TimerFragment) {
    439             ((TimerFragment) frag).setLabel(timer, label);
    440         }
    441     }
    442 }
    443