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.animation.ArgbEvaluator; 20import android.animation.ObjectAnimator; 21import android.app.ActionBar; 22import android.app.ActionBar.Tab; 23import android.app.Activity; 24import android.app.Fragment; 25import android.app.FragmentManager; 26import android.app.FragmentTransaction; 27import android.content.ActivityNotFoundException; 28import android.content.Context; 29import android.content.Intent; 30import android.content.SharedPreferences; 31import android.content.res.Configuration; 32import android.graphics.Outline; 33import android.os.Bundle; 34import android.os.Handler; 35import android.preference.PreferenceManager; 36import android.support.v13.app.FragmentPagerAdapter; 37import android.support.v4.view.ViewPager; 38import android.text.TextUtils; 39import android.text.format.DateUtils; 40import android.util.Log; 41import android.view.Menu; 42import android.view.MenuItem; 43import android.view.MotionEvent; 44import android.view.View; 45import android.view.View.OnClickListener; 46import android.view.View.OnTouchListener; 47import android.view.ViewOutlineProvider; 48import android.widget.ImageButton; 49import android.widget.TextView; 50 51import com.android.deskclock.alarms.AlarmStateManager; 52import com.android.deskclock.provider.Alarm; 53import com.android.deskclock.stopwatch.StopwatchFragment; 54import com.android.deskclock.stopwatch.StopwatchService; 55import com.android.deskclock.stopwatch.Stopwatches; 56import com.android.deskclock.timer.TimerFragment; 57import com.android.deskclock.timer.TimerObj; 58import com.android.deskclock.timer.Timers; 59 60import java.util.ArrayList; 61import java.util.HashSet; 62import java.util.Locale; 63import java.util.TimeZone; 64 65/** 66 * DeskClock clock view for desk docks. 67 */ 68public class DeskClock extends Activity implements LabelDialogFragment.TimerLabelDialogHandler, 69 LabelDialogFragment.AlarmLabelDialogHandler { 70 private static final boolean DEBUG = false; 71 private static final String LOG_TAG = "DeskClock"; 72 // Alarm action for midnight (so we can update the date display). 73 private static final String KEY_SELECTED_TAB = "selected_tab"; 74 private static final String KEY_LAST_HOUR_COLOR = "last_hour_color"; 75 // Check whether to change background every minute 76 private static final long BACKGROUND_COLOR_CHECK_DELAY_MILLIS = DateUtils.MINUTE_IN_MILLIS; 77 private static final int BACKGROUND_COLOR_INITIAL_ANIMATION_DURATION_MILLIS = 3000; 78 // The depth of fab, use it to create shadow 79 private static final float FAB_DEPTH = 20f; 80 private static final int UNKNOWN_COLOR_ID = 0; 81 82 private boolean mIsFirstLaunch = true; 83 private ActionBar mActionBar; 84 private Tab mAlarmTab; 85 private Tab mClockTab; 86 private Tab mTimerTab; 87 private Tab mStopwatchTab; 88 private Menu mMenu; 89 private ViewPager mViewPager; 90 private TabsAdapter mTabsAdapter; 91 private Handler mHander; 92 private ImageButton mFab; 93 private ImageButton mLeftButton; 94 private ImageButton mRightButton; 95 private int mSelectedTab; 96 private int mLastHourColor = UNKNOWN_COLOR_ID; 97 private final Runnable mBackgroundColorChanger = new Runnable() { 98 @Override 99 public void run() { 100 setBackgroundColor(); 101 mHander.postDelayed(this, BACKGROUND_COLOR_CHECK_DELAY_MILLIS); 102 } 103 }; 104 105 public static final int ALARM_TAB_INDEX = 0; 106 public static final int CLOCK_TAB_INDEX = 1; 107 public static final int TIMER_TAB_INDEX = 2; 108 public static final int STOPWATCH_TAB_INDEX = 3; 109 // Tabs indices are switched for right-to-left since there is no 110 // native support for RTL in the ViewPager. 111 public static final int RTL_ALARM_TAB_INDEX = 3; 112 public static final int RTL_CLOCK_TAB_INDEX = 2; 113 public static final int RTL_TIMER_TAB_INDEX = 1; 114 public static final int RTL_STOPWATCH_TAB_INDEX = 0; 115 public static final String SELECT_TAB_INTENT_EXTRA = "deskclock.select.tab"; 116 117 // TODO(rachelzhang): adding a broadcast receiver to adjust color when the timezone/time 118 // changes in the background. 119 120 @Override 121 protected void onStart() { 122 super.onStart(); 123 if (mHander == null) { 124 mHander = new Handler(); 125 } 126 mHander.postDelayed(mBackgroundColorChanger, BACKGROUND_COLOR_CHECK_DELAY_MILLIS); 127 } 128 129 @Override 130 protected void onStop() { 131 super.onStop(); 132 mHander.removeCallbacks(mBackgroundColorChanger); 133 } 134 135 @Override 136 public void onNewIntent(Intent newIntent) { 137 super.onNewIntent(newIntent); 138 if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent); 139 140 // update our intent so that we can consult it to determine whether or 141 // not the most recent launch was via a dock event 142 setIntent(newIntent); 143 144 // Timer receiver may ask to go to the timers fragment if a timer expired. 145 int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1); 146 if (tab != -1) { 147 if (mActionBar != null) { 148 mActionBar.setSelectedNavigationItem(tab); 149 } 150 } 151 } 152 153 private static final ViewOutlineProvider OVAL_OUTLINE_PROVIDER = new ViewOutlineProvider() { 154 @Override 155 public void getOutline(View view, Outline outline) { 156 outline.setOval(0, 0, view.getWidth(), view.getHeight()); 157 } 158 }; 159 160 private void initViews() { 161 setContentView(R.layout.desk_clock); 162 mFab = (ImageButton) findViewById(R.id.fab); 163 mFab.setOutlineProvider(OVAL_OUTLINE_PROVIDER); 164 mFab.setTranslationZ(FAB_DEPTH); 165 mLeftButton = (ImageButton) findViewById(R.id.left_button); 166 mRightButton = (ImageButton) findViewById(R.id.right_button); 167 if (mTabsAdapter == null) { 168 mViewPager = (ViewPager) findViewById(R.id.desk_clock_pager); 169 // Keep all four tabs to minimize jank. 170 mViewPager.setOffscreenPageLimit(3); 171 mTabsAdapter = new TabsAdapter(this, mViewPager); 172 createTabs(mSelectedTab); 173 } 174 175 mFab.setOnClickListener(new OnClickListener() { 176 @Override 177 public void onClick(View view) { 178 getSelectedFragment().onFabClick(view); 179 } 180 }); 181 mLeftButton.setOnClickListener(new OnClickListener() { 182 @Override 183 public void onClick(View view) { 184 getSelectedFragment().onLeftButtonClick(view); 185 } 186 }); 187 mRightButton.setOnClickListener(new OnClickListener() { 188 @Override 189 public void onClick(View view) { 190 getSelectedFragment().onRightButtonClick(view); 191 } 192 }); 193 194 mActionBar.setSelectedNavigationItem(mSelectedTab); 195 } 196 197 private DeskClockFragment getSelectedFragment() { 198 return (DeskClockFragment) mTabsAdapter.getItem(getRtlPosition(mSelectedTab)); 199 } 200 201 private void createTabs(int selectedIndex) { 202 mActionBar = getActionBar(); 203 204 if (mActionBar != null) { 205 mActionBar.setDisplayOptions(0); 206 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 207 208 mAlarmTab = mActionBar.newTab(); 209 mAlarmTab.setIcon(R.drawable.alarm_tab); 210 mAlarmTab.setContentDescription(R.string.menu_alarm); 211 mTabsAdapter.addTab(mAlarmTab, AlarmClockFragment.class, ALARM_TAB_INDEX); 212 213 mClockTab = mActionBar.newTab(); 214 mClockTab.setIcon(R.drawable.clock_tab); 215 mClockTab.setContentDescription(R.string.menu_clock); 216 mTabsAdapter.addTab(mClockTab, ClockFragment.class, CLOCK_TAB_INDEX); 217 218 mTimerTab = mActionBar.newTab(); 219 mTimerTab.setIcon(R.drawable.timer_tab); 220 mTimerTab.setContentDescription(R.string.menu_timer); 221 mTabsAdapter.addTab(mTimerTab, TimerFragment.class, TIMER_TAB_INDEX); 222 223 mStopwatchTab = mActionBar.newTab(); 224 mStopwatchTab.setIcon(R.drawable.stopwatch_tab); 225 mStopwatchTab.setContentDescription(R.string.menu_stopwatch); 226 mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class, STOPWATCH_TAB_INDEX); 227 228 mActionBar.setSelectedNavigationItem(selectedIndex); 229 mTabsAdapter.notifySelectedPage(selectedIndex); 230 } 231 } 232 233 @Override 234 protected void onCreate(Bundle icicle) { 235 super.onCreate(icicle); 236 237 mIsFirstLaunch = (icicle == null); 238 getWindow().setBackgroundDrawable(null); 239 240 mIsFirstLaunch = true; 241 mSelectedTab = CLOCK_TAB_INDEX; 242 if (icicle != null) { 243 mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX); 244 mLastHourColor = icicle.getInt(KEY_LAST_HOUR_COLOR, UNKNOWN_COLOR_ID); 245 if (mLastHourColor != UNKNOWN_COLOR_ID) { 246 getWindow().getDecorView().setBackgroundColor(mLastHourColor); 247 } 248 } 249 250 // Timer receiver may ask the app to go to the timer fragment if a timer expired 251 Intent i = getIntent(); 252 if (i != null) { 253 int tab = i.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1); 254 if (tab != -1) { 255 mSelectedTab = tab; 256 } 257 } 258 initViews(); 259 setHomeTimeZone(); 260 261 // We need to update the system next alarm time on app startup because the 262 // user might have clear our data. 263 AlarmStateManager.updateNextAlarm(this); 264 ExtensionsFactory.init(getAssets()); 265 } 266 267 @Override 268 protected void onResume() { 269 super.onResume(); 270 271 setBackgroundColor(); 272 273 // We only want to show notifications for stopwatch/timer when the app is closed so 274 // that we don't have to worry about keeping the notifications in perfect sync with 275 // the app. 276 Intent stopwatchIntent = new Intent(getApplicationContext(), StopwatchService.class); 277 stopwatchIntent.setAction(Stopwatches.KILL_NOTIF); 278 startService(stopwatchIntent); 279 280 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 281 SharedPreferences.Editor editor = prefs.edit(); 282 editor.putBoolean(Timers.NOTIF_APP_OPEN, true); 283 editor.apply(); 284 Intent timerIntent = new Intent(); 285 timerIntent.setAction(Timers.NOTIF_IN_USE_CANCEL); 286 sendBroadcast(timerIntent); 287 } 288 289 @Override 290 public void onPause() { 291 Intent intent = new Intent(getApplicationContext(), StopwatchService.class); 292 intent.setAction(Stopwatches.SHOW_NOTIF); 293 startService(intent); 294 295 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 296 SharedPreferences.Editor editor = prefs.edit(); 297 editor.putBoolean(Timers.NOTIF_APP_OPEN, false); 298 editor.apply(); 299 Utils.showInUseNotifications(this); 300 301 super.onPause(); 302 } 303 304 @Override 305 protected void onSaveInstanceState(Bundle outState) { 306 super.onSaveInstanceState(outState); 307 outState.putInt(KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex()); 308 outState.putInt(KEY_LAST_HOUR_COLOR, mLastHourColor); 309 } 310 311 @Override 312 public boolean onCreateOptionsMenu(Menu menu) { 313 // We only want to show it as a menu in landscape, and only for clock/alarm fragment. 314 mMenu = menu; 315 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { 316 if (mActionBar.getSelectedNavigationIndex() == ALARM_TAB_INDEX || 317 mActionBar.getSelectedNavigationIndex() == CLOCK_TAB_INDEX) { 318 // Clear the menu so that it doesn't get duplicate items in case onCreateOptionsMenu 319 // was called multiple times. 320 menu.clear(); 321 getMenuInflater().inflate(R.menu.desk_clock_menu, menu); 322 } 323 // Always return true for landscape, regardless of whether we've inflated the menu, so 324 // that when we switch tabs this method will get called and we can inflate the menu. 325 return true; 326 } 327 return false; 328 } 329 330 @Override 331 public boolean onPrepareOptionsMenu(Menu menu) { 332 updateMenu(menu); 333 return true; 334 } 335 336 private void updateMenu(Menu menu) { 337 // Hide "help" if we don't have a URI for it. 338 MenuItem help = menu.findItem(R.id.menu_item_help); 339 if (help != null) { 340 Utils.prepareHelpMenuItem(this, help); 341 } 342 343 // Hide "lights out" for timer. 344 MenuItem nightMode = menu.findItem(R.id.menu_item_night_mode); 345 if (mActionBar.getSelectedNavigationIndex() == ALARM_TAB_INDEX) { 346 nightMode.setVisible(false); 347 } else if (mActionBar.getSelectedNavigationIndex() == CLOCK_TAB_INDEX) { 348 nightMode.setVisible(true); 349 } 350 } 351 352 @Override 353 public boolean onOptionsItemSelected(MenuItem item) { 354 if (processMenuClick(item)) { 355 return true; 356 } 357 358 return super.onOptionsItemSelected(item); 359 } 360 361 private boolean processMenuClick(MenuItem item) { 362 switch (item.getItemId()) { 363 case R.id.menu_item_settings: 364 startActivity(new Intent(DeskClock.this, SettingsActivity.class)); 365 return true; 366 case R.id.menu_item_help: 367 Intent i = item.getIntent(); 368 if (i != null) { 369 try { 370 startActivity(i); 371 } catch (ActivityNotFoundException e) { 372 // No activity found to match the intent - ignore 373 } 374 } 375 return true; 376 case R.id.menu_item_night_mode: 377 startActivity(new Intent(DeskClock.this, ScreensaverActivity.class)); 378 default: 379 break; 380 } 381 return true; 382 } 383 384 /** 385 * Insert the local time zone as the Home Time Zone if one is not set 386 */ 387 private void setHomeTimeZone() { 388 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 389 String homeTimeZone = prefs.getString(SettingsActivity.KEY_HOME_TZ, ""); 390 if (!homeTimeZone.isEmpty()) { 391 return; 392 } 393 homeTimeZone = TimeZone.getDefault().getID(); 394 SharedPreferences.Editor editor = prefs.edit(); 395 editor.putString(SettingsActivity.KEY_HOME_TZ, homeTimeZone); 396 editor.apply(); 397 Log.v(LOG_TAG, "Setting home time zone to " + homeTimeZone); 398 } 399 400 public void registerPageChangedListener(DeskClockFragment frag) { 401 if (mTabsAdapter != null) { 402 mTabsAdapter.registerPageChangedListener(frag); 403 } 404 } 405 406 public void unregisterPageChangedListener(DeskClockFragment frag) { 407 if (mTabsAdapter != null) { 408 mTabsAdapter.unregisterPageChangedListener(frag); 409 } 410 } 411 412 private void setBackgroundColor() { 413 final int duration; 414 if (mLastHourColor == UNKNOWN_COLOR_ID) { 415 mLastHourColor = getResources().getColor(R.color.default_background); 416 duration = BACKGROUND_COLOR_INITIAL_ANIMATION_DURATION_MILLIS; 417 } else { 418 duration = getResources().getInteger(android.R.integer.config_longAnimTime); 419 } 420 final int currHourColor = Utils.getCurrentHourColor(); 421 if (mLastHourColor != currHourColor) { 422 final ObjectAnimator animator = ObjectAnimator.ofInt(getWindow().getDecorView(), 423 "backgroundColor", mLastHourColor, currHourColor); 424 animator.setDuration(duration); 425 animator.setEvaluator(new ArgbEvaluator()); 426 animator.start(); 427 mLastHourColor = currHourColor; 428 } 429 } 430 431 /** 432 * Adapter for wrapping together the ActionBar's tab with the ViewPager 433 */ 434 private class TabsAdapter extends FragmentPagerAdapter 435 implements ActionBar.TabListener, ViewPager.OnPageChangeListener { 436 437 private static final String KEY_TAB_POSITION = "tab_position"; 438 439 final class TabInfo { 440 private final Class<?> clss; 441 private final Bundle args; 442 443 TabInfo(Class<?> _class, int position) { 444 clss = _class; 445 args = new Bundle(); 446 args.putInt(KEY_TAB_POSITION, position); 447 } 448 449 public int getPosition() { 450 return args.getInt(KEY_TAB_POSITION, 0); 451 } 452 } 453 454 private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 455 ActionBar mMainActionBar; 456 Context mContext; 457 ViewPager mPager; 458 // Used for doing callbacks to fragments. 459 HashSet<String> mFragmentTags = new HashSet<String>(); 460 461 public TabsAdapter(Activity activity, ViewPager pager) { 462 super(activity.getFragmentManager()); 463 mContext = activity; 464 mMainActionBar = activity.getActionBar(); 465 mPager = pager; 466 mPager.setAdapter(this); 467 mPager.setOnPageChangeListener(this); 468 } 469 470 @Override 471 public Fragment getItem(int position) { 472 // Because this public method is called outside many times, 473 // check if it exits first before creating a new one. 474 final String name = makeFragmentName(R.id.desk_clock_pager, position); 475 Fragment fragment = getFragmentManager().findFragmentByTag(name); 476 if (fragment == null) { 477 TabInfo info = mTabs.get(getRtlPosition(position)); 478 fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args); 479 if (fragment instanceof TimerFragment) { 480 ((TimerFragment) fragment).setFabAppearance(); 481 ((TimerFragment) fragment).setLeftRightButtonAppearance(); 482 } 483 } 484 return fragment; 485 } 486 487 /** 488 * Copied from: 489 * android/frameworks/support/v13/java/android/support/v13/app/FragmentPagerAdapter.java#94 490 * Create unique name for the fragment so fragment manager knows it exist. 491 */ 492 private String makeFragmentName(int viewId, int index) { 493 return "android:switcher:" + viewId + ":" + index; 494 } 495 496 @Override 497 public int getCount() { 498 return mTabs.size(); 499 } 500 501 public void addTab(ActionBar.Tab tab, Class<?> clss, int position) { 502 TabInfo info = new TabInfo(clss, position); 503 tab.setTag(info); 504 tab.setTabListener(this); 505 mTabs.add(info); 506 mMainActionBar.addTab(tab); 507 notifyDataSetChanged(); 508 } 509 510 @Override 511 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 512 // Do nothing 513 } 514 515 @Override 516 public void onPageSelected(int position) { 517 // Set the page before doing the menu so that onCreateOptionsMenu knows what page it is. 518 mMainActionBar.setSelectedNavigationItem(getRtlPosition(position)); 519 notifyPageChanged(position); 520 521 // Only show the overflow menu for alarm and world clock. 522 if (mMenu != null) { 523 // Make sure the menu's been initialized. 524 if (position == ALARM_TAB_INDEX || position == CLOCK_TAB_INDEX) { 525 mMenu.setGroupVisible(R.id.menu_items, true); 526 onCreateOptionsMenu(mMenu); 527 } else { 528 mMenu.setGroupVisible(R.id.menu_items, false); 529 } 530 } 531 } 532 533 @Override 534 public void onPageScrollStateChanged(int state) { 535 // Do nothing 536 } 537 538 @Override 539 public void onTabReselected(Tab arg0, FragmentTransaction arg1) { 540 // Do nothing 541 } 542 543 @Override 544 public void onTabSelected(Tab tab, FragmentTransaction ft) { 545 final TabInfo info = (TabInfo) tab.getTag(); 546 final int position = info.getPosition(); 547 final int rtlSafePosition = getRtlPosition(position); 548 mSelectedTab = position; 549 550 if (mIsFirstLaunch && isClockTab(rtlSafePosition)) { 551 mLeftButton.setVisibility(View.INVISIBLE); 552 mRightButton.setVisibility(View.INVISIBLE); 553 mFab.setVisibility(View.VISIBLE); 554 mFab.setImageResource(R.drawable.ic_globe); 555 mFab.setContentDescription(getString(R.string.button_cities)); 556 mIsFirstLaunch = false; 557 } else { 558 DeskClockFragment f = (DeskClockFragment) getItem(rtlSafePosition); 559 f.setFabAppearance(); 560 f.setLeftRightButtonAppearance(); 561 } 562 mPager.setCurrentItem(rtlSafePosition); 563 } 564 565 @Override 566 public void onTabUnselected(Tab arg0, FragmentTransaction arg1) { 567 // Do nothing 568 } 569 570 private boolean isClockTab(int rtlSafePosition) { 571 final int clockTabIndex = isRtl() ? RTL_CLOCK_TAB_INDEX : CLOCK_TAB_INDEX; 572 return rtlSafePosition == clockTabIndex; 573 } 574 575 public void notifySelectedPage(int page) { 576 notifyPageChanged(page); 577 } 578 579 private void notifyPageChanged(int newPage) { 580 for (String tag : mFragmentTags) { 581 final FragmentManager fm = getFragmentManager(); 582 DeskClockFragment f = (DeskClockFragment) fm.findFragmentByTag(tag); 583 if (f != null) { 584 f.onPageChanged(newPage); 585 } 586 } 587 } 588 589 public void registerPageChangedListener(DeskClockFragment frag) { 590 String tag = frag.getTag(); 591 if (mFragmentTags.contains(tag)) { 592 Log.wtf(LOG_TAG, "Trying to add an existing fragment " + tag); 593 } else { 594 mFragmentTags.add(frag.getTag()); 595 } 596 // Since registering a listener by the fragment is done sometimes after the page 597 // was already changed, make sure the fragment gets the current page 598 frag.onPageChanged(mMainActionBar.getSelectedNavigationIndex()); 599 } 600 601 public void unregisterPageChangedListener(DeskClockFragment frag) { 602 mFragmentTags.remove(frag.getTag()); 603 } 604 605 } 606 607 public static abstract class OnTapListener implements OnTouchListener { 608 private float mLastTouchX; 609 private float mLastTouchY; 610 private long mLastTouchTime; 611 private final TextView mMakePressedTextView; 612 private final int mPressedColor, mGrayColor; 613 private final float MAX_MOVEMENT_ALLOWED = 20; 614 private final long MAX_TIME_ALLOWED = 500; 615 616 public OnTapListener(Activity activity, TextView makePressedView) { 617 mMakePressedTextView = makePressedView; 618 mPressedColor = activity.getResources().getColor(Utils.getPressedColorId()); 619 mGrayColor = activity.getResources().getColor(Utils.getGrayColorId()); 620 } 621 622 @Override 623 public boolean onTouch(View v, MotionEvent e) { 624 switch (e.getAction()) { 625 case (MotionEvent.ACTION_DOWN): 626 mLastTouchTime = Utils.getTimeNow(); 627 mLastTouchX = e.getX(); 628 mLastTouchY = e.getY(); 629 if (mMakePressedTextView != null) { 630 mMakePressedTextView.setTextColor(mPressedColor); 631 } 632 break; 633 case (MotionEvent.ACTION_UP): 634 float xDiff = Math.abs(e.getX() - mLastTouchX); 635 float yDiff = Math.abs(e.getY() - mLastTouchY); 636 long timeDiff = (Utils.getTimeNow() - mLastTouchTime); 637 if (xDiff < MAX_MOVEMENT_ALLOWED && yDiff < MAX_MOVEMENT_ALLOWED 638 && timeDiff < MAX_TIME_ALLOWED) { 639 if (mMakePressedTextView != null) { 640 v = mMakePressedTextView; 641 } 642 processClick(v); 643 resetValues(); 644 return true; 645 } 646 resetValues(); 647 break; 648 case (MotionEvent.ACTION_MOVE): 649 xDiff = Math.abs(e.getX() - mLastTouchX); 650 yDiff = Math.abs(e.getY() - mLastTouchY); 651 if (xDiff >= MAX_MOVEMENT_ALLOWED || yDiff >= MAX_MOVEMENT_ALLOWED) { 652 resetValues(); 653 } 654 break; 655 default: 656 resetValues(); 657 } 658 return false; 659 } 660 661 private void resetValues() { 662 mLastTouchX = -1 * MAX_MOVEMENT_ALLOWED + 1; 663 mLastTouchY = -1 * MAX_MOVEMENT_ALLOWED + 1; 664 mLastTouchTime = -1 * MAX_TIME_ALLOWED + 1; 665 if (mMakePressedTextView != null) { 666 mMakePressedTextView.setTextColor(mGrayColor); 667 } 668 } 669 670 protected abstract void processClick(View v); 671 } 672 673 /** 674 * Called by the LabelDialogFormat class after the dialog is finished. * 675 */ 676 @Override 677 public void onDialogLabelSet(TimerObj timer, String label, String tag) { 678 Fragment frag = getFragmentManager().findFragmentByTag(tag); 679 if (frag instanceof TimerFragment) { 680 ((TimerFragment) frag).setLabel(timer, label); 681 } 682 } 683 684 /** 685 * Called by the LabelDialogFormat class after the dialog is finished. * 686 */ 687 @Override 688 public void onDialogLabelSet(Alarm alarm, String label, String tag) { 689 Fragment frag = getFragmentManager().findFragmentByTag(tag); 690 if (frag instanceof AlarmClockFragment) { 691 ((AlarmClockFragment) frag).setLabel(alarm, label); 692 } 693 } 694 695 public int getSelectedTab() { 696 return mSelectedTab; 697 } 698 699 private boolean isRtl() { 700 return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == 701 View.LAYOUT_DIRECTION_RTL; 702 } 703 704 private int getRtlPosition(int position) { 705 if (isRtl()) { 706 switch (position) { 707 case TIMER_TAB_INDEX: 708 return RTL_TIMER_TAB_INDEX; 709 case CLOCK_TAB_INDEX: 710 return RTL_CLOCK_TAB_INDEX; 711 case STOPWATCH_TAB_INDEX: 712 return RTL_STOPWATCH_TAB_INDEX; 713 case ALARM_TAB_INDEX: 714 return RTL_ALARM_TAB_INDEX; 715 default: 716 break; 717 } 718 } 719 return position; 720 } 721 722 public ImageButton getFab() { 723 return mFab; 724 } 725 726 public ImageButton getLeftButton() { 727 return mLeftButton; 728 } 729 730 public ImageButton getRightButton() { 731 return mRightButton; 732 } 733} 734