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