/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.embeddedlog.LightUpDroid; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.database.ContentObserver; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.provider.Settings; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.ListView; import com.embeddedlog.LightUpDroid.alarms.AlarmNotifications; import com.embeddedlog.LightUpDroid.widget.TextClock; import com.embeddedlog.LightUpDroid.worldclock.WorldClockAdapter; /** * Fragment that shows the clock (analog or digital), the next alarm info and the world clock. */ public class ClockFragment extends DeskClockFragment implements OnSharedPreferenceChangeListener { private static final String BUTTONS_HIDDEN_KEY = "buttons_hidden"; private final static String TAG = "ClockFragment"; private boolean mButtonsHidden = false; private View mDigitalClock, mAnalogClock, mClockFrame; private WorldClockAdapter mAdapter; private ListView mList; private SharedPreferences mPrefs; private String mDateFormat; private String mDateFormatForAccessibility; private String mDefaultClockStyle; private String mClockStyle; private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); boolean changed = action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_TIMEZONE_CHANGED) || action.equals(Intent.ACTION_LOCALE_CHANGED); if (changed) { Utils.updateDate(mDateFormat, mDateFormatForAccessibility,mClockFrame); if (mAdapter != null) { // *CHANGED may modify the need for showing the Home City if (mAdapter.hasHomeCity() != mAdapter.needHomeCity()) { mAdapter.reloadData(context); } else { mAdapter.notifyDataSetChanged(); } // Locale change: update digital clock format and // reload the cities list with new localized names if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { if (mDigitalClock != null) { Utils.setTimeFormat( (TextClock)(mDigitalClock.findViewById(R.id.digital_clock)), (int)context.getResources(). getDimension(R.dimen.bottom_text_size)); } mAdapter.loadCitiesDb(context); mAdapter.notifyDataSetChanged(); } } Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater); } if (changed || action.equals(AlarmNotifications.SYSTEM_ALARM_CHANGE_ACTION)) { Utils.refreshAlarm(getActivity(), mClockFrame); } } }; private final Handler mHandler = new Handler(); private final ContentObserver mAlarmObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { Utils.refreshAlarm(ClockFragment.this.getActivity(), mClockFrame); } }; // Thread that runs on every quarter-hour and refreshes the date. private final Runnable mQuarterHourUpdater = new Runnable() { @Override public void run() { // Update the main and world clock dates Utils.updateDate(mDateFormat, mDateFormatForAccessibility, mClockFrame); if (mAdapter != null) { mAdapter.notifyDataSetChanged(); } Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater); } }; public ClockFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) { // Inflate the layout for this fragment View v = inflater.inflate(R.layout.clock_fragment, container, false); if (icicle != null) { mButtonsHidden = icicle.getBoolean(BUTTONS_HIDDEN_KEY, false); } mList = (ListView)v.findViewById(R.id.cities); mList.setDivider(null); OnTouchListener longPressNightMode = new OnTouchListener() { private float mMaxMovementAllowed = -1; private int mLongPressTimeout = -1; private float mLastTouchX, mLastTouchY; @Override public boolean onTouch(View v, MotionEvent event) { if (mMaxMovementAllowed == -1) { mMaxMovementAllowed = ViewConfiguration.get(getActivity()).getScaledTouchSlop(); mLongPressTimeout = ViewConfiguration.getLongPressTimeout(); } switch (event.getAction()) { case (MotionEvent.ACTION_DOWN): long time = Utils.getTimeNow(); mHandler.postDelayed(new Runnable() { @Override public void run() { startActivity(new Intent(getActivity(), ScreensaverActivity.class)); } }, mLongPressTimeout); mLastTouchX = event.getX(); mLastTouchY = event.getY(); return true; case (MotionEvent.ACTION_MOVE): float xDiff = Math.abs(event.getX() - mLastTouchX); float yDiff = Math.abs(event.getY() - mLastTouchY); if (xDiff >= mMaxMovementAllowed || yDiff >= mMaxMovementAllowed) { mHandler.removeCallbacksAndMessages(null); } break; default: mHandler.removeCallbacksAndMessages(null); } return false; } }; // On tablet landscape, the clock frame will be a distinct view. Otherwise, it'll be added // on as a header to the main listview. mClockFrame = v.findViewById(R.id.main_clock_left_pane); if (mClockFrame == null) { mClockFrame = inflater.inflate(R.layout.main_clock_frame, mList, false); mList.addHeaderView(mClockFrame, null, false); } else { // The main clock frame needs its own touch listener for night mode now. v.setOnTouchListener(longPressNightMode); } mList.setOnTouchListener(longPressNightMode); // If the current layout has a fake overflow menu button, let the parent // activity set up its click and touch listeners. View menuButton = v.findViewById(R.id.menu_button); if (menuButton != null) { setupFakeOverflowMenuButton(menuButton); } mDigitalClock = mClockFrame.findViewById(R.id.digital_clock); mAnalogClock = mClockFrame.findViewById(R.id.analog_clock); Utils.setTimeFormat((TextClock)(mDigitalClock.findViewById(R.id.digital_clock)), (int)getResources().getDimension(R.dimen.bottom_text_size)); View footerView = inflater.inflate(R.layout.blank_footer_view, mList, false); footerView.setBackgroundResource(R.color.primary); mList.addFooterView(footerView); mAdapter = new WorldClockAdapter(getActivity()); mList.setAdapter(mAdapter); mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); mDefaultClockStyle = getActivity().getResources().getString(R.string.default_clock_style); return v; } @Override public void onResume () { super.onResume(); mPrefs.registerOnSharedPreferenceChangeListener(this); mDateFormat = getString(R.string.abbrev_wday_month_day_no_year); mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year); Activity activity = getActivity(); Utils.setQuarterHourUpdater(mHandler, mQuarterHourUpdater); // Besides monitoring when quarter-hour changes, monitor other actions that // effect clock time IntentFilter filter = new IntentFilter(); filter.addAction(AlarmNotifications.SYSTEM_ALARM_CHANGE_ACTION); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(Intent.ACTION_LOCALE_CHANGED); activity.registerReceiver(mIntentReceiver, filter); // Resume can invoked after changing the cities list or a change in locale if (mAdapter != null) { mAdapter.loadCitiesDb(activity); mAdapter.reloadData(activity); } // Resume can invoked after changing the clock style. View clockView = Utils.setClockStyle(activity, mDigitalClock, mAnalogClock, SettingsActivity.KEY_CLOCK_STYLE); mClockStyle = (clockView == mDigitalClock ? Utils.CLOCK_TYPE_DIGITAL : Utils.CLOCK_TYPE_ANALOG); // Center the main clock frame if cities are empty. if (getView().findViewById(R.id.main_clock_left_pane) != null && mAdapter.getCount() == 0) { mList.setVisibility(View.GONE); } else { mList.setVisibility(View.VISIBLE); } mAdapter.notifyDataSetChanged(); Utils.updateDate(mDateFormat, mDateFormatForAccessibility,mClockFrame); Utils.refreshAlarm(activity, mClockFrame); activity.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, mAlarmObserver); } @Override public void onPause() { super.onPause(); mPrefs.unregisterOnSharedPreferenceChangeListener(this); Utils.cancelQuarterHourUpdater(mHandler, mQuarterHourUpdater); Activity activity = getActivity(); activity.unregisterReceiver(mIntentReceiver); activity.getContentResolver().unregisterContentObserver(mAlarmObserver); } @Override public void onSaveInstanceState (Bundle outState) { outState.putBoolean(BUTTONS_HIDDEN_KEY, mButtonsHidden); super.onSaveInstanceState(outState); } @Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { if (key == SettingsActivity.KEY_CLOCK_STYLE) { mClockStyle = prefs.getString(SettingsActivity.KEY_CLOCK_STYLE, mDefaultClockStyle); mAdapter.notifyDataSetChanged(); } } }