Home | History | Annotate | Download | only in deskclock
      1 /*
      2  * Copyright (C) 2012 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.Activity;
     20 import android.app.AlarmManager;
     21 import android.content.BroadcastReceiver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.SharedPreferences;
     26 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.preference.PreferenceManager;
     30 import android.view.LayoutInflater;
     31 import android.view.MotionEvent;
     32 import android.view.View;
     33 import android.view.View.OnClickListener;
     34 import android.view.View.OnTouchListener;
     35 import android.view.ViewConfiguration;
     36 import android.view.ViewGroup;
     37 import android.widget.ImageButton;
     38 import android.widget.ListView;
     39 import android.widget.TextClock;
     40 
     41 import com.android.deskclock.worldclock.CitiesActivity;
     42 import com.android.deskclock.worldclock.WorldClockAdapter;
     43 
     44 /**
     45  * Fragment that shows  the clock (analog or digital), the next alarm info and the world clock.
     46  */
     47 public class ClockFragment extends DeskClockFragment implements OnSharedPreferenceChangeListener {
     48 
     49     private static final String BUTTONS_HIDDEN_KEY = "buttons_hidden";
     50     private final static String TAG = "ClockFragment";
     51 
     52     private boolean mButtonsHidden = false;
     53     private View mDigitalClock, mAnalogClock, mClockFrame, mHairline;
     54     private WorldClockAdapter mAdapter;
     55     private ListView mList;
     56     private SharedPreferences mPrefs;
     57     private String mDateFormat;
     58     private String mDateFormatForAccessibility;
     59     private String mDefaultClockStyle;
     60     private String mClockStyle;
     61 
     62     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
     63         @Override
     64         public void onReceive(Context context, Intent intent) {
     65             String action = intent.getAction();
     66             boolean changed = action.equals(Intent.ACTION_TIME_CHANGED)
     67                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)
     68                     || action.equals(Intent.ACTION_LOCALE_CHANGED);
     69             if (changed) {
     70                 Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mClockFrame);
     71                 if (mAdapter != null) {
     72                     // *CHANGED may modify the need for showing the Home City
     73                     if (mAdapter.hasHomeCity() != mAdapter.needHomeCity()) {
     74                         mAdapter.reloadData(context);
     75                     } else {
     76                         mAdapter.notifyDataSetChanged();
     77                     }
     78                     // Locale change: update digital clock format and
     79                     // reload the cities list with new localized names
     80                     if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
     81                         if (mDigitalClock != null) {
     82                             Utils.setTimeFormat(
     83                                     (TextClock) (mDigitalClock.findViewById(R.id.digital_clock)),
     84                                     (int) context.getResources().
     85                                             getDimension(R.dimen.main_ampm_font_size)
     86                             );
     87                         }
     88                         mAdapter.loadCitiesDb(context);
     89                         mAdapter.notifyDataSetChanged();
     90                     }
     91                 }
     92                 Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater);
     93             }
     94             if (changed || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
     95                 Utils.refreshAlarm(getActivity(), mClockFrame);
     96             }
     97         }
     98     };
     99 
    100     private final Handler mHandler = new Handler();
    101 
    102     // Thread that runs on every quarter-hour and refreshes the date.
    103     private final Runnable mQuarterHourUpdater = new Runnable() {
    104         @Override
    105         public void run() {
    106             // Update the main and world clock dates
    107             Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mClockFrame);
    108             if (mAdapter != null) {
    109                 mAdapter.notifyDataSetChanged();
    110             }
    111             Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater);
    112         }
    113     };
    114 
    115     public ClockFragment() {
    116     }
    117 
    118     @Override
    119     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    120             Bundle icicle) {
    121         // Inflate the layout for this fragment
    122         View v = inflater.inflate(R.layout.clock_fragment, container, false);
    123         if (icicle != null) {
    124             mButtonsHidden = icicle.getBoolean(BUTTONS_HIDDEN_KEY, false);
    125         }
    126         mList = (ListView) v.findViewById(R.id.cities);
    127         mList.setDivider(null);
    128 
    129         OnTouchListener longPressNightMode = new OnTouchListener() {
    130             private float mMaxMovementAllowed = -1;
    131             private int mLongPressTimeout = -1;
    132             private float mLastTouchX
    133                     ,
    134                     mLastTouchY;
    135 
    136             @Override
    137             public boolean onTouch(View v, MotionEvent event) {
    138                 if (mMaxMovementAllowed == -1) {
    139                     mMaxMovementAllowed = ViewConfiguration.get(getActivity()).getScaledTouchSlop();
    140                     mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
    141                 }
    142 
    143                 switch (event.getAction()) {
    144                     case (MotionEvent.ACTION_DOWN):
    145                         long time = Utils.getTimeNow();
    146                         mHandler.postDelayed(new Runnable() {
    147                             @Override
    148                             public void run() {
    149                                 startActivity(new Intent(getActivity(), ScreensaverActivity.class));
    150                             }
    151                         }, mLongPressTimeout);
    152                         mLastTouchX = event.getX();
    153                         mLastTouchY = event.getY();
    154                         return true;
    155                     case (MotionEvent.ACTION_MOVE):
    156                         float xDiff = Math.abs(event.getX() - mLastTouchX);
    157                         float yDiff = Math.abs(event.getY() - mLastTouchY);
    158                         if (xDiff >= mMaxMovementAllowed || yDiff >= mMaxMovementAllowed) {
    159                             mHandler.removeCallbacksAndMessages(null);
    160                         }
    161                         break;
    162                     default:
    163                         mHandler.removeCallbacksAndMessages(null);
    164                 }
    165                 return false;
    166             }
    167         };
    168 
    169         // On tablet landscape, the clock frame will be a distinct view. Otherwise, it'll be added
    170         // on as a header to the main listview.
    171         mClockFrame = v.findViewById(R.id.main_clock_left_pane);
    172         mHairline = v.findViewById(R.id.hairline);
    173         if (mClockFrame == null) {
    174             mClockFrame = inflater.inflate(R.layout.main_clock_frame, mList, false);
    175             mHairline = mClockFrame.findViewById(R.id.hairline);
    176             mHairline.setVisibility(View.VISIBLE);
    177             mList.addHeaderView(mClockFrame, null, false);
    178         } else {
    179             mHairline.setVisibility(View.GONE);
    180             // The main clock frame needs its own touch listener for night mode now.
    181             v.setOnTouchListener(longPressNightMode);
    182         }
    183         mList.setOnTouchListener(longPressNightMode);
    184 
    185         // If the current layout has a fake overflow menu button, let the parent
    186         // activity set up its click and touch listeners.
    187         View menuButton = v.findViewById(R.id.menu_button);
    188         if (menuButton != null) {
    189             setupFakeOverflowMenuButton(menuButton);
    190         }
    191 
    192         mDigitalClock = mClockFrame.findViewById(R.id.digital_clock);
    193         mAnalogClock = mClockFrame.findViewById(R.id.analog_clock);
    194         Utils.setTimeFormat((TextClock) (mDigitalClock.findViewById(R.id.digital_clock)),
    195                 (int) getResources().getDimension(R.dimen.main_ampm_font_size));
    196         View footerView = inflater.inflate(R.layout.blank_footer_view, mList, false);
    197         mList.addFooterView(footerView, null, false);
    198         mAdapter = new WorldClockAdapter(getActivity());
    199         if (mAdapter.getCount() == 0) {
    200             mHairline.setVisibility(View.GONE);
    201         }
    202         mList.setAdapter(mAdapter);
    203 
    204         mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
    205         mDefaultClockStyle = getActivity().getResources().getString(R.string.default_clock_style);
    206         return v;
    207     }
    208 
    209     @Override
    210     public void onResume() {
    211         super.onResume();
    212 
    213         final DeskClock activity = (DeskClock) getActivity();
    214         if (activity.getSelectedTab() == DeskClock.CLOCK_TAB_INDEX) {
    215             setFabAppearance();
    216             setLeftRightButtonAppearance();
    217         }
    218 
    219         mPrefs.registerOnSharedPreferenceChangeListener(this);
    220         mDateFormat = getString(R.string.abbrev_wday_month_day_no_year);
    221         mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year);
    222 
    223         Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater);
    224         // Besides monitoring when quarter-hour changes, monitor other actions that
    225         // effect clock time
    226         IntentFilter filter = new IntentFilter();
    227         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
    228         filter.addAction(Intent.ACTION_TIME_CHANGED);
    229         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
    230         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
    231         activity.registerReceiver(mIntentReceiver, filter);
    232 
    233         // Resume can invoked after changing the cities list or a change in locale
    234         if (mAdapter != null) {
    235             mAdapter.loadCitiesDb(activity);
    236             mAdapter.reloadData(activity);
    237         }
    238         // Resume can invoked after changing the clock style.
    239         View clockView = Utils.setClockStyle(activity, mDigitalClock, mAnalogClock,
    240                 SettingsActivity.KEY_CLOCK_STYLE);
    241         mClockStyle = (clockView == mDigitalClock ?
    242                 Utils.CLOCK_TYPE_DIGITAL : Utils.CLOCK_TYPE_ANALOG);
    243 
    244         // Center the main clock frame if cities are empty.
    245         if (getView().findViewById(R.id.main_clock_left_pane) != null && mAdapter.getCount() == 0) {
    246             mList.setVisibility(View.GONE);
    247         } else {
    248             mList.setVisibility(View.VISIBLE);
    249         }
    250         mAdapter.notifyDataSetChanged();
    251 
    252         Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mClockFrame);
    253         Utils.refreshAlarm(activity, mClockFrame);
    254     }
    255 
    256     @Override
    257     public void onPause() {
    258         super.onPause();
    259         mPrefs.unregisterOnSharedPreferenceChangeListener(this);
    260         Utils.cancelQuarterHourUpdater(mHandler, mQuarterHourUpdater);
    261         Activity activity = getActivity();
    262         activity.unregisterReceiver(mIntentReceiver);
    263     }
    264 
    265     @Override
    266     public void onSaveInstanceState(Bundle outState) {
    267         outState.putBoolean(BUTTONS_HIDDEN_KEY, mButtonsHidden);
    268         super.onSaveInstanceState(outState);
    269     }
    270 
    271     @Override
    272     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    273         if (key == SettingsActivity.KEY_CLOCK_STYLE) {
    274             mClockStyle = prefs.getString(SettingsActivity.KEY_CLOCK_STYLE, mDefaultClockStyle);
    275             mAdapter.notifyDataSetChanged();
    276         }
    277     }
    278 
    279     @Override
    280     public void onFabClick(View view) {
    281         final Activity activity = getActivity();
    282         startActivity(new Intent(activity, CitiesActivity.class));
    283     }
    284 
    285     @Override
    286     public void setFabAppearance() {
    287         final DeskClock activity = (DeskClock) getActivity();
    288         if (mFab == null || activity.getSelectedTab() != DeskClock.CLOCK_TAB_INDEX) {
    289             return;
    290         }
    291         mFab.setVisibility(View.VISIBLE);
    292         mFab.setImageResource(R.drawable.ic_globe);
    293         mFab.setContentDescription(getString(R.string.button_cities));
    294     }
    295 
    296     @Override
    297     public void setLeftRightButtonAppearance() {
    298         final DeskClock activity = (DeskClock) getActivity();
    299         if (mLeftButton == null || mRightButton == null ||
    300                 activity.getSelectedTab() != DeskClock.CLOCK_TAB_INDEX) {
    301             return;
    302         }
    303         mLeftButton.setVisibility(View.INVISIBLE);
    304         mRightButton.setVisibility(View.INVISIBLE);
    305     }
    306 }
    307