/* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * 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 net.micode.notes.ui; import java.text.DateFormatSymbols; import java.util.Calendar; import net.micode.notes.R; import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; import android.content.Context; import android.text.format.DateFormat; import android.view.View; import android.widget.FrameLayout; import android.widget.NumberPicker; public class DateTimePicker extends FrameLayout { private static final boolean DEFAULT_ENABLE_STATE = true; private static final int HOURS_IN_HALF_DAY = 12; private static final int HOURS_IN_ALL_DAY = 24; private static final int DAYS_IN_ALL_WEEK = 7; private static final int DATE_SPINNER_MIN_VAL = 0; private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1; private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23; private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1; private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12; private static final int MINUT_SPINNER_MIN_VAL = 0; private static final int MINUT_SPINNER_MAX_VAL = 59; private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MAX_VAL = 1; private final NumberPicker mDateSpinner; private final NumberPicker mHourSpinner; private final NumberPicker mMinuteSpinner; private final NumberPicker mAmPmSpinner; private Calendar mDate; private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; private boolean mIsAm; private boolean mIs24HourView; private boolean mIsEnabled = DEFAULT_ENABLE_STATE; private boolean mInitialising; private OnDateTimeChangedListener mOnDateTimeChangedListener; // 移除同步账户相关设置 private void removeSyncAccount() { // 获取指定名称的 SharedPreferences 对象,使用私有模式,确保只有本应用可以访问这些设置 SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取 SharedPreferences 的编辑器,用于修改存储的设置 SharedPreferences.Editor editor = settings.edit(); // 检查 SharedPreferences 中是否包含同步账户名称的键 if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { // 如果包含,则从编辑器中移除该键值对 editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); } // 检查 SharedPreferences 中是否包含最后同步时间的键 if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { // 如果包含,则从编辑器中移除该键值对 editor.remove(PREFERENCE_LAST_SYNC_TIME); } // 提交编辑器中的修改,将更改保存到 SharedPreferences 中 editor.commit(); // 清理本地与 Google 任务(GTask)相关的信息,由于数据库操作可能会阻塞主线程,因此在新线程中执行 new Thread(new Runnable() { public void run() { // 创建一个 ContentValues 对象,用于存储要更新的数据 ContentValues values = new ContentValues(); // 将 GTask ID 字段设置为空字符串 values.put(NoteColumns.GTASK_ID, ""); // 将同步 ID 字段设置为 0 values.put(NoteColumns.SYNC_ID, 0); // 使用 ContentResolver 更新 Notes 内容提供者中的笔记数据,将 GTask ID 和同步 ID 字段清空 getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); } }).start(); } // 获取当前设置的同步账户名称 public static String getSyncAccountName(Context context) { // 获取指定名称的 SharedPreferences 对象,使用私有模式 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 从 SharedPreferences 中获取同步账户名称,如果不存在则返回空字符串 return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); } // 设置最后一次同步的时间 public static void setLastSyncTime(Context context, long time) { // 获取指定名称的 SharedPreferences 对象,使用私有模式 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 获取 SharedPreferences 的编辑器,用于修改存储的设置 SharedPreferences.Editor editor = settings.edit(); // 将最后同步时间存储到编辑器中 editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); // 提交编辑器中的修改,将更改保存到 SharedPreferences 中 editor.commit(); } // 获取最后一次同步的时间 public static long getLastSyncTime(Context context) { // 获取指定名称的 SharedPreferences 对象,使用私有模式 SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); // 从 SharedPreferences 中获取最后同步时间,如果不存在则返回 0 return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); } // 自定义广播接收器,用于接收 GTask 同步服务的广播 private class GTaskReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 刷新界面,更新账户设置和同步按钮状态等信息 refreshUI(); // 检查广播意图中是否包含正在同步的标志,并且标志为 true if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { // 查找用于显示同步状态的 TextView 控件 TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); // 设置同步状态文本为广播意图中携带的进度消息 syncStatus.setText(intent .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); } } } // 处理选项菜单的点击事件 public boolean onOptionsItemSelected(MenuItem item) { // 根据点击的菜单项 ID 进行不同的处理 switch (item.getItemId()) { // 如果点击的是应用图标(即返回按钮) case android.R.id.home: // 创建一个意图,用于启动 NotesListActivity Intent intent = new Intent(this, NotesListActivity.class); // 添加标志,确保启动的 NotesListActivity 位于任务栈的顶部,并清除之前的所有活动 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 启动 NotesListActivity startActivity(intent); // 返回 true 表示事件已处理 return true; // 如果点击的是其他菜单项 default: // 返回 false 表示事件未处理 return false; } } // 获取当前月份 public int getCurrentMonth() { // 通过Calendar对象获取当前月份 return mDate.get(Calendar.MONTH); } /** * 设置当前年份中的月份 * * @param month 年份中的月份 */ public void setCurrentMonth(int month) { // 如果不是初始化阶段且设置的月份与当前月份相同,则直接返回 if (!mInitialising && month == getCurrentMonth()) { return; } // 设置Calendar对象的月份 mDate.set(Calendar.MONTH, month); // 更新日期控件显示 updateDateControl(); // 触发日期时间改变的回调 onDateTimeChanged(); } /** * 获取当前月份中的日期 * * @return 月份中的日期 */ public int getCurrentDay() { // 通过Calendar对象获取当前月份中的日期 return mDate.get(Calendar.DAY_OF_MONTH); } /** * 设置当前月份中的日期 * * @param dayOfMonth 月份中的日期 */ public void setCurrentDay(int dayOfMonth) { // 如果不是初始化阶段且设置的日期与当前日期相同,则直接返回 if (!mInitialising && dayOfMonth == getCurrentDay()) { return; } // 设置Calendar对象的日期 mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); // 更新日期控件显示 updateDateControl(); // 触发日期时间改变的回调 onDateTimeChanged(); } /** * 获取24小时制的当前小时,范围在(0~23) * @return 24小时制的当前小时 */ public int getCurrentHourOfDay() { // 通过Calendar对象获取24小时制的当前小时 return mDate.get(Calendar.HOUR_OF_DAY); } // 获取当前小时,根据是否为24小时制进行不同处理 private int getCurrentHour() { if (mIs24HourView){ // 如果是24小时制,直接返回24小时制的当前小时 return getCurrentHourOfDay(); } else { // 如果是12小时制 int hour = getCurrentHourOfDay(); if (hour > HOURS_IN_HALF_DAY) { // 如果小时数大于12,减去12 return hour - HOURS_IN_HALF_DAY; } else { // 如果小时数为0,则显示为12,否则直接显示 return hour == 0 ? HOURS_IN_HALF_DAY : hour; } } } /** * 设置24小时制的当前小时,范围在(0~23) * * @param hourOfDay 24小时制的当前小时 */ public void setCurrentHour(int hourOfDay) { // 如果不是初始化阶段且设置的小时与当前小时相同,则直接返回 if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { return; } // 设置Calendar对象的小时 mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); if (!mIs24HourView) { // 如果是12小时制 if (hourOfDay >= HOURS_IN_HALF_DAY) { // 如果小时数大于等于12,设置为下午 mIsAm = false; if (hourOfDay > HOURS_IN_HALF_DAY) { // 如果小时数大于12,减去12 hourOfDay -= HOURS_IN_HALF_DAY; } } else { // 如果小时数小于12,设置为上午 mIsAm = true; if (hourOfDay == 0) { // 如果小时数为0,则显示为12 hourOfDay = HOURS_IN_HALF_DAY; } } // 更新上午/下午控件显示 updateAmPmControl(); } // 设置小时选择器的值 mHourSpinner.setValue(hourOfDay); // 触发日期时间改变的回调 onDateTimeChanged(); } /** * 获取当前分钟 * * @return 当前分钟 */ public int getCurrentMinute() { // 通过Calendar对象获取当前分钟 return mDate.get(Calendar.MINUTE); } /** * 设置当前分钟 */ public void setCurrentMinute(int minute) { // 如果不是初始化阶段且设置的分钟与当前分钟相同,则直接返回 if (!mInitialising && minute == getCurrentMinute()) { return; } // 设置分钟选择器的值 mMinuteSpinner.setValue(minute); // 设置Calendar对象的分钟 mDate.set(Calendar.MINUTE, minute); // 触发日期时间改变的回调 onDateTimeChanged(); } /** * @return 如果是24小时制视图返回true,否则返回false。 */ public boolean is24HourView () { // 返回是否为24小时制视图的标志 return mIs24HourView; } /** * 设置是否为24小时制或上午/下午模式。 * * @param is24HourView 为true表示24小时制模式,为false表示上午/下午模式。 */ public void set24HourView(boolean is24HourView) { // 如果当前模式与要设置的模式相同,则直接返回 if (mIs24HourView == is24HourView) { return; } // 更新是否为24小时制视图的标志 mIs24HourView = is24HourView; // 根据是否为24小时制视图,显示或隐藏上午/下午选择器 mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); // 获取当前24小时制的小时 int hour = getCurrentHourOfDay(); // 更新小时选择器的范围 updateHourControl(); // 设置当前小时 setCurrentHour(hour); // 更新上午/下午控件显示 updateAmPmControl(); } // 更新日期控件的显示 private void updateDateControl() { // 创建一个新的Calendar对象 Calendar cal = Calendar.getInstance(); // 设置Calendar对象的时间为当前时间 cal.setTimeInMillis(mDate.getTimeInMillis()); // 将日期向前移动DAYS_IN_ALL_WEEK / 2 + 1天 cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1); // 清空日期选择器的显示值 mDateSpinner.setDisplayedValues(null); for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) { // 日期向后移动1天 cal.add(Calendar.DAY_OF_YEAR, 1); // 将日期格式化为"MM.dd EEEE"的字符串 mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal); } // 设置日期选择器的显示值 mDateSpinner.setDisplayedValues(mDateDisplayValues); // 设置日期选择器的当前值为中间值 mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); // 使日期选择器重绘 mDateSpinner.invalidate(); } // 更新上午/下午控件的显示 private void updateAmPmControl() { if (mIs24HourView) { // 如果是24小时制视图,隐藏上午/下午选择器 mAmPmSpinner.setVisibility(View.GONE); } else { // 如果是12小时制视图,根据是否为上午设置选择器的值 int index = mIsAm ? Calendar.AM : Calendar.PM; mAmPmSpinner.setValue(index); // 显示上午/下午选择器 mAmPmSpinner.setVisibility(View.VISIBLE); } } // 更新小时控件的显示 private void updateHourControl() { if (mIs24HourView) { // 如果是24小时制视图,设置小时选择器的最小值和最大值 mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW); } else { // 如果是12小时制视图,设置小时选择器的最小值和最大值 mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); } } /** * 设置当点击“设置”按钮时的回调函数 * @param callback 回调函数,如果为null则不做任何操作 */ public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { // 设置日期时间改变的回调函数 mOnDateTimeChangedListener = callback; } // 触发日期时间改变的回调 private void onDateTimeChanged() { if (mOnDateTimeChangedListener != null) { // 调用回调函数,传递当前的年、月、日、小时和分钟 mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); } } }