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