• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ClockFragment()120     public ClockFragment() {
121     }
122 
123     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle)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
onResume()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
onPause()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
onSaveInstanceState(Bundle outState)262     public void onSaveInstanceState (Bundle outState) {
263         outState.putBoolean(BUTTONS_HIDDEN_KEY, mButtonsHidden);
264         super.onSaveInstanceState(outState);
265     }
266 
267     @Override
onSharedPreferenceChanged(SharedPreferences prefs, String key)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