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