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