diff options
Diffstat (limited to 'src/com/cyanogenmod/setupwizard/setup/DateTimePage.java')
-rw-r--r-- | src/com/cyanogenmod/setupwizard/setup/DateTimePage.java | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java b/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java new file mode 100644 index 0000000..40eda95 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import org.xmlpull.v1.XmlPullParserException; + +import android.app.Activity; +import android.app.AlarmManager; +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.TimePickerDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.os.Handler; +import android.text.format.DateFormat; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.DatePicker; +import android.widget.SimpleAdapter; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.TimePicker; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +public class DateTimePage extends SetupPage { + + public static final String TAG = "DateTimePage"; + + private static final String KEY_ID = "id"; // value: String + private static final String KEY_DISPLAYNAME = "name"; // value: String + private static final String KEY_GMT = "gmt"; // value: String + private static final String KEY_OFFSET = "offset"; // value: int (Integer) + private static final String XMLTAG_TIMEZONE = "timezone"; + + private static final int HOURS_1 = 60 * 60000; + + + public DateTimePage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + DateTimeFragment fragment = new DateTimeFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_datetime; + } + + public static class DateTimeFragment extends SetupPageFragment + implements TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener { + + private TimeZone mCurrentTimeZone; + private View mDateView; + private View mTimeView; + private TextView mDateTextView; + private TextView mTimeTextView; + + + private final Handler mHandler = new Handler(); + + @Override + public void onResume() { + super.onResume(); + // Register for time ticks and other reasons for time change + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + getActivity().registerReceiver(mIntentReceiver, filter, null, null); + + updateTimeAndDateDisplay(getActivity()); + } + + @Override + public void onPause() { + super.onPause(); + getActivity().unregisterReceiver(mIntentReceiver); + } + + @Override + protected void initializePage() { + final Spinner spinner = (Spinner) mRootView.findViewById(R.id.timezone_list); + final SimpleAdapter adapter = constructTimezoneAdapter(getActivity(), false); + mCurrentTimeZone = TimeZone.getDefault(); + mDateView = mRootView.findViewById(R.id.date_item); + mDateView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showDatePicker(); + } + }); + mTimeView = mRootView.findViewById(R.id.time_item); + mTimeView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showTimePicker(); + } + }); + mDateTextView = (TextView)mRootView.findViewById(R.id.date_text); + mTimeTextView = (TextView)mRootView.findViewById(R.id.time_text); + // Pre-select current/default timezone + mHandler.post(new Runnable() { + @Override + public void run() { + int tzIndex = getTimeZoneIndex(adapter, mCurrentTimeZone); + spinner.setAdapter(adapter); + if (tzIndex != -1) { + spinner.setSelection(tzIndex); + } + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { + final Map<?, ?> map = (Map<?, ?>) adapterView.getItemAtPosition(position); + final String tzId = (String) map.get(KEY_ID); + if (mCurrentTimeZone != null && !mCurrentTimeZone.getID().equals(tzId)) { + // Update the system timezone value + final Activity activity = getActivity(); + final AlarmManager alarm = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE); + alarm.setTimeZone(tzId); + mCurrentTimeZone = TimeZone.getTimeZone(tzId); + } + + } + + @Override + public void onNothingSelected(AdapterView<?> adapterView) { + } + }); + } + }); + } + + private void showDatePicker() { + DatePickerFragment datePickerFragment = DatePickerFragment.newInstance(); + datePickerFragment.setOnDateSetListener(this); + datePickerFragment.show(getFragmentManager(), DatePickerFragment.TAG); + } + + private void showTimePicker() { + TimePickerFragment timePickerFragment = TimePickerFragment.newInstance(); + timePickerFragment.setOnTimeSetListener(this); + timePickerFragment.show(getFragmentManager(), TimePickerFragment.TAG); + } + + public void updateTimeAndDateDisplay(Context context) { + java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(context); + final Calendar now = Calendar.getInstance(); + mTimeTextView.setText(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); + mDateTextView.setText(shortDateFormat.format(now.getTime())); + } + + @Override + protected int getLayoutResource() { + return R.layout.setup_datetime_page; + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int day) { + final Activity activity = getActivity(); + if (activity != null) { + setDate(activity, year, month, day); + updateTimeAndDateDisplay(activity); + } + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + final Activity activity = getActivity(); + if (activity != null) { + setTime(activity, hourOfDay, minute); + updateTimeAndDateDisplay(activity); + } + } + + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final Activity activity = getActivity(); + if (activity != null) { + updateTimeAndDateDisplay(activity); + } + } + }; + + } + + private static SimpleAdapter constructTimezoneAdapter(Context context, + boolean sortedByName) { + final String[] from = new String[] {KEY_DISPLAYNAME, KEY_GMT}; + final int[] to = new int[] {android.R.id.text1, android.R.id.text2}; + + final String sortKey = (sortedByName ? KEY_DISPLAYNAME : KEY_OFFSET); + final TimeZoneComparator comparator = new TimeZoneComparator(sortKey); + final List<HashMap<String, Object>> sortedList = getZones(context); + Collections.sort(sortedList, comparator); + final SimpleAdapter adapter = new SimpleAdapter(context, + sortedList, + R.layout.date_time_setup_custom_list_item_2, + from, + to); + + return adapter; + } + + private static List<HashMap<String, Object>> getZones(Context context) { + final List<HashMap<String, Object>> myData = new ArrayList<HashMap<String, Object>>(); + final long date = Calendar.getInstance().getTimeInMillis(); + try { + XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones); + while (xrp.next() != XmlResourceParser.START_TAG) + continue; + xrp.next(); + while (xrp.getEventType() != XmlResourceParser.END_TAG) { + while (xrp.getEventType() != XmlResourceParser.START_TAG) { + if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) { + return myData; + } + xrp.next(); + } + if (xrp.getName().equals(XMLTAG_TIMEZONE)) { + String id = xrp.getAttributeValue(0); + String displayName = xrp.nextText(); + addItem(myData, id, displayName, date); + } + while (xrp.getEventType() != XmlResourceParser.END_TAG) { + xrp.next(); + } + xrp.next(); + } + xrp.close(); + } catch (XmlPullParserException xppe) { + Log.e(TAG, "Ill-formatted timezones.xml file"); + } catch (java.io.IOException ioe) { + Log.e(TAG, "Unable to read timezones.xml file"); + } + + return myData; + } + + private static void addItem( + List<HashMap<String, Object>> myData, String id, String displayName, long date) { + final HashMap<String, Object> map = new HashMap<String, Object>(); + map.put(KEY_ID, id); + map.put(KEY_DISPLAYNAME, displayName); + final TimeZone tz = TimeZone.getTimeZone(id); + final int offset = tz.getOffset(date); + final int p = Math.abs(offset); + final StringBuilder name = new StringBuilder(); + name.append("GMT"); + + if (offset < 0) { + name.append('-'); + } else { + name.append('+'); + } + + name.append(p / (HOURS_1)); + name.append(':'); + + int min = p / 60000; + min %= 60; + + if (min < 10) { + name.append('0'); + } + name.append(min); + + map.put(KEY_GMT, name.toString()); + map.put(KEY_OFFSET, offset); + + myData.add(map); + } + + private static int getTimeZoneIndex(SimpleAdapter adapter, TimeZone tz) { + final String defaultId = tz.getID(); + final int listSize = adapter.getCount(); + for (int i = 0; i < listSize; i++) { + // Using HashMap<String, Object> induces unnecessary warning. + final HashMap<?,?> map = (HashMap<?,?>)adapter.getItem(i); + final String id = (String)map.get(KEY_ID); + if (defaultId.equals(id)) { + // If current timezone is in this list, move focus to it + return i; + } + } + return -1; + } + + private static void setDate(Context context, int year, int month, int day) { + Calendar c = Calendar.getInstance(); + + c.set(Calendar.YEAR, year); + c.set(Calendar.MONTH, month); + c.set(Calendar.DAY_OF_MONTH, day); + long when = c.getTimeInMillis(); + + if (when / 1000 < Integer.MAX_VALUE) { + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); + } + } + + private static void setTime(Context context, int hourOfDay, int minute) { + Calendar c = Calendar.getInstance(); + + c.set(Calendar.HOUR_OF_DAY, hourOfDay); + c.set(Calendar.MINUTE, minute); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + long when = c.getTimeInMillis(); + + if (when / 1000 < Integer.MAX_VALUE) { + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); + } + } + + private static class TimeZoneComparator implements Comparator<HashMap<?, ?>> { + private String mSortingKey; + + public TimeZoneComparator(String sortingKey) { + mSortingKey = sortingKey; + } + + public void setSortingKey(String sortingKey) { + mSortingKey = sortingKey; + } + + public int compare(HashMap<?, ?> map1, HashMap<?, ?> map2) { + Object value1 = map1.get(mSortingKey); + Object value2 = map2.get(mSortingKey); + + /* + * This should never happen, but just in-case, put non-comparable + * items at the end. + */ + if (!isComparable(value1)) { + return isComparable(value2) ? 1 : 0; + } else if (!isComparable(value2)) { + return -1; + } + + return ((Comparable) value1).compareTo(value2); + } + + private boolean isComparable(Object value) { + return (value != null) && (value instanceof Comparable); + } + } + + private static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener { + + private static String TAG = TimePickerFragment.class.getSimpleName(); + + private TimePickerDialog.OnTimeSetListener mOnTimeSetListener; + + public static TimePickerFragment newInstance() { + TimePickerFragment frag = new TimePickerFragment(); + return frag; + } + + private void setOnTimeSetListener(TimePickerDialog.OnTimeSetListener onTimeSetListener) { + mOnTimeSetListener = onTimeSetListener; + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + if (mOnTimeSetListener != null) { + mOnTimeSetListener.onTimeSet(view, hourOfDay, minute); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Calendar calendar = Calendar.getInstance(); + return new TimePickerDialog( + getActivity(), + this, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + DateFormat.is24HourFormat(getActivity())); + + } + } + + private static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener { + + private static String TAG = DatePickerFragment.class.getSimpleName(); + + private DatePickerDialog.OnDateSetListener mOnDateSetListener; + + public static DatePickerFragment newInstance() { + DatePickerFragment frag = new DatePickerFragment(); + return frag; + } + + private void setOnDateSetListener(DatePickerDialog.OnDateSetListener onDateSetListener) { + mOnDateSetListener = onDateSetListener; + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int day) { + if (mOnDateSetListener != null) { + mOnDateSetListener.onDateSet(view, year, month, day); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Calendar calendar = Calendar.getInstance(); + return new DatePickerDialog( + getActivity(), + this, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH)); + + } + } + +} |