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